如何从数据库中检索和显示图像在JSP页面上?

33

我如何从数据库中检索并在JSP页面上显示图片?

6个回答

71

让我们逐步看看应该发生的事情:

  • JSP基本上是一种视图技术,用于生成HTML输出。
  • 要在HTML中显示图像,您需要使用HTML <img>元素。
  • 为了让它定位图像,您需要指定其src属性。
  • src属性需要指向有效的http://URL,而不是本地磁盘文件系统路径file://,因为当服务器和客户端在物理上不同的计算机上运行时,这种方式将无法工作。
  • 图像URL需要在请求路径(例如http://example.com/context/images/foo.png)或作为请求参数(例如http://example.com/context/images?id=1)中具有图像标识符。
  • 在JSP / Servlet世界中,您可以让Servlet侦听某个URL模式,例如/images/*,以便您可以在特定的URL上执行一些Java代码。
  • 图像是二进制数据,可以从DB中获取为byte[]InputStreamJDBC API 提供了ResultSet#getBytes()ResultSet#getBinaryStream()JPA API 提供了@Lob
  • 在Servlet中,您可以将此byte[]InputStream以通常的Java IO方式写入响应的OutputStream
  • 客户端需要指示数据应该被处理为图像,因此至少需要设置Content-Type响应头。您可以通过ServletContext#getMimeType()获取正确的MIME类型,基于图像文件扩展名,您可以通过<mime-mapping>web.xml中进行扩展和/或覆盖。

就是这样。它几乎可以自己编写代码了。让我们从HTML(在JSP中)开始:

<img src="${pageContext.request.contextPath}/images/foo.png">
<img src="${pageContext.request.contextPath}/images/bar.png">
<img src="${pageContext.request.contextPath}/images/baz.png">

如果需要,在使用JSTL 迭代时,也可以使用 EL 动态设置 src

<c:forEach items="${imagenames}" var="imagename">
    <img src="${pageContext.request.contextPath}/images/${imagename}">
</c:forEach>

然后定义/创建一个Servlet,它在URL模式/images/*上监听GET请求,下面的示例使用普通的JDBC完成此任务:

@WebServlet("/images/*")
public class ImageServlet extends HttpServlet {

    // content=blob, name=varchar(255) UNIQUE.
    private static final String SQL_FIND = "SELECT content FROM Image WHERE name = ?";

    @Resource(name="jdbc/yourDB") // For Tomcat, define as <Resource> in context.xml and declare as <resource-ref> in web.xml.
    private DataSource dataSource;
    
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String imageName = request.getPathInfo().substring(1); // Returns "foo.png".

        try (Connection connection = dataSource.getConnection(); PreparedStatement statement = connection.prepareStatement(SQL_FIND)) {
            statement.setString(1, imageName);
            
            try (ResultSet resultSet = statement.executeQuery()) {
                if (resultSet.next()) {
                    byte[] content = resultSet.getBytes("content");
                    response.setContentType(getServletContext().getMimeType(imageName));
                    response.setContentLength(content.length);
                    response.getOutputStream().write(content);
                } else {
                    response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
                }
            }
        } catch (SQLException e) {
            throw new ServletException("Something failed at SQL/DB level.", e);
        }
    }

}

就是这样。如果您担心头部和缓存标头以及对这些请求做出适当的响应,请使用此静态资源servlet的抽象模板

另请参阅:


我做了一个小改动,因为如果你正在使用Spring MVC,你需要添加return,否则我们会得到错误“at org.apache.catalina.connector.ResponseFacade.setBufferSize(ResponseFacade.java:233)”,因为响应已经被提交。当在设置响应头之前就已经提交响应时,响应就已经被提交了。 - Pulkit
@Pulkit:问题和答案基于纯JSP/Servlet,而不是Spring MVC。 - BalusC
1
@BalusC:我知道,我也提到了“如果你正在使用MVC”,实际上当用户使用MVC时,他可能会遇到这篇文章(就像我现在正在使用MVC一样)。 - Pulkit
1
@Pulkit:普通的JSP/Servlet也可以用作MVC。当前问题根本不涉及Spring MVC框架。如果您真的需要发布面向Spring MVC的答案/评论,请寻找正确的问题。 - BalusC
对于那些寻找基于Hibernate而非JDBC的解决方案的人,请查看https://dev59.com/5F_Va4cB1Zd3GeqPW8zE?lq=1 - KNU
显示剩余2条评论

6

0

我已经使用Oracle数据库在JSP中编写并配置了代码。 希望它能对你有所帮助。

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * Servlet implementation class displayfetchimage
 */
@WebServlet("/displayfetchimage")
public class displayfetchimage extends HttpServlet {
    private static final long serialVersionUID = 1L;

    /**
     * @see HttpServlet#HttpServlet()
     */
    public displayfetchimage() {
        super();
        // TODO Auto-generated constructor stub
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // TODO Auto-generated method stub
        Statement stmt = null;
        String sql = null;
        BufferedInputStream bin = null;
        BufferedOutputStream bout = null;
        InputStream in = null;

        response.setContentType("image/jpeg");
        ServletOutputStream out;
        out = response.getOutputStream();
        Connection conn = employee.DbConnection.getDatabaseConnection();
        HttpSession session = (HttpSession) request.getSession();
        String ID = session.getAttribute("userId").toString().toLowerCase();
        try {
            stmt = conn.createStatement();
            sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
            ResultSet result = stmt.executeQuery(sql);
            if (result.next()) {
                in = result.getBinaryStream(1);// Since my data was in first column of table.
            }
            bin = new BufferedInputStream(in);
            bout = new BufferedOutputStream(out);
            int ch = 0;
            while ((ch = bin.read()) != -1) {
                bout.write(ch);
            }

        } catch (SQLException ex) {
            Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (bin != null)
                    bin.close();
                if (in != null)
                    in.close();
                if (bout != null)
                    bout.close();
                if (out != null)
                    out.close();
                if (conn != null)
                    conn.close();
            } catch (IOException | SQLException ex) {
                System.out.println("Error : " + ex.getMessage());
            }
        }

    }

    // response.getWriter().append("Served at: ").append(request.getContextPath());
    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        Statement stmt = null;
        String sql = null;
        BufferedInputStream bin = null;
        BufferedOutputStream bout = null;
        InputStream in = null;

        response.setContentType("image/jpeg");
        ServletOutputStream out;
        out = response.getOutputStream();
        Connection conn = employee.DbConnection.getDatabaseConnection();
        HttpSession session = (HttpSession) request.getSession();
        String ID = session.getAttribute("userId").toString().toLowerCase();
        try {
            stmt = conn.createStatement();
            sql = "select user_image from employee_data WHERE username='" + ID + "' and rownum<=1";
            ResultSet result = stmt.executeQuery(sql);
            if (result.next()) {
                in = result.getBinaryStream(1);
            }
            bin = new BufferedInputStream(in);
            bout = new BufferedOutputStream(out);
            int ch = 0;
            while ((ch = bin.read()) != -1) {
                bout.write(ch);
            }

        } catch (SQLException ex) {
            Logger.getLogger(displayfetchimage.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                if (bin != null)
                    bin.close();
                if (in != null)
                    in.close();
                if (bout != null)
                    bout.close();
                if (out != null)
                    out.close();
                if (conn != null)
                    conn.close();
            } catch (IOException | SQLException ex) {
                System.out.println("Error : " + ex.getMessage());
            }
        }

    }

}

