【问题标题】:Display images on a JSP page through a servlet通过 servlet 在 JSP 页面上显示图像
【发布时间】:2014-12-11 13:18:55
【问题描述】:

我正在尝试使用 Jstl 在 Jsp 页面中显示图像,并且图像路径由 servlet 传递。 Jsp页面实际上只显示了一张检索到的图片,并抛出了NullPointerException。

Jsp 看起来像这样:

<c:forEach items="${images}" var="img">
    <div class="col-md-3">
        <img src="displayImg?imageId=${img.imageId}">
    </div>
</c:forEach>

servlet doGet 方法如下所示:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    int imageId = Integer.parseInt(request.getParameter("imageId"));
    Image img = imageDao.getImageById(imageId);
    response.setContentType("image/" + img.getImageType());

    File f = new File(img.getImagePath());
    BufferedImage bi = ImageIO.read(f);
    OutputStream out = response.getOutputStream();
    ImageIO.write(bi, img.getImageType(), out);
    out.close();
}

我不明白为什么当请求参数正确时,这个 servlet 设法提供一个图像而在其他图像上失败并出现 NullPointerException。我的印象是这是一个并发问题,因为 Jsp 显示任意图像。

有什么帮助吗?

这是 DAO:

public Image getImageById(int imageId) {
        String query = "SELECT * FROM images WHERE imageId=?";
        Image img = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            connection = ConnectionManager.getConnection();
            ps = connection.prepareStatement(query);
            ps.setInt(1, imageId);
            rs = ps.executeQuery();
            if (rs.next()) {
                img = new Image();
                img.setImageId(rs.getInt("imageId")); //NPE thrown here
                img.setImagePath(rs.getString("imagePath"));
                img.setImageType(rs.getString("imageType"));
                ...
                img.setDescription(rs.getString("description"));
                img.setCreatedOn(rs.getTimestamp("createdOn"));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally {
            close(rs);
            close(ps);
            close(connection); //Removed this and problem disappears
        }
        return img;
    }

解决了!! 这很奇怪,但我只是避免关闭与数据库的连接,并且我的所有图像都正确显示,没有错误。我猜想在每次访问数据库后关闭连接是有问题的,因为它无法在您想要的确切时间关闭,但可能在另一个调用数据库的中间。现在我想知道,根本不关闭连接也是有问题的。遇到这种情况怎么办?

【问题讨论】:

  • 请跟踪堆栈。 ;-) 另外,是 JSP 还是图像 servlet 抛出了 NPE?
  • @haraldK at com.mysql.jdbc.ResultSetImpl.buildIndexMapping(ResultSetImpl.java:674) at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1029) at com.mysql.jdbc .ResultSetImpl.getInt(ResultSetImpl.java:2566) 在 be.kayiranga.daoImpl.ImageDaoImpl.getImageById(ImageDaoImpl.java:114) 在 be.kayiranga.controller.ImageDisplayer.doGet(ImageDisplayer.java:32) 在 javax.servlet。 http.HttpServlet.service(HttpServlet.java:618) at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
  • @haraldK NPE 来自 DAO。 Jsp 和 Servlet 似乎都很好。但是,我仍然怀疑问题在于如何以及何时完成对业务代码的调用。
  • 专业提示:不要回答 cmets 询问详情。而是更新问题。这将有助于新读者理解您的问题。 :-) 另外,我认为您还没有发布相关代码。最有可能的是,它存在于您的 DAO 中。
  • @haraldK 照你说的做了!!!

标签: java jsp servlets


【解决方案1】:

奇怪的是imageId在查询中被用作列名,并且有一条记录,rs.next()。 也许它不是 int 而是 long 或 SQL VARCHAR。 也许 MySQL 过于聪明地忽略了 imageId,因为这是在 WHERE 中指定的? 或者在这种情况下你需要使用rs.getInt("images.imageId")

            img.setImageId(rs.getInt("imageId")); //NPE thrown here

但是可以写(绕过)为

            img.setImageId(mageId);

