Изображението не се сервира в jsp от Servlets

Имам jsp, в който за всеки ред от таблицата трябва да покажа изображението, присъстващо в базата данни. Извличам всички данни от реда на таблицата от базата данни, включително изображението като Blob, и го съхранявам в bean. Изображението се съхранява в bean като байтов масив по следния начин:

photo = rs.getBlob("PHOTO");
photoByteArray = photo.getBytes(1, (int)photo.length());

Докато преглеждате списъка с бобове в jsp, атрибутът src сочи към сървлет като този:

<img class="img" width="55" height="50" src="displayThumbnail?photoData=${part.photoData}">

който обслужва изображението, както е показано по-долу, но те не се показват, но при отстраняване на грешки масивът от байтове изглежда има данни.

protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws IOException {
    response.setContentType("image/jpeg");
    OutputStream o = response.getOutputStream();
    String photoDataStr = request.getParameter("photoData");
    byte[] photoData = null;
    if(photoDataStr != null) {
        photoData = photoDataStr.getBytes();
    }
    o.write(photoData);
    o.close();
}

Изображението обаче не се показва. Сега, ако направя заявка в базата данни за всяко отделно изображение, както е показано по-долу, изображенията се показват добре в този случай.

protected void processRequest(HttpServletRequest request, HttpServletResponse response) {
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    Connection conn = null;
            try {
        if(conn == null) {
            conn = open();
        }
        pstmt = conn.prepareStatement("select photo from PART_PHOTOS where id = ?");
        String id = request.getParameter("id");
        pstmt.setString(1, id);
        rs = pstmt.executeQuery();
        if (rs.next()) {
            Blob b = rs.getBlob("photo");
            response.setContentType("image/jpeg");
            response.setContentLength((int) b.length());
            InputStream is = b.getBinaryStream();
            OutputStream os = response.getOutputStream();
            byte buf[] = new byte[(int) b.length()];
            is.read(buf);
            os.write(buf);
            os.close();
            is.close();
        }
    } catch (Exception ex) {
        System.out.println(ex.getMessage());
        ex.printStackTrace();
    } finally {
         if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            rs = null;
        }
        if (pstmt != null) {
            try {
                pstmt.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            pstmt = null;
        }
        //check if it's the end of the loop
            if (conn != null) {
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                    conn = null;
                }
    }
}

Ще съм много благодарен, ако някой може да даде препоръки около същото.


person John C    schedule 22.04.2011    source източник


Отговори (3)


Вие предполагате, че можете да поставите произволни двоични данни в HTML файл и той ще бъде анализиран правилно и изпратен обратно на вашия сървър непокътнат. Това е лошо предположение! Ако не друго, байтът, който съответства на ASCII за символа за кавичка, ще създаде проблеми, нали? Да не говорим за проблемите с кодирането и факта, че параметрите на URL трябва да бъдат urlencoded. Това просто е обречено на провал.

За да направите това да работи, ще трябва да имате някакъв вид изрично кодиране на текст на двоичните данни, когато обслужвате страницата (base64, може би), и след това да декодирате параметъра на сървлета обратно към данните за двоично изображение, след като URL адресът бъде публикуван обратно.

person Ernest Friedman-Hill    schedule 22.04.2011
comment
@BaluC : Има ли някакъв бърз изход от това, без да отделяте твърде много време за настройка на кеша и т.н. - person John C; 22.04.2011
comment
@BalusC: както сега трябва да можете да видите от някои други коментари, оставени от OP, той наистина се опитваше да залепи данните за изображението директно в HTML: цитат, ${part.photoData} връща байтовия масив, който се извлича от първоначалното извикване на базата данни. След това той очаква неговият сървлет да може да извлече този масив от байтове от мястото, където го е вградил като URL в етикета ‹img›, и да го върне директно обратно на заявителя. Мислех, че съм доста ясен в обяснението си, но изглежда никой от другите отговори не е оценил какво се случва. - person Ernest Friedman-Hill; 22.04.2011
comment
О, той се опита да предаде цялото изображение като параметър! Съжалявам, сега го виждам. Тълкувах го като идентификатор на изображение. Взимам си думите назад. - person BalusC; 22.04.2011

Първият ви фрагмент processRequest() изпраща обратно само байтовото представяне на параметъра на заявката за photoData, а не данните за снимката, идентифицирани от параметъра. Изглежда, че има грешка в кода ви.

Изглежда, че се опитвате да разрешите проблема си по грешен начин. Когато за първи път създадете HTML таблицата, съхраняването на изображението във вашия "bean" от първата ви заявка не ви дава нищо, освен ако не кеширате данните, а последващата заявка за displayThumbnail извлича изображението от кеша, избягвайки заявката към базата данни.

Ако не искате да се забърквате с кеширането, тогава няма нужда да съхранявате изображението във вашия първоначален bean, тъй като той не ви дава нищо, и просто направете нещо като вашия втори фрагмент processRequest(), за да извлечете изображението директно, когато браузърът поиска то.

person ewh    schedule 22.04.2011

Вашият ${part.photoData} израз трябва да върне някакъв идентификатор. В метода processRequest() трябва да получите тази стойност на ID (като използвате request.getParameter("photoData")) и чрез тази стойност да извлечете изображение от базата данни (или по-добре от кеша или от файловата система) и да изпратите двоичните данни към уеб клиента .

person user179437    schedule 22.04.2011
comment
${part.photoData} връща масива от байтове, който е извлечен от първоначалното извикване на базата данни. Не искам да правя отделни извиквания към база данни за извличане на изображения. - person John C; 22.04.2011
comment
не можете да поставите байтов масив в src атрибут на img таг, няма да работи. И ако не искате да се обадите на базата данни, можете да запазите map, който има ID като ключ и байтов масив като стойност. - person user179437; 22.04.2011