【问题标题】:How to show my Photo from Mysql in JAVAFX如何在 JAVAFX 中显示我的 Mysql 中的照片
【发布时间】:2017-09-26 21:28:45
【问题描述】:

我正在从我的网络摄像头拍摄一张照片,首先保存在 D: 驱动器中,然后从 D: 驱动器作为 Blob 保存到 MySQL 中的数据库。我想在表格视图中更改行时显示该图片。所有其他值都在表格视图中工作,显示在文本字段中,但我无法从数据库中检索图像。这是我的 tableview 的图片:

Tableview OK 有一个 ImageView,我想在其中显示与所选行对应的图像。

首先这是将图片保存到db的代码。

//Guardar datos visitantes en DB
public void guardar(ActionEvent event) throws Exception{

    if ( txtcedula.getText().equals("") || 
         txtnombres.getText().equals("") ||
         txtapellidos.getText().equals("")|| 
         txtapartamento.getText().equals("")||
         txtcelular.getText().equals("") ||
         txtobservaciones.getText().equals("")) {

        lblcampos.setText("No debe haber campos vacios");
    } else {
        ConexionSQL cn = new ConexionSQL();
        Connection con = cn.conexion();
        FileInputStream fis = null;
        String ubicaimg = "@../../../../../../Kamui/Imagenes/foto.jpg";
        File archivo = new File(ubicaimg);
        fis = new FileInputStream(archivo);
        //fin busqueda de la foto
        String ced,nom,ape,conj,apto,cel,obs;
        String sql="";
        ced=txtcedula.getText();
        nom=txtnombres.getText();
        ape=txtapellidos.getText();
        conj=cmbconjunto.getSelectionModel().getSelectedItem().toString();
        apto=txtapartamento.getText();
        cel=txtcelular.getText();
        obs = txtobservaciones.getText();

        sql="INSERT INTO visitantes (cedula_visi,nombre_visi,apellidos_visi,nomconj_visi,apartamento_visi,celular_visi,observaciones_visi,foto_visi) VALUES (?,?,?,?,?,?,?,?)";
        try{
            PreparedStatement sta = con.prepareStatement(sql);
            sta.setString(1,ced);
            sta.setString(2,nom);
            sta.setString(3,ape);
            sta.setString(4,conj);
            sta.setString(5,apto);
            sta.setString(6,cel);
            sta.setString(7,obs);
            sta.setBinaryStream(8, fis, (int) archivo.length());//se convierte la imagen en binary y se guarda como BLOB
            sta.executeUpdate();
            lblcampos.setText("Guardado Con exito");
            lblinfocamara.setVisible(false);
        } catch(Exception e){
             String info = e.getMessage();
             lblinfo.setText(info);

        }
    }
}

这是在文本字段中显示其他值的代码

package application;


import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.sql.Blob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;

import javax.imageio.ImageIO;
import javax.imageio.stream.FileImageOutputStream;
import javax.swing.ImageIcon;

import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.image.ImageView;



public class ver_visitantes implements Initializable {

