向大家致意,
我正在使用primefaces 4和Tomcat 7.我希望用户能够上传多个图像,并在将这些图像写入磁盘之前立即查看每个上传的图像(当它们在内存中时)。图像将仅在表单提交后写入磁盘。我正在使用p:fileUpload组件。
以下是相关代码:
...
<p:tab id="imageTab" title="#{msgs.images}">
<p:dataGrid id="imagesDataGrid" columns="4" value="#{modifyProductAdminBean.imageIds}"
var="imgId" >
<p:graphicImage value="#{pA_ImageService.image}" >
<f:param name="id" value="#{imgId}" />
</p:graphicImage>
</p:dataGrid>
<p:fileUpload fileUploadListener="#{modifyProductAdminBean.handleFileUpload}" mode="advanced"
dragDropSupport="true" multiple="true" sizeLimit="5242880"
invalidFileMessage="#{msgs.invalidFileType}"
invalidSizeMessage="#{msgs.fileTooLarge}"
allowTypes="/(\.|\/)(gif|jpe?g|png|jpg)$/"
cancelLabel="#{msgs.cancel}"
uploadLabel="#{msgs.upload}"
label="#{msgs.choose}"
update="imagesDataGrid" />
</p:tab>
...
@ManagedBean
@ViewScoped
public class ModifyProductAdminBean implements Serializable {
private Map<String, UploadedFile> uploadedImages;
public void handleFileUpload(FileUploadEvent event) {
UploadedFile file = event.getFile();
String uniqueId = UUID.randomUUID().toString();
this.getUploadedImages().put(uniqueId, file);
}
public Set<String> getImageIds() {
return this.getUploadedImages().keySet();
}
public Map<String, UploadedFile> getUploadedImages() {
return uploadedImages;
}
...
}
@ManagedBean
@ApplicationScoped
public class PA_ImageService implements Serializable {
private final ModifyProductAdminBean modifyProductAdminBean;
public PA_ImageService() {
this.modifyProductAdminBean = BeanManager.findBean("modifyProductAdminBean");
}
// Taken from http://stackoverflow.com/questions/8207325/display-image-from-database-with-pgraphicimage
public StreamedContent getImage() {
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the HTML. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
} else {
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
String imageId = context.getExternalContext().getRequestParameterMap().get("id");
// remove [, ] characters between
imageId = imageId.substring(1, imageId.length() - 1);
UploadedFile uFile = this.modifyProductAdminBean.getUploadedImages().get(imageId);
return new DefaultStreamedContent(new ByteArrayInputStream(uFile.getContents()));
}
}
...
}
public class BeanManager implements Serializable {
@SuppressWarnings("unchecked")
public static <T> T findBean(String beanName) {
FacesContext context = FacesContext.getCurrentInstance();
return (T) context.getApplication().evaluateExpressionGet(context, "#{" + beanName + "}", Object.class);
}
...
}
当我运行此代码时,我在“PA_ImageService”的最后一行得到一个NullPointerException(返回new ...)。更确切地说,虽然uFile不为null,但“uFile.getContents()”返回null。为什么?我做错了什么?
我观察到的更多细节:
我注意到当我上传文件时,Tomcat会暂时将其存储在E:\Program Files (x86)\Apache Software Foundation\Apache Tomcat 7.0.41\work\Catalina\localhost\MyProject
文件的.tmp
目录中。
通过调试项目,我可以看到:当我到达if (context... == PhaseId.RENDER_RESPONSE)
的{{1}}行时,.tmp文件仍然存在。但是,在PA_ImageService
方法的第二次访问中,当控件移动到getImage()
块时,我可以看到tmp文件不再存在。因此,无法检索其内容,因此无法检索else
结果。
有关这种情况如何发生的任何想法?
答案 0 :(得分:1)
您需要将图像存储在(临时)磁盘/数据库位置,而不是视图范围bean的属性。您可以将其存储为会话范围bean的属性,但我不建议在HTTP会话中携带占用内存的字节,这在需要序列化时会受到影响,例如服务器集群。
您可以轻松使用File#renameTo()
从临时位置移动到固定位置。您可以轻松运行会话侦听器来获取/清除任何与用户相关的临时文件。
答案 1 :(得分:0)
这里最明显的问题是你试图从@ViewScoped
bean中访问@ApplicationScoped
bean;这在JSF中是非法的。
您只能注射范围比注射目标范围更广的豆类。这意味着您可以按以下范围的顺序注入bean:
ApplicationScope &gt;&gt; SessionScope &gt;&gt; ViewScope &gt;&gt; RequestScope
话虽如此,虽然我无法看到您如何将ModifyProductAdminBean
注入PA_ImageService
(没有注释或 faces-config.xml 可见),但它是安全的说以下行不应该起作用
UploadedFile uFile = this.modifyProductAdminBean.getUploadedImages().get(imageId);