You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

无法将数据库Blob格式图片显示到JavaFX TableView的问题求助

问题:数据库Blob图片无法在JavaFX TableView中显示

我尝试将数据库中以Blob格式存储的图片显示到TableView的图片列中,其他数据均能正常展示,唯有图片列无法显示。


现有代码

1. 加载数据到TableView的方法

public void loadPropertyData() throws IOException {
    try {
        Connection connection = OracleConnect.getConnection();
        String query = "SELECT id, property, image, price, contact, location, status FROM property" + getProfileName().getText();
        PreparedStatement statement = connection.prepareStatement(query);
        ResultSet resultSet = statement.executeQuery();
        ObservableList<Property> propertyList = FXCollections.observableArrayList();

        while (resultSet.next()) {
            int id = resultSet.getInt("id");
            String property = resultSet.getString("property");
            Blob imageBlob = resultSet.getBlob("image");
            Image image = null;
            if (imageBlob != null) {
                InputStream is = imageBlob.getBinaryStream();
                image = new Image(is);
            }
            String price = resultSet.getString("price");
            String contact = resultSet.getString("contact");
            String location = resultSet.getString("location");
            String status = resultSet.getString("status");

            Property propertyObj = new Property(id, property, image, price, contact, location, status);
            propertyList.add(propertyObj);
        }

        propertyIDColumn.setCellValueFactory(cellData -> cellData.getValue().idProperty().asObject());
        propertyColumn.setCellValueFactory(cellData -> cellData.getValue().propertyProperty());
        propertyImageColumn.setCellValueFactory(col -> col.getValue().imageProperty());
        propertyImageColumn.setCellFactory(col -> {
            TableCell<Property, Image> cell = new TableCell<Property, Image>() {
                private final ImageView imageView = new ImageView();

                {
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                }

                @Override
                protected void updateItem(Image item, boolean empty) {
                    super.updateItem(item, empty);

                    if (empty || item == null) {
                        imageView.setImage(null);
                        setGraphic(null);
                    } else {
                        imageView.setImage(item);
                        setGraphic(imageView);
                    }
                }
            };

            return cell;
        });
        propertyPriceColumn.setCellValueFactory(cellData -> cellData.getValue().priceProperty());
        propertyContactColumn.setCellValueFactory(cellData -> cellData.getValue().contactProperty());
        propertyLocationColumn.setCellValueFactory(cellData -> cellData.getValue().locationProperty());
        propertyStatusColumn.setCellValueFactory(cellData -> cellData.getValue().statusProperty());

        propertyTableView.setItems(propertyList);

        resultSet.close();
        statement.close();
        connection.close();
    } catch (SQLException e) {
        e.printStackTrace();
    }
}

2. Property模型类

public class Property {
    private IntegerProperty id;
    private StringProperty property;
    private ObjectProperty<Image> image;
    private StringProperty price;
    private StringProperty contact;
    private StringProperty location;
    private StringProperty status;

    public Property(int id, String property, Image image, String price, String contact, String location, String status) {
        this.id = new SimpleIntegerProperty(id);
        this.property = new SimpleStringProperty(property);
        this.image = new SimpleObjectProperty<>(image);
        this.price = new SimpleStringProperty(price);
        this.contact = new SimpleStringProperty(contact);
        this.location = new SimpleStringProperty(location);
        this.status = new SimpleStringProperty(status);
    }

    public IntegerProperty idProperty() {
        return id;
    }

    public int getId() {
        return id.get();
    }

    public void setId(int id) {
        this.id.set(id);
    }

    public StringProperty propertyProperty() {
        return property;
    }

    public String getProperty() {
        return property.get();
    }

    public void setProperty(String property) {
        this.property.set(property);
    }

    public ObjectProperty<Image> imageProperty() {
        return image;
    }

    public Image getImage() {
        return image.get();
    }

    public void setImage(Image image) {
        this.image.set(image);
    }

    public StringProperty priceProperty() {
        return price;
    }

    public String getPrice() {
        return price.get();
    }

    public void setPrice(String price) {
        this.price.set(price);
    }

    public StringProperty contactProperty() {
        return contact;
    }

    public String getContact() {
        return contact.get();
    }

    public void setContact(String contact) {
        this.contact.set(contact);
    }

    public StringProperty locationProperty() {
        return location;
    }

    public String getLocation() {
        return location.get();
    }

    public void setLocation(String location) {
        this.location.set(location);
    }

    public StringProperty statusProperty() {
        return status;
    }

    public String getStatus() {
        return status.get();
    }