    @FXML private TableView<visitantes> tbvisitantes;//enlazar tableview con el objeto visitantes
    @FXML private TableColumn<visitantes, String> clcedula;
    @FXML private TableColumn<visitantes, String> clnombres;
    @FXML private TableColumn<visitantes, String> clapellidos;
    @FXML private TableColumn<visitantes, String> clhentrada;
    @FXML private TableColumn<visitantes, String> clconjunto;
    @FXML private TableColumn<visitantes, String> clapartamento;
    @FXML private TableColumn<visitantes, String> clcelular;
    @FXML private TableColumn<visitantes, String> clobservaciones;
    @FXML private ImageView imgfotovisi;
    @FXML private TextField txtcedula;
    @FXML private TextField txtnombres;
    @FXML private TextField txtapellidos;
    @FXML private TextField txtconjunto;
    @FXML private TextField txtapto;
    @FXML private TextField txtcelular;
    @FXML private TextField txtobservaciones;
    @FXML private Label lbltest; 
    private ObservableList<visitantes> visitorlist;//dar nombre al observable list que se llena con el objeto visitantes

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        ConexionSQL cnt = new ConexionSQL();
        cnt.conexion();
        visitorlist = FXCollections.observableArrayList();
        visitantes.llenarlistavisitas(cnt.conexion(), visitorlist);
        tbvisitantes.setItems(visitorlist);//llenar table view con la lista
        imgfotovisi.getClass().getResourceAsStream("imagenes/huellabiometrico.jpg");
        //enlazar cada columna con el campo a llenar del resultset con los metodos getter 
        clcedula.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getcedula()));
        clnombres.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getnombres()));
        clapellidos.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getapellidos()));
        clconjunto.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getconjunto()));
        clapartamento.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getapartamento()));
        clcelular.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getcelular()));
        clobservaciones.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().getobservaciones()));
        clhentrada.setCellValueFactory(cellData -> new ReadOnlyStringWrapper(cellData.getValue().gethentrada()));
        gestionarEventos();
        /*visitantes visi = new visitantes(null, null, null, null, null, null, null, null, null);
        String image;
        image = visi.getfoto();

        imgfotovisi.setId(image);*/
    }


    public void gestionarEventos(){

        tbvisitantes.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<visitantes>() {
            @Override
            public void changed(ObservableValue<? extends visitantes> arg0,
                    visitantes valorAnterior, visitantes valorSeleccionado) {
                if (valorSeleccionado!=null){
                    txtcedula.setText(String.valueOf(valorSeleccionado.getcedula()));
                    txtnombres.setText(valorSeleccionado.getnombres());
                    txtapellidos.setText(valorSeleccionado.getapellidos());
                    txtconjunto.setText(String.valueOf(valorSeleccionado.getconjunto()));
                    txtapto.setText(String.valueOf(valorSeleccionado.getapartamento()));
                    txtcelular.setText(String.valueOf(valorSeleccionado.getcelular()));
                    txtobservaciones.setText(String.valueOf(valorSeleccionado.getobservaciones()));
                 }
             }
         });
     }
 }

这是visitantes对象

package application;

import java.sql.Blob;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.ObservableList;

public class visitantes {
    private StringProperty cedula;
    private StringProperty nombres;
    private StringProperty apellidos;
    private StringProperty hentrada;
    private StringProperty conjunto;
    private StringProperty apartamento;
    private StringProperty celular;
    private StringProperty observaciones;
    private Blob foto;


    public visitantes(String cedula,String nombres,String apellidos,String hentrada,String conjunto,String apartamento,String celular,String observaciones,Blob foto){

        this.cedula = new SimpleStringProperty(cedula);
        this.nombres = new SimpleStringProperty(nombres);
        this.apellidos = new SimpleStringProperty(apellidos);
        this.hentrada = new SimpleStringProperty(hentrada);
        this.conjunto = new SimpleStringProperty(conjunto);
        this.apartamento = new SimpleStringProperty(apartamento);
        this.celular = new SimpleStringProperty(celular);
        this.observaciones = new SimpleStringProperty(observaciones);
        this.foto = foto;
    }



    public String getnombres(){
        return nombres.get();
    }

    public void setnombres(String nombres){
        this.nombres = new SimpleStringProperty(nombres);
    }

    public String getcedula(){
        return cedula.get();
    }

    public void setcedula(String cedula){
        this.cedula = new SimpleStringProperty(cedula);
    }
    public String getapellidos(){
        return apellidos.get();
    }

    public void setapellidos(String apellidos){
        this.apellidos = new SimpleStringProperty(apellidos);
    }

    public String gethentrada(){
        return hentrada.get();
    }

    public void sethentrada(String hentrada){
        this.hentrada = new SimpleStringProperty(hentrada);
    }

    public String getconjunto(){
        return conjunto.get();
    }

    public void setconjunto(String conjunto){
        this.conjunto = new SimpleStringProperty(conjunto);
    }

    public String getapartamento(){
        return apartamento.get();
    }

    public void setapartamento(String apartamento){
        this.apartamento = new SimpleStringProperty(apartamento);
    }

    public String getcelular(){
        return celular.get();
    }

    public void setcelular(String celular){
        this.celular = new SimpleStringProperty(celular);
    }

    public String getobservaciones(){
        return observaciones.get();
    }

    public void setobservaciones(String observaciones){
        this.observaciones = new SimpleStringProperty(observaciones);
    }
public Blob getfoto(){
        return foto;
}

