简体   繁体   English

试图从mysql到jtable同时检索文本和blob

[英]trying to retrieve both text and blob from mysql to jtable

So I'm trying to retrieve text and a blob(image) from a database inside a jtable in a nice way. 所以我试图以一种很好的方式从jtable内的数据库中检索文本和blob(image)。 For some reason, whenever I try to retrieve the blob I get this: 由于某种原因,每当我尝试检索Blob时,我都会得到以下信息:

java.io.ByteArrayInputStream@1cb63183

in every other column, although I've specified that the blob is on the 8th ! 在所有其他列中,尽管我已指定blob在8号上!

here is a screenshot: 这是屏幕截图:

http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at_1_26_55_PM.png http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at_1_26_55_PM.png

在此处输入图片说明

Here is my code 这是我的代码

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);
}

Could someone explain to me why is this approach not doing the job? 有人可以向我解释为什么这种方法不起作用吗?

by the way, if I removed this line: 顺便说一句,如果我删除了这一行:

 row.add(rs.getBinaryStream(8));

The problem of getting the java.io.ByteArrayInputSteam will disappear, however, I will only be getting the text representation of the image. 获取java.io.ByteArrayInputSteam的问题将消失,但是,我将仅获取图像的文本表示形式。

it's actually not a duplicate because I'm trying to add it in a specific column depending on how many rows I have, which are BOTH text and Image. 它实际上不是重复的,因为我正尝试将其添加到特定列中,具体取决于我拥有的行数,即文本和图像。 So it's dynamically done and the sql has both the image and the text at the same time unlike the "possible duplicate" 因此它是动态完成的,并且与“可能的重复项”不同,sql同时具有图像和文本

Thanks in advance! 提前致谢!

So, you seem to have a series of compounding problems. 因此,您似乎遇到了一系列复杂的问题。 Let's start here, where you load the data from the database... 让我们从这里开始,从数据库中加载数据...

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);
    }

So, for each row in the ResultSet you look through the columns, BUT, for each column, you add the String value AND the blob from the last column, so the blob will be added 6 times (based on your screen shot). 因此,对于ResultSet每一行,您要查看各列,但对于每一列,您要添加String值和最后一列中的blob,因此该blob将被添加6次(基于屏幕截图)。 This is, obviously, not what you want and also the reason why you're getting java.io.ByteArrayInputStream@1cb63183 in every other column. 显然,这不是您想要的,也是每隔一列获取java.io.ByteArrayInputStream@1cb63183的原因。

Instead, you want to loop through columns 1 - columnsNumbers - 1 , because we don't want the last column, and add the image to the last column, maybe something like... 相反,您要遍历第1columnsNumbers - 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);
}

Next problem... 下一个问题...

It still prints java.io.ByteArrayInputStream@1cb63183 in the last column!? 仍然在最后一列中打印java.io.ByteArrayInputStream@1cb63183 !?

This is simply because all you added to the row Vector was the binary stream representing the binary data in the database, JTable has no means by which to render this. 这仅仅是因为您添加到Vector所有row都是代表数据库中二进制数据的二进制流,因此JTable无法呈现该二进制数据。 You should start by having a look at Concepts: Editors and Renderers and Using Custom Renderers for more details about how you can customise the rendering of these components 您应该先看一下概念:编辑器和渲染器以及使用自定义渲染器,以获取有关如何自定义这些组件的渲染的更多详细信息。

First, we need to convert the binary data to an image format which we can use 首先,我们需要将二进制数据转换为可以使用的图像格式

row.add(ImageIO.read(rs.getBinaryStream(8)));

And use something similar to what is outlined in Rendering BufferedImage in JTable cell 并使用类似于在JTable单元渲染BufferedImage概述的内容

or 要么

row.add(new ImageIcon(ImageIO.read(rs.getBinaryStream(8))));

which should allow the "default" TableCellRenderer to render it 这应该允许“默认” TableCellRenderer呈现它

Runnable Example... 可运行的示例...

Warning: This example is a little long, because I had to build the database and populate it. 警告:这个例子有点长,因为我必须构建数据库并填充它。 It uses a standalong H2 Database engine for simplicity, but should be translatable to most other database. 为了简化起见,它使用了标准的H2数据库引擎 ,但应可翻译为大多数其他数据库。 The example also uses a column type of blob , this is deliberate, as it improves the performance of the database engine. 该示例还使用blob的列类型,这是有意的,因为它可以提高数据库引擎的性能。

The problem with getting images to display in a JTable when using a DefaultTableModel is, DefaultTableModel returns Object.class from the TableModel#getColumnClass method 使用DefaultTableModel时获取图像以显示在JTable的问题是, DefaultTableModelTableModel#getColumnClass方法返回Object.class

Even the DefaultTableModel documentation makes note of this... 甚至DefaultTableModel文档也记录了这一点...

Warning: DefaultTableModel returns a column class of Object . 警告: DefaultTableModel返回Object的列类。 When DefaultTableModel is used with a TableRowSorter this will result in extensive use of toString , which for non- String data types is expensive. 当将DefaultTableModelTableRowSorter一起使用时,这将导致toString广泛使用,这对于非String数据类型而言是昂贵的。 If you use DefaultTableModel with a TableRowSorter you are strongly encouraged to override getColumnClass to return the appropriate type. 如果将DefaultTableModelTableRowSorter一起使用,则强烈建议您重写getColumnClass以返回适当的类型。

I overcame this by customising the DefaultTableModel I returned from TestPane#makeTableModel ... 我通过自定义从TestPane#makeTableModel返回的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);
    }
};

This allowed the JTable to use the correct TableCellRenderer 这允许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;
        }

    }
}

The alternative is to use a custom TableCellRender as demonstrated in Rendering BufferedImage in JTable cell 替代方法是使用自定义TableCellRender在JTable单元中的BufferedImage渲染中所示。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM