пытаясь получить как текст, так и большой двоичный объект из mysql в jtable

Итак, я пытаюсь получить текст и blob (изображение) из базы данных внутри jtable хорошим способом. По какой-то причине всякий раз, когда я пытаюсь получить BLOB-объект, я получаю следующее:

java.io.ByteArrayInputStream@1cb63183

в каждом втором столбце, хотя я указал, что капля находится на 8-м!

вот скриншот:

http://s24.postimg.org/t71o3izlh/Screen_Shot_2016_01_28_at

java.io.ByteArrayInputStream@1cb63183
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 исчезнет, ​​однако я буду получать только текстовое представление изображения.

на самом деле это не дубликат, потому что я пытаюсь добавить его в определенный столбец в зависимости от того, сколько строк у меня есть, которые являются ОБА текстом и изображением. Так что это делается динамически, и sql одновременно имеет и изображение, и текст, в отличие от «возможного дубликата».

Заранее спасибо!


person rullzing    schedule 28.01.2016    source источник
comment
Массив байтов представляет собой двоичное представление изображения, затем вам нужно преобразовать его обратно в какое-то изображение.   -  person MadProgrammer    schedule 28.01.2016
comment
@MadProgrammer на самом деле это не дубликат, потому что я пытаюсь добавить его в определенный столбец в зависимости от того, сколько строк у меня есть. Так что это делается динамически, и sql одновременно имеет и изображение, и текст, в отличие от возможного дубликата.   -  person rullzing    schedule 28.01.2016
comment
Значит, вы понятия не имеете, какие данные на самом деле находятся в столбце, и не знаете, как их расшифровать? В качестве общего комментария к вашим требованиям это звучит просто безумно. Вам либо нужны два столбца, один для текста и один для изображения, либо вам нужен еще один столбец для указания типа данных. Как правило, столбец должен представлять тип данных, которые он содержит, например image и text, а не data, что исключает возможность узнать, какой тип данных он представляет на самом деле.   -  person MadProgrammer    schedule 28.01.2016
comment
@MadProgrammer хорошо, изображение должно быть только в 8-м столбце. Остальные будут с текстом. Однако SQL-запрос — это только тот, который у меня есть. По какой-то причине, хотя я указал 8-й столбец для изображения, я все еще не могу заставить его это сделать. Я даже пытался добавить другие данные, чтобы один был для изображения, а другой для текста, но это тоже не сработало.   -  person rullzing    schedule 28.01.2016
comment
Итак, это дубликат! У вас есть ByteArrayInputStream, который является двоичным представлением большого двоичного объекта (или изображения) из базы данных, вам нужно использовать ImageIO, чтобы прочитать ByteArrayInputStream и преобразовать его обратно в BufferedImage, который затем можно отобразить в вашем JTable!!!   -  person MadProgrammer    schedule 29.01.2016
comment
Возможный дубликат Преобразовать BufferedInputStream в изображение. Эти Blob blob = rs.getBlob(8); и BufferedImage img = ImageIO.read(blob.getBinaryStream()); — это то, что вам нужно, чтобы прочитать последний столбец и преобразовать его в изображение. Но, учитывая ByteArrayStream, вы также можете использовать его, но это немного сложнее   -  person MadProgrammer    schedule 29.01.2016
comment
Затем возникает проблема, как отобразить изображение в JTable, которое станет дубликатом Rendering BufferedImage в JTable. ячейка   -  person MadProgrammer    schedule 29.01.2016
comment
@MadProgrammer Я пытался использовать то, что вы предложили, и теперь я получаю еще одну ошибку в каждом втором столбце. На этот раз это ava.io.ByteArrayInputStream@1034d0b4, и когда я изменил row.add на BufferedImage, я получил это: BufferedImage@3b7f825e: type = 5 ColorModel: #pixelBits = 24 numComponents = 3 color space = java.awt.color.ICC_ColorSpace@232b985c transparency = 1 has alpha = false isAlphaPre = false ByteInterleavedRaster: width = 1000 height = 750 #numDataElements 3 dataOff[0] = 2"   -  person rullzing    schedule 29.01.2016
comment
Это не ошибка. TableCellRenderer использует метод объектов toString для его отображения. Вы использовали ImageIO.read для чтения двоичного потока из базы данных? Вы добавили полученное изображение в row Vector? Вы использовали пользовательский TableCellRenderer для отображения BufferedImage?   -  person MadProgrammer    schedule 29.01.2016
comment
@MadProgrammer, как это не ошибка, если он добавляет его в каждый второй столбец, а не добавляет только к 1? На самом деле я добавил полученное изображение к вектору-строке, поэтому он пропустил весь текст в нем.   -  person rullzing    schedule 29.01.2016
comment
На мой взгляд, ошибка сгенерировала бы какую-то Exception, то, что у вас есть, это ошибка   -  person MadProgrammer    schedule 29.01.2016


