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

Posted

技术标签:

【中文标题】如何在 JSP 页面中从数据库中检索和显示图像?【英文标题】:How to retrieve and display images from a database in a JSP page? 【发布时间】:2011-01-21 09:01:18 【问题描述】:

【问题讨论】:

【参考方案1】:

让我们分步看看会发生什么:

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 代码。 图像是二进制数据,将作为byte[]InputStream 从数据库中获取,JDBC API 为此提供ResultSet#getBytes()ResultSet#getBinaryStream(),JPA API 提供@Lob为此。 在 Servlet 中,您可以使用通常的 Java IO 方式将 byte[]InputStream 写入响应的 OutputStream。 需要指示客户端将数据作为图像处理,因此至少还需要设置Content-Type响应头。您可以根据图像文件扩展名通过ServletContext#getMimeType() 获取正确的图像文件扩展名,您可以通过web.xml 中的<mime-mapping> 扩展和/或覆盖。

应该是这样的。它几乎自己编写代码。让我们从 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 进行迭代时动态设置 src 和 EL:

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

然后定义/创建一个servlet,它在/images/* 的 URL 模式上侦听 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);
        
    


就是这样。如果您担心 HEAD 和缓存标头并正确响应这些请求,请使用此 abstract template for static resource servlet。

另见:

How should I connect to JDBC database / datasource in a servlet based application? How to upload an image and save it in database? Simplest way to serve static data from outside the application server in a Java web application

【讨论】:

@BalusC :如何在 Spring Framework 中做到这一点。控制器只返回一个视图。字节流如何返回。 @Ashwin:同样的方式。 Spring 不会禁止您创建另一个 servlet。 我做了一个小改动,因为如果您使用的是 spring MVC,您还需要添加 return 否则我们将在 org.apache.catalina.connector.ResponseFacade.setBufferSize(ResponseFacade.java: 233)" 因为已经提交了响应,所以在之前设置了响应头等时提交了响应 @BalusC:我知道先生,我还提到“如果您使用 MVC”实际上用户在使用 MVC 时可能会遇到这篇文章(就像我使用 MVC 一样)。 @Pulkit:Plain JSP/Servlet 也可以用作 MVC。当前的问题根本与 Spring MVC 框架无关。如果您确实需要发布针对 Spring MVC 的答案/评论,只需寻找正确的问题。【参考方案2】:

我建议您将其作为两个问题来解决。有几个与两者相关的问题和答案。

    如何从 mysql 加载 blob

    例如见Retrieve image stored as blob

    如何动态显示图片

    例如见Show thumbnail dynamically

【讨论】:

【参考方案3】:

如果输出流不显示,请尝试刷新并关闭它。 Blob image = rs.getBlob(ImageColName); InputStream in = image.getBinaryStream(); // 将 blob 输出到 HttpServletResponse response.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();

【讨论】:

【参考方案4】:

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

1) 创建自定义标签java类和tld文件。

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

因此,无论您是在单个 jsp 页面中仅显示一张图片还是多张图片,它都适用于每张图片。

【讨论】:

【参考方案5】:

我使用的是 SQL SERVER 数据库,所以答案的代码是一致的。你所要做的就是在你的jsp页面中包含一个&lt;img&gt;标签,然后像这样从它的src属性调用一个servlet

<img   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:我已经更新了我的答案。现在完美了。

以上是关于如何在 JSP 页面中从数据库中检索和显示图像?的主要内容,如果未能解决你的问题,请参考以下文章

如何在C#中从数据库中检索时将varBinary转换为图像或视频

如何在 Struts 2 中将数据库记录列表(通过 Hibernate 检索)显示到 JSP 页面?

在 C# 中从 Access 数据库存储和检索图像

在 PHP 中从数据库中检索数据并在同一页面上的 JQuery 中显示它们

如何在 PHP 中从 Parse 中检索图像文件?

Firestore如何在回收站视图中从firestore检索数据