    public static void llenarlistavisitas(Connection connection, ObservableList<visitantes> lista){
        try {
            String sql="SELECT * FROM visitantes";
            Statement statement = connection.createStatement();
            ResultSet visitantes = statement.executeQuery(sql);
                while (visitantes.next()){
                lista.add (
                        new visitantes(

                                visitantes.getString("cedula_visi"),
                                visitantes.getString("nombre_visi"),
                                visitantes.getString("apellidos_visi"),
                                visitantes.getString("hentrada"),
                                visitantes.getString("nomconj_visi"),
                                visitantes.getString("apartamento_visi"),
                                visitantes.getString("celular_visi"),
                                visitantes.getString("observaciones_visi"),
                                visitantes.getBlob("foto_visi")

                                      )

                         );
                    }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

我希望你能帮我解决这个问题。非常感谢。

【问题讨论】:

  • 如果出现以下情况,回答您的问题会容易得多: 1. 布置布局以便阅读(只需使用您的 IDE 生成标准的、可识别的代码布局:您真的不应该有30+列缩进),2.你使用proper naming conventions

标签: java database image javafx imageview


【解决方案1】:

Blob 对象不包含相应 blob 数据库字段中的数据,而只是指向 SQL BLOB 数据的指针。显然,此指针仅在存在与数据库的有效连接(通过打开的结果集或更新语句)时才有效。 Javadocs 声明为

默认情况下,驱动程序使用 SQL 定位器 (BLOB) 实现 Blob,这意味着 Blob 对象包含指向 SQL BLOB 数据的逻辑指针,而不是数据本身。 Blob 对象在交易期间有效 [原文如此] 已创建

(重点是我的。)

因此,将Blob 存储为模型对象的一部分是没有意义的。当您访问Blob时,数据库事务已经完成,JavaBlob实例与数据库BLOB数据之间的连接将不再存在。

一个选项可能是在您从数据库中检索数据时实际加载每个实例的图像,并在Visitantes 模型中创建一个Image 字段。

您基本上可以通过将Visitante 类中foto 的类型从Blob 更改为Image 来实现。然后当你从数据库中加载数据时,替换

new visitantes(         
    visitantes.getString("cedula_visi"),
    visitantes.getString("nombre_visi"),
    visitantes.getString("apellidos_visi"),
    visitantes.getString("hentrada"),
    visitantes.getString("nomconj_visi"),
    visitantes.getString("apartamento_visi"),
    visitantes.getString("celular_visi"),
    visitantes.getString("observaciones_visi"),
    visitantes.getBlob("foto_visi")
)

new visitantes(         
    visitantes.getString("cedula_visi"),
    visitantes.getString("nombre_visi"),
    visitantes.getString("apellidos_visi"),
    visitantes.getString("hentrada"),
    visitantes.getString("nomconj_visi"),
    visitantes.getString("apartamento_visi"),
    visitantes.getString("celular_visi"),
    visitantes.getString("observaciones_visi"),
    new Image(visitantes.getBlob("foto_visi").getBinaryStream(), false)
)

然后在表中选中项的更改监听器中,你可以简单地做

imgfotovisi.setImage(valorSeleccionado.getFoto());

但是,图像作为 Java 对象通常非常大,并且这种方法可能会使用不合理的内存量:事实上,如果项目列表相当大(完全),您就会冒程序的风险OufOfMemoryErrors 失败。

相反,我强烈建议在选择更改时重新连接到数据库以检索新图像。 (即根据需要获取图像。)您需要在此处考虑一些并发问题(进一步讨论),并处理选择更改速度快于从数据库加载图像的可能性。

我假设cedula 是数据库中的主键,我将从您的数据访问器类中的一个方法开始:

public Image getImageById(String id) throws SQLException, IOException  {

    try (
        Connection con = ... ;
        PreparedStatement ps = con.prepareStatement(
            "SELECT foto_visi FROM visitantes WHERE cedula_visi = ?");
    ) {

        ps.setString(1, id);
        ResultSet results = ps.executeQuery();
        Image img = null ;
        if (results.next()) {
            Blob foto = results.getBlob("foto_visi");
            InputStream is = foto.getBinaryStream();
            img = new Image(is, false) ; // false = no background loading
            is.close();
        }
        results.close();
        return img ;
    }
}

检索图像非常耗时,应在后台线程上执行。另外,如果用户在图像检索过程中选择了新的表项,则需要取消现有的图像检索(否则最终会出现竞态条件,可能导致在检索时显示不正确的图像)一切都完成了)。 Service 非常适合这个。回到控制器,我会这样做:

private final Service<Image> imageRetrievalService = new Service<Image>() {
    @Override
    protected Task<Image> createTask() {
        final String id ;
        final Visitante visitante = tbvisitantes.getSelectionModel().getSelectedItem();
        if (visitante == null) {
            id = null ;
        } else {
            id = visitante.getCedula();
        }
        return new Task<Image>() {
            @Override
            protected Image call() throws Exception {
                if (id == null) {
                    return null ;
                }
                return dataAccessor.getImageById(id);
            }
        } ;
    }
};

现在你可以这样做了:

public void gestionarEventos(){

    tbvisitantes.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<visitantes>() {



        @Override
        public void changed(ObservableValue<? extends visitantes> arg0,
                visitantes valorAnterior, visitantes valorSeleccionado) {

            // cancel any image retrieval and start new one:
            imageRetrievalService.restart();

            if (valorSeleccionado!=null){
                txtcedula.setText(valorSeleccionado.getcedula());
                txtnombres.setText(valorSeleccionado.getnombres();
                txtapellidos.setText(valorSeleccionado.getapellidos());
                txtconjunto.setText(valorSeleccionado.getconjunto()));
                txtapto.setText(valorSeleccionado.getapartamento());
                txtcelular.setText(valorSeleccionado.getcelular());
                txtobservaciones.setText(valorSeleccionado.getobservaciones());
            }
        }
    });

    imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty());

}

