Изображение не обслуживается внутри jsp из сервлетов

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

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

При циклическом просмотре списка bean-компонентов в 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-адреса должны быть закодированы. Это просто обречено на провал.

Чтобы это работало, вам нужно иметь какую-то явную текстовую кодировку двоичных данных при обслуживании страницы (возможно, 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, сохранение изображения в вашем «бине» из вашего первого запроса ничего не дает вам, если вы не кешируете данные, а последующий запрос displayThumbnail извлекает изображение из кеша, избегая запроса к базе данных.

Если вы не хотите возиться с кешированием, тогда нет необходимости хранить изображение в исходном bean-компоненте, поскольку оно ничего вам не дает, и просто сделайте что-то вроде второго фрагмента processRequest(), чтобы получить изображение напрямую, когда браузер запрашивает Это.

person ewh    schedule 22.04.2011

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

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