1

in a jsp page I want to display many images taken from a db (from a blob field).

Now i have this code in my jsp page:

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

In the servlet ShowImage i make a query using idI and i print the image.

This is not good to me, because i may have 100 items in my loop and ill have to call 100 times the servlet ShowImage; since i call the db inside the servlet ShowImage this would means that ill make 100 connections to the database, in just one page.

What's the right way to print a loop of images taken from a db (from a bliob field) with just on query?

MDP
  • 4,177
  • 21
  • 63
  • 119

2 Answers2

0

you can use the out of the JSTL

Here is a simple example:

The 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>

And the BackingBean, i initialized the List with the Images on the first Instantiation of the Bean, do this, if the number of your images wont change, otherwise you can query the list of the images fresh from the Database, when you call the getImages() Method or encapsulate this in another method and call this before return images; on the Bean.

So here is the Demo 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", "https://i.stack.imgur.com/7bI1Y.jpg"));
        images.add(new DisplayImage("Image2", "https://i.stack.imgur.com/XZ4V5.jpg"));
        images.add(new DisplayImage("Image3", "https://i.stack.imgur.com/7bI1Y.jpg"));
        images.add(new DisplayImage("Image4", "https://i.stack.imgur.com/iQFxo.gif"));
    }
    public List<DisplayImage> getImages() {
        return images;
    }

    public void setImages(List<DisplayImage> images) {
        this.images = images;
    }
}

And the Domain class

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;
    }
}

Now you can display all your Images on one JSP Page.

Patrick

Patrick
  • 4,532
  • 2
  • 26
  • 32
  • I dont have a URI for my images, i get them from a DB – MDP Jul 25 '14 at 11:38
  • 1
    Then fill your List with the Images from the Database.. you work with a ResultSet i think, so do for example like this: `DisplayImages di = new DisplayImage(); di.setName(rs.getString("nameCol")); di.setSourceUri(rs.getString("source"));` And add the Image within the while loop to a List and return this object. – Patrick Jul 25 '14 at 11:49
  • In the db i just have an InputStream (inside a blob field) for each image, i don't have the images uri – MDP Jul 25 '14 at 12:04
  • Okay, i see, then [this](http://stackoverflow.com/questions/10510416/jsp-convert-byte-array-to-an-image) and [that](http://stackoverflow.com/questions/5243726/how-to-display-an-image-in-jsp) Post should be helpful for you. – Patrick Jul 25 '14 at 12:18
  • But isn't there a way to do so without creating a wrapper class? A way to get a servlet to return a list of images and then use `${servletName}` to access that list? – parsecer Dec 21 '19 at 13:08
0

If you have plenty of memory in your server, and not too much images, simply preload everything in memory, but I must acknowledge it may not be a real option.

But your problem is really a question of caching the accesses to the database. It is easy to use one single query for the whole page, with the option of caching it for the duration of the session, depending on the disponible memory and the expected number of concurrent sessions.

Princips : in this answer, I will not separate the controller, service and database layers for brevity. As you get listaNews form the request attributes, I assume that you allready have a servlet that calculate this list put it in a request attribute and forward to your JSP. This servlet will load all the images from listaNews from database, and store them in session. Then ShowImage searches the image in session (if it is not there for any reason it should load it from database) and returns it. Optionaly, it removes it from session if saving memory is a concern.

I would implement it that way, using a count to send for evicting cached images from session - if <0, never evict, if >0 number of send before cache evict (1 for normal case) :

CachedImage : keeps image bytes and the number of times it can be sent

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();
    }
}

Modification in the servlet that prepares the page :

@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);
}

ShowImage :

@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
}
Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • Yes, u r right. Struggling with this issue, i get to this non-logic solution. I cant understand how can i print several images from a db with just one SELECT. – MDP Jul 25 '14 at 14:28
  • @MatteoDepasquali : Are your images static, and is their number change ? And if they may change what is the typical change rythme ? – Serge Ballesta Jul 25 '14 at 14:36
  • Imagine something like facebook. I have plenty of pic for every user. So, for every user page, i have to print all its pics it saved in the database (in a blob field). A user can have 1 or 100 pics, it can upload a new pic every day or never. – MDP Jul 25 '14 at 14:40
  • What is the typical size of your images ? But anyway, with 100 images I do not think that inlining is an option. – Serge Ballesta Jul 25 '14 at 14:55
  • the size is about 500 k. Actually, in this application probably there won't be more than 20-30 images per page. – MDP Jul 25 '14 at 15:28
  • Thank you for your help, I really appreciate it. After a week end of thoughts I came up to your same solution. Besides, this solution integrates well with my code, so I'll have to write few new code. Thank you – MDP Jul 28 '14 at 06:34