最后,只需从 Visitante 类中删除 foto 字段及其 get/set 方法。

【讨论】:

  • 嗨。谢谢你的回答 James_D 。我试图插入方法 getImageById() 并需要为 Image 做一个导入; 1-java.awt.Image; 2-javafx.scene.image.Image;或 3- com.sun.prism.Image;哪一个是正确的进口?如果我导入 java.awt.Image;一,我在这一行得到一个错误 img = new Image(is, false) ; //不能实例化类型Image。
  • @YolfranMontañoCorredor javafx.scene.image.Image 之一。 (因为这是你需要传递给图像视图的那个......)
  • 我还有一个小问题,在最后的 imageRetrievalService 中出现语法错误。返回 dataAccessor.getImageById(id); } }//语法错误,插入;完成退货声明。 } };如果我把“;”在那一行得到更多的错误,需要导入“任务”,javafx.current,但是dataAccessor.getImageById(id)中的错误;行出现dataAccessor无法解析
  • 添加了缺少的;。您显然需要将 dataAccessor 替换为对您用于数据访问的任何类的实例的引用(即您定义 getImageById(...); 的类的实例。)
  • OMG 终于成功了:D thakas 很多,你是编程之神。Thaks 很多 James_D
【解决方案2】:

这是显示保存为 Blob 的 DB Mysql 中的图片的最终解决方案。

在我的 ver_visitantes 类中我添加了这个

            private final Service<Image> imageRetrievalService = new Service<Image>() {
            @Override
            protected Task<Image> createTask() {
                final String id ;
                final visitantes visitante = tbvisitantes.getSelectionModel().getSelectedItem();
                if (visitante == null) {
                    id = null ;
                } else {
                    id = visitante.getcedula();
                }
                return new Task<Image>() {
                    @Override
                    protected Image call() throws Exception {
                        if (id == null) {
                            return null ;
                        }
                        return visitante.getImageById(id);
                    }
                };
            }
        };

并将此代码添加到访问者类

//getter image
            public Image getImageById(String id) throws SQLException, IOException  {
                try (
                        ConexionSQL cn = new ConexionSQL();
                        Connection con = cn.conexion();
                    PreparedStatement ps = con.prepareStatement(
                        "SELECT foto_visi FROM visitantes WHERE cedula_visi = ?");
                ) {
                    ps.setString(1, id);
                    ResultSet results = ps.executeQuery();
                    Image img = null ;
                    if (results.next()) {
                        Blob foto = results.getBlob("foto_visi");
                        InputStream is = foto.getBinaryStream();
                        img = new Image(is) ; // false = no background loading 
                        is.close();
                    }
                    results.close();
                    return img ;
                } catch (Throwable e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
                return null;
            }//fin getter image

在这一行

  img = new Image(is, false) ; // false = no background loading

使用 James_D 代码向我显示一个错误,它已修复,如 eclipse 建议的那样删除“,false”。

img = new Image(is);

当然这行在我的 gestionarEventos();

imgfotovisi.imageProperty().bind(imageRetrievalService.valueProperty());

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-06
    相关资源
    最近更新 更多