这里有一个很大的误解。JSF 基本上是一个 HTML 代码生成器。在 HTML 中,图像不会内联在 HTML 输出中。相反,它们应该由<img>
属性中具有(相对)URL 的元素表示src
,浏览器在解析获得的 HTML 输出期间必须单独下载该属性。查看生成的 HTML 输出,JSF<h:graphicImage>
组件生成一个 HTML<img>
元素,该元素必须具有src
指向有效 URL 的属性。
必须代表一个有效的<h:graphicImage value>
URL。但是,如果您将图像存储在数据库中而不是公共网络内容中,那么您基本上应该创建一个独立的servlet,它根据一些唯一的请求参数或 URL 路径从数据库中读取单个图像并将其写入响应正文.
因此,假设您从现在开始按如下方式呈现图像 URL,
<h:graphicImage value="/userProfileImageServlet?id=#{userProfile.id}" />
那么 servlet 的以下启动示例(省略 nullchecks 等琐碎的检查)应该做:
@WebServlet("/userProfileImageServlet")
public class UserProfileImageServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
Long userProfileId = Long.valueOf(request.getParameter("id"));
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT image, imageFileName, LENGTH(image) AS imageContentLength FROM userProfile WHERE id=?");
) {
statement.setLong(1, userProfileId);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
response.setContentType(getServletContext().getMimeType(resultSet.getString("imageFileName")));
response.setContentLength(resultSet.getInt("imageContentLength"));
response.setHeader("Content-Disposition", "inline;filename=\"" + resultSet.getString("imageFileName") + "\"");
try (
ReadableByteChannel input = Channels.newChannel(resultSet.getBinaryStream("image"));
WritableByteChannel output = Channels.newChannel(externalContext.getResponseOutputStream());
) {
for (ByteBuffer buffer = ByteBuffer.allocateDirect(10240); input.read(buffer) != -1; buffer.clear()) {
output.write((ByteBuffer) buffer.flip());
}
}
}
} else {
response.sendError(HttpServletResponse.SC_NOT_FOUND);
}
} catch (SQLException e) {
throw new ServletException("Something failed at SQL/DB level.", e);
}
}
}
如果您碰巧在 JSF 2.2 + CDI 环境中使用 JSF 实用程序库OmniFaces,那么您可以改用它<o:graphicImage>
,它可以更直观地使用。
<o:graphicImage value="#{userProfileImageBean.getBytes(userProfile.id)}" />
@Named
@ApplicationScoped
public class UserProfileImageBean {
public byte[] getBytes(Long userProfileId) {
try (
Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement("SELECT image FROM userProfile WHERE id=?");
) {
statement.setLong(1, userProfileId);
try (ResultSet resultSet = statement.executeQuery()) {
if (resultSet.next()) {
return resultSet.getBytes("image");
}
} else {
return null;
}
} catch (SQLException e) {
throw new FacesException("Something failed at SQL/DB level.", e);
}
}
}
它还通过设置透明地支持日期 URI 方案dataURI="true"
:
<o:graphicImage value="#{userProfileImageBean.getBytes(userProfile.id)}" dataURI="true" />
也可以看看: