Error in streaming dynamic resource. null

丶灬走出姿态 提交于 2019-12-03 07:39:53

This is a bug (at least, a functional/technical design mistake) in PrimeResourceHandler. It shouldn't have assumed the dynamic resource or its content to be never null. It should have conditionally checked if that was the case and then simply have returned a HTTP 404 "Not Found" response.

In other words, instead of

85    streamedContent = (StreamedContent) ve.getValue(eLContext);
86 
87    externalContext.setResponseStatus(200);
88    externalContext.setResponseContentType(streamedContent.getContentType());

they should have done

85    streamedContent = (StreamedContent) ve.getValue(eLContext);
86 
87    if (streamedContent == null || streamedContent.getStream() == null) {
88        externalContext.responseSendError(HttpServletResponse.SC_NOT_FOUND, ((HttpServletRequest) externalContext.getRequest()).getRequestURI());
89        return;
90    }
91
92    externalContext.setResponseStatus(200);
93    externalContext.setResponseContentType(streamedContent.getContentType());

This way you can just return null or an empty StreamedContent from the getImage() method in order to generate a decent 404.

Well, what can you do?

  1. Report it to them and hope that they'll fix it. Update They fixed it in version 5.2.

  2. And/or, put a copy of PrimeResourceHandler class in the Java source folder of your webapp project, in exactly its own org.primefaces.application package and then just edit it to include the mentioned change and finally just build/deploy your webapp project as WAR as usual. Classes in /WEB-INF/classes have higher classloading precedence over those in JARs in /WEB-INF/lib, so the modified one will be used instead.

srbs

I would suggest to include an attribute in the object the <p:dataTable> is iterating on to signify if an image exists. That way, there are no unnecessary (or null return) calls to BannerBean.getImage().

Example:

<p:column headerText="Header">
    <p:graphicImage value="#{bannerBean.image}" height="200" width="200"
            rendered="#{row.hasImage}">
        <f:param name="id" value="#{row.bannerId}"/>
    </p:graphicImage>
<p:column>

Another option is to grab the Primefaces source code, edit PrimeResourceHandler.java, and build it. (see the wiki)


An alternative solution would be to setup your own Serlvet to provide the images.

  • Main benefit is that browsers can cache the image (you can specify cache timeout if wanted).
  • Be aware of SQL Injection & other security attacks.
  • Attach some sort of login/permission check for additional security. (if needed)

Example:

<p:column headerText="Header">
    <p:graphicImage value="#{request.contextPath}/images/banner/?id=#{row.bannerId}"
            height="200" width="200" />
<p:column>
@WebServlet(name = "Retrieve Banner Images", urlPatterns = "/images/banner/*")
public class BannerImageServlet extends HttpServlet
{
    @EJB
    private final BannerBeanLocal service;

    protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
        String[] ids = req.getParameterValues("id");
        if(ids != null && ids.length == 1) {
            byte[] bytes = service.findImageById(Long.parseLong(ids[0]));
            if(bytes != null) {
                // see link #3 below
            }
        }
    }
}

Sources / useful links:

  1. #{request.contextPath}
  2. @WebServlet tutorial
  3. how to send byte stream back to the client
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!