试图从 mysql 中检索文本和 blob 到 jtable
trying to retrieve both text and blob from mysql to jtable
所以我试图以一种很好的方式从 jtable 中的数据库中检索文本和 blob(图像)。出于某种原因,每当我尝试检索 blob 时,我都会得到:
java.io.ByteArrayInputStream@1cb63183
在每隔一列中,尽管我已经指定 blob 在 8 号!
这里是截图:
http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at_1_26_55_PM.png
这是我的代码
sql = "SELECT * FROM Products";
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
// getting the columns number
int columnsNumber = rsmd.getColumnCount();
// setting a vector with columns number
Vector columns = new Vector(columnsNumber);
// adding column names
for(int i=1; i<=columnsNumber; i++)
columns.add(rsmd.getColumnName(i));
// setting a vector with row data
Vector rowdata = new Vector();
Vector row;
JTable table = new JTable(rowdata, columns);
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i<=columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
row.add(rs.getBinaryStream(8));
}
// adding the rows in the database
rowdata.add(row);
}
有人可以向我解释为什么这种方法不起作用吗?
顺便说一句,如果我删除了这一行:
row.add(rs.getBinaryStream(8));
获取 java.io.ByteArrayInputSteam 的问题将消失,但是,我只会获取图像的文本表示。
它实际上不是重复的,因为我试图根据我有多少行(文本和图像)将其添加到特定列中。所以它是动态完成的,与 "possible duplicate"
不同,sql 同时具有图像和文本
提前致谢!
所以,您似乎遇到了一系列复杂的问题。让我们从这里开始,从数据库加载数据...
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i<=columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
row.add(rs.getBinaryStream(8));
}
// adding the rows in the database
rowdata.add(row);
}
因此,对于 ResultSet
中的每一行,您查看列,但是,对于每一列,您添加 String
值和最后一列的 blob,因此 blob 将添加 6 次(根据您的屏幕截图)。显然,这不是您想要的,也是您在其他所有列中获得 java.io.ByteArrayInputStream@1cb63183
的原因。
相反,您想遍历 1
-columnsNumbers - 1
列,因为我们不想要最后一列,并将图像添加到最后一列,可能类似于...
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i < columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
}
row.add(rs.getBinaryStream(8));
// adding the rows in the database
rowdata.add(row);
}
下一个问题...
它仍然在最后一列打印 java.io.ByteArrayInputStream@1cb63183
!?
这只是因为您添加到 row
Vector
的所有内容都是表示数据库中二进制数据的二进制流,JTable
无法呈现它。您应该首先查看 Concepts: Editors and Renderers and Using Custom Renderers,了解有关如何自定义这些组件的渲染的更多详细信息
首先,我们需要将二进制数据转换为我们可以使用的图像格式
row.add(ImageIO.read(rs.getBinaryStream(8)));
并使用类似于 Rendering BufferedImage in JTable cell
中概述的内容
或
row.add(new ImageIcon(ImageIO.read(rs.getBinaryStream(8))));
应该允许 "default" TableCellRenderer
渲染它
可运行示例...
警告:这个例子有点长,因为我必须构建数据库并填充它。为简单起见,它使用独立的 H2 Database engine,但应该可以转换为大多数其他数据库。该示例还使用了 blob
的列类型,这是故意的,因为它提高了数据库引擎的性能。
在使用 DefaultTableModel
时让图像显示在 JTable
中的问题是,DefaultTableModel
returns Object.class
来自 TableModel#getColumnClass
方法
甚至 DefaultTableModel
文档也记录了这一点...
Warning: DefaultTableModel
returns a
column class of Object
. When
DefaultTableModel
is used with a
TableRowSorter
this will result in extensive use of
toString
, which for non-String
data types
is expensive. If you use DefaultTableModel
with a
TableRowSorter
you are strongly encouraged to override
getColumnClass
to return the appropriate type.
我通过自定义 DefaultTableModel
我从 TestPane#makeTableModel
...
返回来克服了这个问题
DefaultTableModel model = new DefaultTableModel(new String[]{"Name", "Image"}, 0) {
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
}
};
这允许 JTable
使用正确的 TableCellRenderer
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] args) {
try {
Class.forName("org.h2.Driver");
makeDatabase();
populateDatabase();
new Main();
} catch (ClassNotFoundException | SQLException | IOException exp) {
exp.printStackTrace();
}
}
protected static Connection makeConnection() throws SQLException {
String path = "jdbc:h2:./TestDatabase";
return DriverManager.getConnection(path, "sa", "");
}
protected static void makeDatabase() throws SQLException {
String cmd = "create table if not exists fruits ("
+ "key BIGINT IDENTITY, "
+ "name varchar(128), "
+ "image longblob)";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
System.out.println("> Make fruits table");
stmt.executeUpdate();
}
}
}
protected static void populateDatabase() throws SQLException, IOException {
removeAlFruits();
insert("Apple", ImageIO.read(new File("Apple.png")));
insert("Banana", ImageIO.read(new File("Banana.png")));
insert("Cherries", ImageIO.read(new File("Cherries.png")));
insert("Grapes", ImageIO.read(new File("Grapes.png")));
insert("Orange", ImageIO.read(new File("Orange.png")));
insert("Pear", ImageIO.read(new File("Pear.png")));
insert("Pine Apple", ImageIO.read(new File("PineApple.png")));
insert("Strewberry", ImageIO.read(new File("Strewberry.png")));
insert("Water Melon", ImageIO.read(new File("WaterMelon.png")));
}
protected static void insert(String name, BufferedImage image) throws SQLException, IOException {
String cmd = "insert into fruits (name, image) values (?, ?)";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (InputStream is = convertImageToInputStream(image)) {
System.out.println("> Insert " + name);
stmt.setString(1, name);
stmt.setBinaryStream(2, is);
int rows = stmt.executeUpdate();
System.out.println("> " + rows + " rows updated");
}
}
}
}
protected static InputStream convertImageToInputStream(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = null;
ByteArrayInputStream bais = null;
try {
baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
baos.close();
bais = new ByteArrayInputStream(baos.toByteArray());
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) {
}
}
}
return bais;
}
protected static void removeAlFruits() throws SQLException {
String cmd = "delete from fruits";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
System.out.println("> Remove all fruits");
int rows = stmt.executeUpdate();
System.out.println("> " + rows + " rows updated");
}
}
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (SQLException | IOException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() throws SQLException, IOException {
setLayout(new BorderLayout());
DefaultTableModel model = makeTableModel();
JTable table = new JTable(model);
table.setRowHeight(100);
add(new JScrollPane(table));
}
protected DefaultTableModel makeTableModel() throws SQLException, IOException {
DefaultTableModel model = new DefaultTableModel(new String[]{"Name", "Image"}, 0) {
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
}
};
String cmd = "select name, image from fruits";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String name = rs.getString(1);
Blob blob = rs.getBlob(2);
ImageIcon icon = null;
try (InputStream is = blob.getBinaryStream()) {
BufferedImage img = ImageIO.read(is);
icon = new ImageIcon(img);
}
model.addRow(new Object[]{name, icon});
}
}
}
}
return model;
}
}
}
替代方法是使用自定义 TableCellRender
,如 Rendering BufferedImage in JTable cell
中所示
所以我试图以一种很好的方式从 jtable 中的数据库中检索文本和 blob(图像)。出于某种原因,每当我尝试检索 blob 时,我都会得到:
java.io.ByteArrayInputStream@1cb63183
在每隔一列中,尽管我已经指定 blob 在 8 号!
这里是截图:
http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at_1_26_55_PM.png
这是我的代码
sql = "SELECT * FROM Products";
ResultSet rs = stmt.executeQuery(sql);
ResultSetMetaData rsmd = rs.getMetaData();
// getting the columns number
int columnsNumber = rsmd.getColumnCount();
// setting a vector with columns number
Vector columns = new Vector(columnsNumber);
// adding column names
for(int i=1; i<=columnsNumber; i++)
columns.add(rsmd.getColumnName(i));
// setting a vector with row data
Vector rowdata = new Vector();
Vector row;
JTable table = new JTable(rowdata, columns);
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i<=columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
row.add(rs.getBinaryStream(8));
}
// adding the rows in the database
rowdata.add(row);
}
有人可以向我解释为什么这种方法不起作用吗?
顺便说一句,如果我删除了这一行:
row.add(rs.getBinaryStream(8));
获取 java.io.ByteArrayInputSteam 的问题将消失,但是,我只会获取图像的文本表示。
它实际上不是重复的,因为我试图根据我有多少行(文本和图像)将其添加到特定列中。所以它是动态完成的,与 "possible duplicate"
不同,sql 同时具有图像和文本提前致谢!
所以,您似乎遇到了一系列复杂的问题。让我们从这里开始,从数据库加载数据...
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i<=columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
row.add(rs.getBinaryStream(8));
}
// adding the rows in the database
rowdata.add(row);
}
因此,对于 ResultSet
中的每一行,您查看列,但是,对于每一列,您添加 String
值和最后一列的 blob,因此 blob 将添加 6 次(根据您的屏幕截图)。显然,这不是您想要的,也是您在其他所有列中获得 java.io.ByteArrayInputStream@1cb63183
的原因。
相反,您想遍历 1
-columnsNumbers - 1
列,因为我们不想要最后一列,并将图像添加到最后一列,可能类似于...
while(rs.next())
{
row = new Vector(columnsNumber);
for(int i=1; i < columnsNumber; i++)
{
// adding the rows in "row vector"
InputStream binaryStream = rs.getBinaryStream(i);
row.add(rs.getString(i));
}
row.add(rs.getBinaryStream(8));
// adding the rows in the database
rowdata.add(row);
}
下一个问题...
它仍然在最后一列打印 java.io.ByteArrayInputStream@1cb63183
!?
这只是因为您添加到 row
Vector
的所有内容都是表示数据库中二进制数据的二进制流,JTable
无法呈现它。您应该首先查看 Concepts: Editors and Renderers and Using Custom Renderers,了解有关如何自定义这些组件的渲染的更多详细信息
首先,我们需要将二进制数据转换为我们可以使用的图像格式
row.add(ImageIO.read(rs.getBinaryStream(8)));
并使用类似于 Rendering BufferedImage in JTable cell
中概述的内容或
row.add(new ImageIcon(ImageIO.read(rs.getBinaryStream(8))));
应该允许 "default" TableCellRenderer
渲染它
可运行示例...
警告:这个例子有点长,因为我必须构建数据库并填充它。为简单起见,它使用独立的 H2 Database engine,但应该可以转换为大多数其他数据库。该示例还使用了 blob
的列类型,这是故意的,因为它提高了数据库引擎的性能。
在使用 DefaultTableModel
时让图像显示在 JTable
中的问题是,DefaultTableModel
returns Object.class
来自 TableModel#getColumnClass
方法
甚至 DefaultTableModel
文档也记录了这一点...
Warning:
DefaultTableModel
returns a column class ofObject
. WhenDefaultTableModel
is used with aTableRowSorter
this will result in extensive use oftoString
, which for non-String
data types is expensive. If you useDefaultTableModel
with aTableRowSorter
you are strongly encouraged to overridegetColumnClass
to return the appropriate type.
我通过自定义 DefaultTableModel
我从 TestPane#makeTableModel
...
DefaultTableModel model = new DefaultTableModel(new String[]{"Name", "Image"}, 0) {
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
}
};
这允许 JTable
使用正确的 TableCellRenderer
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.table.DefaultTableModel;
public class Main {
public static void main(String[] args) {
try {
Class.forName("org.h2.Driver");
makeDatabase();
populateDatabase();
new Main();
} catch (ClassNotFoundException | SQLException | IOException exp) {
exp.printStackTrace();
}
}
protected static Connection makeConnection() throws SQLException {
String path = "jdbc:h2:./TestDatabase";
return DriverManager.getConnection(path, "sa", "");
}
protected static void makeDatabase() throws SQLException {
String cmd = "create table if not exists fruits ("
+ "key BIGINT IDENTITY, "
+ "name varchar(128), "
+ "image longblob)";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
System.out.println("> Make fruits table");
stmt.executeUpdate();
}
}
}
protected static void populateDatabase() throws SQLException, IOException {
removeAlFruits();
insert("Apple", ImageIO.read(new File("Apple.png")));
insert("Banana", ImageIO.read(new File("Banana.png")));
insert("Cherries", ImageIO.read(new File("Cherries.png")));
insert("Grapes", ImageIO.read(new File("Grapes.png")));
insert("Orange", ImageIO.read(new File("Orange.png")));
insert("Pear", ImageIO.read(new File("Pear.png")));
insert("Pine Apple", ImageIO.read(new File("PineApple.png")));
insert("Strewberry", ImageIO.read(new File("Strewberry.png")));
insert("Water Melon", ImageIO.read(new File("WaterMelon.png")));
}
protected static void insert(String name, BufferedImage image) throws SQLException, IOException {
String cmd = "insert into fruits (name, image) values (?, ?)";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (InputStream is = convertImageToInputStream(image)) {
System.out.println("> Insert " + name);
stmt.setString(1, name);
stmt.setBinaryStream(2, is);
int rows = stmt.executeUpdate();
System.out.println("> " + rows + " rows updated");
}
}
}
}
protected static InputStream convertImageToInputStream(BufferedImage image) throws IOException {
ByteArrayOutputStream baos = null;
ByteArrayInputStream bais = null;
try {
baos = new ByteArrayOutputStream();
ImageIO.write(image, "png", baos);
baos.close();
bais = new ByteArrayInputStream(baos.toByteArray());
} finally {
if (baos != null) {
try {
baos.close();
} catch (IOException ex) {
}
}
}
return bais;
}
protected static void removeAlFruits() throws SQLException {
String cmd = "delete from fruits";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
System.out.println("> Remove all fruits");
int rows = stmt.executeUpdate();
System.out.println("> " + rows + " rows updated");
}
}
}
public Main() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
} catch (SQLException | IOException ex) {
ex.printStackTrace();
}
}
});
}
public class TestPane extends JPanel {
public TestPane() throws SQLException, IOException {
setLayout(new BorderLayout());
DefaultTableModel model = makeTableModel();
JTable table = new JTable(model);
table.setRowHeight(100);
add(new JScrollPane(table));
}
protected DefaultTableModel makeTableModel() throws SQLException, IOException {
DefaultTableModel model = new DefaultTableModel(new String[]{"Name", "Image"}, 0) {
@Override
public Class<?> getColumnClass(int columnIndex) {
return columnIndex == 1 ? Icon.class : super.getColumnClass(columnIndex);
}
};
String cmd = "select name, image from fruits";
try (Connection con = makeConnection()) {
try (PreparedStatement stmt = con.prepareStatement(cmd)) {
try (ResultSet rs = stmt.executeQuery()) {
while (rs.next()) {
String name = rs.getString(1);
Blob blob = rs.getBlob(2);
ImageIcon icon = null;
try (InputStream is = blob.getBinaryStream()) {
BufferedImage img = ImageIO.read(is);
icon = new ImageIcon(img);
}
model.addRow(new Object[]{name, icon});
}
}
}
}
return model;
}
}
}
替代方法是使用自定义 TableCellRender
,如 Rendering BufferedImage in JTable cell