我会检查是否有错误的错字:í(口音)、西里尔字母 e(如果您是东欧人)或制表符。老实说,您的代码看起来很整洁,但在不太整洁的代码中也会出现类似的错误:ps、ps2、rs、rs2 作为字段,对并发使用造成严重破坏并且容易出现拼写错误。

BTW 写入可以用更少的内存资源更快地完成:

Path path = Paths.get(img.getImagePath());
OutputStream out = response.getOutputStream();
Files.copy(path, out);

关于搜索错误:

调查错误似乎是唯一的选择:

ResultSetMetaData meta = rs.getMetaData();
int numberOfColumns = meta.getColumnCount();
for (int i = 1; i <= numberOfColumns; ++i) {
    log(... i, meta.getColumnName(i), meta.getColumnLabel(i) ...);
}

【讨论】:

  • 如果我写 img.setImageId(imageId) 就可以了,但是 NPE 会移动到下一行,就好像 ResultSet 不是 null 而是有一个空行一样。
  • imageId 肯定是一个 int。我正在使用本地 mysql 数据库。
  • 我在结果集结果上添加了代码。真的很奇怪。一定很简单。
  • 我用你的代码片段进行了调查,关于 rs 元数据一切都很好。不过这很奇怪,我要测试三张图像,每次我运行应用程序时 Jsp 都会显示一张或两张或所有图像,而且完全是任意的。当某些图像没有显示时,我当然会得到 NPE。
【解决方案2】:

只需阅读堆栈跟踪:

at com.mysql.jdbc.ResultSetImpl.buildIndexMapping(ResultSetImpl.java:674)
at com.mysql.jdbc.ResultSetImpl.findColumn(ResultSetImpl.java:1029) 
at com.mysql.jdbc.ResultSetImpl.getInt(ResultSetImpl.java:2566) 
at be.kayiranga.daoImpl.ImageDaoImpl.getImageById(ImageDaoImpl.java:114)

所以,异常是由

rs.getInt("imageId")

表示结果集中没有名为"imageId"的列。

你不应该使用select *。使用显式列名,并在从结果集中获取数据时使用这些显式列名:

select imageId, imagePath, imageType, description, createdOn from ...

【讨论】:

  • 如果该列不存在,我会在我有意打印的 stackTrace 中看到它。因此,该列就在那里,因为恰好成功检索并显示了一张图像,如果 DAO 存在任何问题,则不会发生这种情况。尝试删除 * 并将列名放入完全相同的结果。
【解决方案3】:

此答案可能无法完全帮助您,因为我相信没有人完全了解您在做什么。我假设您有一个 JSP 页面和一个内部表单,我可以向您展示如何将图像显示为字符串。

public showImage(){
  BASE64Encoder base64Encoder = new BASE64Encoder();
 // your method to retreive the image
 if(image == null){
   File imagePath = new File("/home/akshay/images.jpeg"); // display alternate image
      try {
          BufferedImage bufferedImage = ImageIO.read(imagePath);
          ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
         ImageIO.write(bufferedImage, "png", byteArrayOutputStream);
   //Below person is the main object model, and String is the image in string
        person.setProfilePhotoString("data:image/png;base64," +   base64Encoder.encode(byteArrayOutputStream.toByteArray()));
                } catch (IOException e) {
                    e.printStackTrace();
                }
  } else{
         person1.setProfilePhotoString("data:image/png;base64," +  base64Encoder.encode(person1.getProfilephoto()));
}
}

JSP 页面:

<form:form action="${showAction}" commandName="person">
    <table>
 <tr>
            <td><img src= "${person.profilePhotoString}"  height=100 width=100/>
        </tr>
</table>
</form>

【讨论】:

  • 我实际上将图像存储在我的服务器上,例如:C:\apache-tomcat-8.0.15\webapps\userdirs\rmedardo_xPn6HH。我只在数据库中存储路径其他详细信息,所以没有字节。
  • 好的,那你可以修改上面的代码并使用它......我相信它会工作的。只需将图像作为 byteArrayoutputstream 获取,然后对字符串使用 setter 方法。
猜你喜欢
  • 2023-03-23
  • 2011-07-27
  • 2012-09-29
  • 1970-01-01
  • 2019-09-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多