1

I need to get an image from MongoDB GridFS system, then displaying it in a JSP img tag. This is my code that isnt working:

@RequestMapping(value = "/getPhoto", method = RequestMethod.GET)
public @ResponseBody
void getPhoto(HttpServletRequest request,
        HttpServletResponse response) {
    try {
    System.out.println("getting photo...");
    GridFSDBFile imageForOutput = userFacade.loadProfilePhoto((User) SecurityContextHolder.getContext().getAuthentication()
            .getPrincipal());
    BufferedImage image = ImageIO.read(imageForOutput.getInputStream());
    byte[] imageBytes = ((DataBufferByte) image.getData().getDataBuffer()).getData();
    response.setHeader("expires", "0"); 
    response.setContentType("image/jpg");
    response.setContentLength(imageBytes.length);
    OutputStream out = response.getOutputStream();
    out.write(imageBytes, 0, imageBytes.length);
    out.flush();
    out.close();
    return;
    } catch (Exception e) {
        // TODO Auto-generated catch block
    }

Firstly i get the GridFSDBFile and then I need to get the byte[].After that i write it in the response object but i dont know if i am doing it correctly.

The code in the JSP is as follows:

<c:url var="getPhoto" value="/settingsAdmin/getPhoto" />
<div id="preview">
   <img id="imagePreview" src="${getPhoto}" alt="Profile Photo"/>
</div>

Finally, the controller is called correctly but the mistake must be inside it.

Thx in advance

guille209
  • 23
  • 1
  • 6
  • The approach here is not a very good one. You should **not** inline image data in you markup. You **should** use a controller endpoint to simulate a file. The general approach is shown [here](http://stackoverflow.com/a/22400508/2313887) – Neil Lunn Mar 27 '14 at 09:24
  • don't know too much about JSP. what exactly is the error? you can't see the image or something? here is an [example](http://stackoverflow.com/questions/1207190/embedding-base64-images) if you want to embed image data into the tag. It's definitely not a good idea though. – yaoxing Mar 27 '14 at 09:54
  • The issue is that the img is not shown in the view, is there anyway to get the Base64 string from the GridfsDbFile so as to show it in the view at least, its the first time i do it – guille209 Mar 27 '14 at 10:07
  • How is this in-lined? I thought to be in-lined you had to set the `src` attribute to something like 'data:'. All he is doing is calling a Spring controller that is returning a binary same as it would for reading an image off the drive. – CodeChimp Mar 27 '14 at 11:20
  • So , is this the correct approach? Because i think this way it doesnt work either out.write(Base64.encode(imageBytes),0,Base64.encode(imageBytes).length); – guille209 Mar 27 '14 at 11:29

2 Answers2

1

Finally i reached a solution by myself, i post it so others can work it out:

The Controller part

@RequestMapping(value = "/getPhoto", method = RequestMethod.GET)
public @ResponseBody
void getPhoto(HttpServletRequest request,
        HttpServletResponse response) {
    try {
            GridFSDBFile imageForOutput = userFacade.loadProfilePhoto((User) SecurityContextHolder.getContext().getAuthentication()
                    .getPrincipal());
            InputStream is = imageForOutput.getInputStream();
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int nRead;
            byte[] data = new byte[16384];
            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            buffer.flush();
            byte[]imagenEnBytes = buffer.toByteArray();


            response.setHeader("Accept-ranges","bytes");
            response.setContentType( "image/jpeg" );
            response.setContentLength(imagenEnBytes.length);
            response.setHeader("Expires","0");
            response.setHeader("Cache-Control","must-revalidate, post-check=0, pre-check=0");
            response.setHeader("Content-Description","File Transfer");
            response.setHeader("Content-Transfer-Encoding:","binary");

            OutputStream out = response.getOutputStream();
            out.write( imagenEnBytes );
            out.flush();
            out.close();
    } catch (Exception e) {
        // TODO Auto-generated catch block

    }

}

The JSP view

<c:url var="getPhoto" value="/settingsAdmin/getPhoto" />
<div id="preview">
    <img id="imagePreview" src="${getPhoto}"alt="Profile Photo"/>
</div>

Thank you everyone for your help

guille209
  • 23
  • 1
  • 6
0

try this,

@Controller
public class GetImageController {

    private static final int DEFAULT_BUFFER_SIZE = 10240; // 10KB.

    @Autowired
    ServletContext servletContext;

    @RequestMapping(value="/getImage", method=RequestMethod.GET)
    public void getPhoto(HttpServletRequest request,
            HttpServletResponse response) {
        try {
        System.out.println("getting photo...");

        File image = new File("E:\\path\\to\\image.jpg");
        System.out.println("file exists: "+image.exists());
        // Get content type by filename.
        String contentType = servletContext.getMimeType(image.getName());

        // Init servlet response.
        response.reset();
        response.setBufferSize(DEFAULT_BUFFER_SIZE);
        response.setContentType(contentType);
        response.setHeader("Content-Length", String.valueOf(image.length()));
        response.setHeader("Content-Disposition", "inline; filename=\"" + image.getName() + "\"");

        // Prepare streams.
        BufferedInputStream input = null;
        BufferedOutputStream output = null;

        try {
            // Open streams.
            input = new BufferedInputStream(new FileInputStream(image), DEFAULT_BUFFER_SIZE);
            output = new BufferedOutputStream(response.getOutputStream(), DEFAULT_BUFFER_SIZE);

            // Write file contents to response.
            byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
            int length;
            while ((length = input.read(buffer)) > 0) {
                output.write(buffer, 0, length);
            }
        } finally {
            // Gently close streams.
            close(output);
            close(input);
        }
        // Check if file is actually an image (avoid download of other files by hackers!).
        // For all content types, see: http://www.w3schools.com/media/media_mimeref.asp
        if (contentType == null || !contentType.startsWith("image")) {
            // Do your thing if the file appears not being a real image.
            // Throw an exception, or send 404, or show default/warning image, or just ignore it.
            response.sendError(HttpServletResponse.SC_NOT_FOUND); // 404.
            return;
        }

    }

    // Helpers (can be refactored to public utility class) ----------------------------------------

    private static void close(Closeable resource) {
        if (resource != null) {
            try {
                resource.close();
            } catch (IOException e) {
                // Do your thing with the exception. Print it, log it or mail it.
                e.printStackTrace();
            }
        }
    }
}

and in jsp render image like:

<c:url value="/getImage" var="imgUrl"/>
<img alt="my image" src="${imgUrl}"> //to display on browser
<a href="${imgUrl}">img</a> //to display in new window

Note: This is not better way to display images in spring MVC, But in Servlets


Other way is(two lines of code):

return direct byte[] and specify produces = MediaType.IMAGE_JPEG_VALUE in @RequestMapping like:

@RequestMapping(value="/getImage", method=RequestMethod.GET, produces = MediaType.IMAGE_JPEG_VALUE)
    public @ResponseBody byte[] getPhoto() throws IOException {
        System.out.println("getting photo...");

        FileInputStream image = new FileInputStream(new File("E:\\path\\to\\image.jpg"));
        return IOUtils.toByteArray(image);        
    }

Both way's are worked fine for me.

Abhishek Nayak
  • 3,732
  • 3
  • 33
  • 64