    public void setStatus(String status) {
        this.status.set(status);
    }
}

3. 创建数据库表及插入数据的代码

@FXML
private void Signup() {
    Connection connection = null;
    PreparedStatement createTableStatement = null;
    PreparedStatement createSequenceStatement = null;
    PreparedStatement insertStatement = null;

    try {
        connection = OracleConnect.getConnection();

        // Create table
        String createTableProperty = "CREATE TABLE property" + signupTF.getText() +
                " (" +
                "    id NUMBER," +
                "    property VARCHAR2(50)," +
                "    image BLOB," +
                "    price VARCHAR2(50)," +
                "    contact VARCHAR2(50)," +
                "    location VARCHAR2(50)," +
                "    status VARCHAR2(50)" +
                ")";
        createTableStatement = connection.prepareStatement(createTableProperty);
        createTableStatement.execute();

        // Create sequence
        String createSequenceProperty = "CREATE SEQUENCE property" +
                signupTF.getText() + "_seq " +
                "START WITH 1 " +
                "INCREMENT BY 1 " +
                "MINVALUE 1 " +
                "NOCACHE";
        createSequenceStatement = connection.prepareStatement(createSequenceProperty);
        createSequenceStatement.execute();

        // Insert data
        String insertData = "INSERT INTO property" + signupTF.getText() +
                " (id, property, image, price, contact, location, status)" +
                " VALUES (property" + signupTF.getText() + "_seq.nextval, ?, ?, ?, ?, ?, ?)";
        insertStatement = connection.prepareStatement(insertData);
        insertStatement.setString(1, "Property Name"); // Set the property name
        insertStatement.setBlob(2, new FileInputStream(new File("path/to/image.jpg"))); // Set the image file
        insertStatement.setString(3, "Price"); // Set the price
        insertStatement.setString(4, "Contact"); // Set the contact
        insertStatement.setString(5, "Location"); // Set the location
        insertStatement.setString(6, "Status"); // Set the status
        insertStatement.execute();

    } catch (SQLException e) {
        if (e.getErrorCode() == 1400) {
            JOptionPane.showMessageDialog(null, "Please enter required information");
        } else {
            JOptionPane.showMessageDialog(null, "An error occurred: " + e.getMessage());
        }
    } catch (FileNotFoundException e) {
        JOptionPane.showMessageDialog(null, "Image file not found: " + e.getMessage());
    } finally {
        try {
            if (insertStatement != null) {
                insertStatement.close();
            }
            if (createSequenceStatement != null) {
                createSequenceStatement.close();
            }
            if (createTableStatement != null) {
                createTableStatement.close();
            }
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            JOptionPane.showMessageDialog(null, "An error occurred while closing the resources: " + e.getMessage());
        }
    }
}

现状说明

  • 数据库表中已存储包含Blob图片的数据,表内图片字段显示有内容
  • TableView中ID、名称、价格等列均正常展示,仅图片列无任何内容

排查与解决建议

1. 验证Image对象是否有效

在加载图片的代码块中添加日志,确认从Blob生成的Image对象是否正常:

if (imageBlob != null) {
    InputStream is = imageBlob.getBinaryStream();
    image = new Image(is);
    // 打印日志验证
    System.out.println("Image状态: " + (image != null) + ",宽度: " + (image != null ? image.getWidth() : 0));
}

如果Image宽度为0,说明数据流读取不完整或图片格式不兼容。

2. 关闭Blob输入流

使用try-with-resources自动关闭输入流,避免资源泄漏导致数据读取异常:

if (imageBlob != null) {
    try (InputStream is = imageBlob.getBinaryStream()) {
        image = new Image(is);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

3. 设置ImageView显示尺寸

默认ImageView可能尺寸为0,导致图片不可见,在TableCell初始化时添加尺寸设置:

{
    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    imageView.setFitWidth(80);
    imageView.setFitHeight(80);
    imageView.setPreserveRatio(true); // 保持图片比例
}

4. 确认查询表名正确性

检查查询语句中拼接的表名property + getProfileName().getText()是否和创建的表名完全一致,避免查询错误表导致图片数据为空。

5. 处理JavaFX线程问题

如果loadPropertyData在后台线程执行,需确保Image对象在JavaFX应用线程中创建:

if (imageBlob != null) {
    byte[] imageBytes = imageBlob.getBytes(1, (int) imageBlob.length());
    Platform.runLater(() -> {
        image = new Image(new ByteArrayInputStream(imageBytes));
    });
}

内容的提问来源于stack exchange,提问作者phamnguyen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 13:55:54