【问题标题】:How to print image (a plenty of) in jsp如何在jsp中打印图像(大量)
【发布时间】:2014-07-25 10:36:28
【问题描述】:

在 jsp 页面中,我想显示从 db(来自 blob 字段)获取的许多图像。

现在我的 jsp 页面中有这段代码:

    <c:forEach var="news" items="${requestScope.listaNews}">    
            <img src="ShowImage?idI=${news.idImmagine}" >
    </c:forEach>

servlet ShowImage 中,我使用idI 进行查询并打印图像。

这对我不好,因为我的循环中可能有 100 个项目,我必须调用 servlet ShowImage 的 100 次;因为我在 servlet ShowImage 中调用了 db,这意味着只需要一页就可以与数据库建立 100 个连接。

仅在查询时打印从数据库(来自 bliob 字段)获取的图像循环的正确方法是什么?

【问题讨论】:

    标签: java jsp servlets


    【解决方案1】:

    如果您的服务器中有足够的内存,并且没有太多的图像,只需将所有内容预加载到内存中,但我必须承认这可能不是一个真正的选择。

    但是您的问题实际上是缓存对数据库的访问的问题。对整个页面使用单个查询很容易,并且可以选择在会话期间缓存它,具体取决于可分配的内存和预期的并发会话数。

    原则:在这个答案中,为简洁起见,我不会将控制器、服务和数据库层分开。当您从请求属性中获得listaNews 时,我假设您已经拥有一个计算此列表的servlet,将其放入请求属性中并转发到您的JSP。 这个 servlet 将从数据库中加载来自listaNews 的所有图像,并将它们存储在会话中。然后ShowImage 在会话中搜索图像(如果由于任何原因它不存在,它应该从数据库中加载它)并返回它。 (可选)如果需要节省内存,它会将其从会话中删除。

    我会以这种方式实现它,使用发送计数从会话中驱逐缓存的图像 - 如果 0 次(正常情况下为 1):

    CachedImage:保存图片字节数和可以发送的次数

    public class CachedImage {
        private static final int BUFFER_SIZE = 32768; // 32k buf
        byte[] data;
        int toSend;
    
        public CachedImage(int toSend, InputStream is) throws IOException {
            byte[] buffer = new byte[BUFFER_SIZE];
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            while (is.read(buffer) != -1) {
                os.write(buffer);
            }
            data = os.toByteArray();
        }
    }
    

    在准备页面的 servlet 中的修改:

    @Override
    protected void service(HttpServletRequest hsr, HttpServletResponse hsr1) throws ServletException, IOException {
        final int TO_SEND = 1; //number of time each image should be downloaded before purge (-1 = no purge)
        HashMap<String, CachedImage> images = new HashMap<String, CachedImage>();
        ...
        // calculates listaNews
        // loads all the images from database and store them in session
        for(...) { // loops for the images key id , InputStream is
            images.put(id, new CachedImage(TO_SEND, is));
        }
        HttpSession session = hsr.getSession();
        session.setAttribute("cachedImages", images);
    }
    

    显示图像:

    @Override
    protected void service(HttpServletRequest hsr, HttpServletResponse hsr1) throws ServletException, IOException {
        String id = hsr.getParameter("idI");
        HttpSession session = hsr.getSession();
        Map<String,CachedImage> images = (Map<String,CachedImage>) session.getAttribute("cachedImages");
        if (images != null) { // Ok map is in session
            CachedImage cached = images.get(id);
            if (cached != null) { // ok image is in cache
                if (cached.toSend > 0) { // if relevant, evict image from session cache
                    if (--cached.toSend == 0) {
                        images.remove(id);
                    }
                }
            }
            //send cached image : cached.data
        }
        // load image from database and send it
    }
    

    【讨论】:

    • 是的,你说得对。在这个问题上苦苦挣扎,我得到了这个非逻辑的解决方案。我不明白如何只用一个 SELECT 从数据库中打印多张图像。
    • @MatteoDepasquali:您的图像是静态的吗?它们的数量是否发生了变化?如果他们可能会改变什么是典型的改变节奏?
    • 想象一下 Facebook 之类的东西。我为每个用户提供了大量图片。因此,对于每个用户页面,我必须打印它保存在数据库中的所有图片(在 blob 字段中)。一个用户可以有 1 或 100 张照片,它可以每天上传一张新照片,也可以从不上传。
    • 图片的典型尺寸是多少?但无论如何,对于 100 张图片,我不认为内联是一种选择。
    • 大小约为 500 k。实际上,在这个应用程序中,每页可能不会超过 20-30 张图片。
    【解决方案2】:

    你可以用出JSTL

    这是一个简单的例子:

    JSP

    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    
    <!DOCTYPE html>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Image Overview</title>
        </head>
        <body>
            <c:forEach items="${imageBean.images}" step="1" var="img">
                <c:out value="${img.name}"/><br/>
                <img src="${img.sourceUri}"><br/>
            </c:forEach>
        </body>
    </html>
    

    还有 BackingBean,我在 Bean 的第一次实例化时用图像初始化了列表,如果图像的数量不会改变,请执行此操作,否则您可以从数据库中查询新的图像列表,当您调用getImages() 方法或将其封装在另一个方法中并在Bean 上的return images; 之前调用它。

    这里是演示 Bean

    import de.professional_webworkx.imagegallery.domain.DisplayImage;
    import java.io.Serializable;
    import java.util.ArrayList;
    import java.util.List;
    import javax.annotation.PostConstruct;
    import javax.enterprise.context.SessionScoped;
    import javax.inject.Named;
    
    
    @Named(value = "imageBean")
    @SessionScoped
    public class ImageBean implements Serializable {
    
        private List<DisplayImage> images = new ArrayList<>();
    
        @PostConstruct
        public void init() {
            images.add(new DisplayImage("Image1", "http://i.stack.imgur.com/7bI1Y.jpg"));
            images.add(new DisplayImage("Image2", "http://i.stack.imgur.com/XZ4V5.jpg"));
            images.add(new DisplayImage("Image3", "http://i.stack.imgur.com/7bI1Y.jpg"));
            images.add(new DisplayImage("Image4", "http://i.stack.imgur.com/iQFxo.gif"));
        }
        public List<DisplayImage> getImages() {
            return images;
        }
    
        public void setImages(List<DisplayImage> images) {
            this.images = images;
        }
    }
    

    还有域类

    import java.io.Serializable;
    
    
    public class DisplayImage implements Serializable {
    
        private String name;
        private String sourceUri;
    
        public DisplayImage() {
        }
    
        public DisplayImage(String name, String sourceUri) {
            this.name = name;
            this.sourceUri = sourceUri;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public String getSourceUri() {
            return sourceUri;
        }
    
        public void setSourceUri(String sourceUri) {
            this.sourceUri = sourceUri;
        }
    }
    

    现在您可以在一个 JSP 页面上显示所有图片。

    帕特里克

    【讨论】:

    • 我的图片没有 URI,我从数据库中获取
    • 然后用数据库中的图像填充您的列表。我认为您使用的是 ResultSet,所以例如这样做:DisplayImages di = new DisplayImage(); di.setName(rs.getString("nameCol")); di.setSourceUri(rs.getString("source")); 并将 while 循环中的图像添加到列表中 并返回此对象。
    • 在数据库中,每个图像我只有一个 InputStream(在 blob 字段内),我没有图像 uri
    • 好的,我明白了,那么thisthat 的帖子应该对你有帮助。
    • 但是没有创建包装类的方法吗?一种让 servlet 返回图像列表然后使用 ${servletName} 访问该列表的方法?
    猜你喜欢
    • 1970-01-01
    • 2016-11-10
    • 2014-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-20
    • 1970-01-01
    • 2013-06-12
    相关资源
    最近更新 更多