Ответы (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);
    }

Таким образом, для каждой строки в 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 не имеет средств для его отображения. Вы должны начать с изучения Концепции: редакторы и визуализаторы и Использование пользовательских средств визуализации для получения дополнительной информации. о том, как можно настроить отрисовку этих компонентов

Во-первых, нам нужно преобразовать двоичные данные в формат изображения, который мы можем использовать.

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

И используйте что-то похожее на то, что описано в Визуализация BufferedImage в ячейке JTable

or

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

который должен позволить "по умолчанию" TableCellRenderer отображать его

Запускаемый пример...

Предупреждение. Этот пример немного длинный, потому что мне нужно было создать базу данных и заполнить ее. Он использует автономный ядро базы данных H2 для простоты, но должен быть переведен в большинство других баз данных. . В примере также используется тип столбца blob, это сделано намеренно, так как это повышает производительность ядра базы данных.

Проблема с отображением изображений в JTable при использовании DefaultTableModel заключается в том, что DefaultTableModel возвращает Object.class из метода TableModel#getColumnClass.

Даже в документации DefaultTableModel отмечается этого...

Внимание! DefaultTableModel возвращает класс столбца Object. Когда DefaultTableModel используется с TableRowSorter, это приводит к широкому использованию toString, что для типов данных, отличных от String, является дорогостоящим. Если вы используете DefaultTableModel с TableRowSorter, вам настоятельно рекомендуется переопределить getColumnClass, чтобы вернуть соответствующий тип.

Я преодолел это, настроив 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, как показано в разделе Визуализация BufferedImage в ячейке JTable.

person MadProgrammer    schedule 28.01.2016
comment
На самом деле он даже не печатает java.io.ByteArrayInputStream@1cb63183 в последнем столбце. Это так же, как если бы вы читали строку изображения так же, как если бы вы открывали изображение с помощью блокнота - person rullzing; 29.01.2016
comment
Что печатает в последнем столбце? Как изображения вставляются в базу данных? - person MadProgrammer; 29.01.2016
comment
оказывается, что метод ImageIcon действительно работает, и я смог просмотреть изображение с помощью showMessageDialog. Поэтому мне нужно найти способ поместить его в Jtable. Вот скриншот того, что он печатает: s21.postimg.org/6ku22ajjr/ . Изображение вставляется с помощью JFileChooser и FileInputStream. - person rullzing; 29.01.2016
comment
Визуализация BufferedImage в ячейке JTable. Теоретически ImageIcon должен рендериться JTable из коробки, если метод TableModel#getColumnClass возвращает ImageIcon.class или Icon.class - person MadProgrammer; 29.01.2016
comment
Разве это не относится только к отображению изображений? как я могу указать, какой из них какой? Кроме того, я не использую DefaultTableModel, я использую векторы - person rullzing; 29.01.2016
comment
Нет, не совсем, вы можете настроить каждый столбец по мере необходимости - person MadProgrammer; 29.01.2016
comment
Хорошо, полностью работоспособный пример. Я использовал автономную базу данных h2 для создания примера (и некоторых пользовательских изображений), но концепции должны быть переводимыми. - person MadProgrammer; 29.01.2016
comment
все, что мне было нужно, это класс TestPane. Мне пришлось проигнорировать векторный подход, потому что он никуда меня не вел. Спасибо ! - person rullzing; 29.01.2016