-1
尝试刷新并关闭输出流,如果它没有显示。Blob image = rs.getBlob(ImageColName);InputStream in = image.getBinaryStream();// 将 Blob 输出到 HttpServletResponseresponse.setContentType("image/jpeg");BufferedOutputStream o = new BufferedOutputStream(response.getOutputStream());
    byte by[] = new byte[32768];
    int index = in.read(by, 0, 32768);
    while (index != -1) {
        o.write(by, 0, index);
        index = in.read(by, 0, 32768);
    }
    o.flush();
    o.close();

-2

我使用了SQL SERVER数据库,因此答案的代码也是相应的。你只需要在jsp页面中包含一个<img>标签,并从它的src属性调用一个servlet就行了,像这样

<img width="200" height="180" src="DisplayImage?ID=1">

这里的1是数据库中图像的唯一ID,而ID是一个变量。我们在servlet中接收到此变量的值。在servlet代码中,我们从正确的列中获取二进制流输入。也就是说,您的图像存储在哪个列中。在我的代码中,我使用了第三列,因为我的图像以二进制数据形式存储在第三列中。从表中检索输入流数据后,我们将其内容读入输出流中,以便可以在屏幕上写入。就是这样

import java.io.*;  
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.*;  
import javax.servlet.http.*;  
import model.ConnectionManager;
public class DisplayImage extends HttpServlet { 
    public void doGet(HttpServletRequest request,HttpServletResponse response)  
             throws IOException  
    { 
    Statement stmt=null;
    String sql=null;
    BufferedInputStream bin=null;
    BufferedOutputStream bout=null;
    InputStream in =null;

    response.setContentType("image/jpeg");  
    ServletOutputStream out;  
    out = response.getOutputStream();  
    Connection conn = ConnectionManager.getConnection();

    int ID = Integer.parseInt(request.getParameter("ID"));
        try {
            stmt = conn.createStatement();
            sql = "SELECT * FROM IMAGETABLE WHERE ID="+ID+"";
            ResultSet result = stmt.executeQuery(sql);
            if(result.next()){
                in=result.getBinaryStream(3);//Since my data was in third column of table.
            }
            bin = new BufferedInputStream(in);  
            bout = new BufferedOutputStream(out);  
            int ch=0;   
            while((ch=bin.read())!=-1)  
                {  
                bout.write(ch);  
            }  

        } catch (SQLException ex) {
            Logger.getLogger(DisplayImage.class.getName()).log(Level.SEVERE, null, ex);
        }finally{
        try{
            if(bin!=null)bin.close();  
            if(in!=null)in.close();  
            if(bout!=null)bout.close();  
            if(out!=null)out.close();
            if(conn!=null)conn.close();
        }catch(IOException | SQLException ex){
            System.out.println("Error : "+ex.getMessage());
        }
    }


    }  
}  

在执行您的jsp或html文件后,您将在屏幕上看到图像。


警告:此代码不是线程安全的,会泄漏资源,并且内存效率低下。正确的方法请参见当前接受的答案。 - BalusC
亲爱的BalusC,您能使这段代码线程安全,并消除您所述的其他缺陷吗?谢谢。 - Gaurav Mahindra
@BalusC:我已经更新了我的答案。现在它是完美的。 - Gaurav Mahindra

-5

您还可以创建自定义标签来显示图像。

1)创建自定义标签Java类和TLD文件。

2)编写逻辑以显示图像,例如将byte[]转换为Base64字符串。

因此,它可用于每个图像,无论您是在单个JSP页面中显示一个图像还是多个图像。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接