![](/img/trans.png)
[英]How to load an image from a directory using graphicImage in Primefaces?
[英]Why does an image in graphicImage not load fully (PrimeFaces mobile)?
我有一个使用PrimeFaces Mobile显示图像的应用程序。
有时但并非总是如此,图像无法完全显示-仅顶部显示。
具有该图像的页面的XHTML代码如下所示:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
xmlns:h="http://java.sun.com/jsf/html"
xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui"
xmlns:pm="http://primefaces.org/mobile">
<f:view renderKitId="PRIMEFACES_MOBILE"/>
<h:head>
</h:head>
<f:event listener="#{main.loadFirstImage}" type="preRenderView" />
<h:body id="body">
<pm:page id="page">
<pm:header title="myapp">
</pm:header>
<pm:content id="content">
<h:form>
<p:graphicImage id="image" rendered="false" value="#{main.currentImage()}"
cache="false">
</p:graphicImage>
[...]
</h:form>
</pm:content>
<pm:footer title="m.myapp.com"></pm:footer>
</pm:page>
</h:body>
</html>
并且main
bean具有以下代码:
@ManagedBean(name = "main")
@SessionScoped
public class MainView {
private byte[] currentImageData;
private byte[] productId;
private byte[] imageId;
public void loadFirstImage()
{
// This method initializes currentImageData
fetchNextImage();
}
[...]
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
return new DefaultStreamedContent();
}
else {
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData));
}
}
[...]
}
如何解决此错误?
更新1(03.11.2014 23:21 MSK):
我已经尝试按照以下方法修复错误:
1)为该Primefaces页面的所有元素禁用缓存。
2)通过将maxExtensionSize
和maxTrailerSize
( server.xml
)设置为-1
来禁用响应分块。
3)使用以下doFilter
添加过滤doFilter
:
@Override
public void doFilter(final ServletRequest aServletRequest,
final ServletResponse aServletResponse,
final FilterChain aFilterChain) throws IOException, ServletException {
System.out.println("aServletRequest instanceof HttpServletRequest: " +
(aServletRequest instanceof HttpServletRequest));
if (aServletRequest instanceof HttpServletRequest)
{
final HttpServletRequest request = (HttpServletRequest) aServletRequest;
final String requestURI = request.getRequestURI().toLowerCase();
if (!requestURI.endsWith("/javax.faces.resource/dynamiccontent.properties"))
{
aFilterChain.doFilter(aServletRequest, aServletResponse);
}
}
}
4)将currentImage
方法更改为
public StreamedContent currentImage()
{
FacesContext context = FacesContext.getCurrentInstance();
if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
// So, we're rendering the view. Return a stub StreamedContent so that it will generate right URL.
return new DefaultStreamedContent();
}
else {
String mimeType = null;
if (imageFileName.toLowerCase().endsWith(".png"))
{
mimeType = "image/png";
}
else if (imageFileName.toLowerCase().endsWith(".jpeg") || imageFileName.toLowerCase().endsWith(".jpg"))
{
mimeType = "image/jpeg";
}
// So, browser is requesting the image. Return a real StreamedContent with the image bytes.
return new DefaultStreamedContent(new ByteArrayInputStream(currentImageData), mimeType);
}
}
但这仍然行不通。 我在另一个Web应用程序中使用了不同的框架(Vaadin)编写了一段代码,该框架显示来自同一源的图像。
我收到相同的错误(图像仅部分显示)。
由此我得出结论,错误必定会发生
用于从URL检索图像的代码
如果在读取图像期间发生错误,则按以下方法发生:
protected Binary readImage(final String viewItemURL) {
InputStream inputStream = null;
Binary image = null;
try
{
inputStream = new URL(viewItemURL).openStream();;
byte bytes[] = new byte[inputStream.available()];
inputStream.read(bytes);
image = new Binary(bytes);
}
catch (final IOException exception)
{
LOGGER.error("", exception);
}
finally
{
IOUtils.closeQuietly(inputStream);
}
return image;
}
viewItemURL
是图像的URL。
在MongoDB中保存图像的代码
如果问题在于将图像保存在数据库中,则将通过以下方法发生:
protected void saveProductImages(final byte[] aNewProductId, final List<String> aPictureUrls,
final IMongoPersistenceState aPersistenceState) {
final DB db = aPersistenceState.getDb();
final DBCollection productImagesColl = db.getCollection(
MyAppPersistenceAction.COLLECTION_USER_PRODUCT_IMAGES);
for (final String curPictureUrl : aPictureUrls)
{
final Binary imageData = readImage(curPictureUrl);
final Map<String,Object> map = new HashMap<String, Object>();
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_CREATOR_EMAIL, CREATOR_EMAIL);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_PRODUCT_ID, aNewProductId);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_DATA, imageData);
final String fileName = extractFileName(curPictureUrl);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_FILE_NAME, fileName);
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_MIME_TYPE, getMimeType(fileName));
map.put(FIELD_COLLECTION_USER_PRODUCT_IMAGES_IS_DELETED, Boolean.FALSE);
productImagesColl.insert(WriteConcern.SAFE, createRecordObject(map));
}
}
您的readImage()
方法有一个主要错误:
byte bytes[] = new byte[inputStream.available()];
InputStream#available()
不会执行您认为的操作。 它不会返回总的内容长度,这是其余代码所期望的。 它返回可读取的字节数,而不会阻塞所有其他线程(即,当前已放入硬件缓冲区的字节)。 这完全解释了为什么只显示图像的那一部分。
无需羞愧。 实际上,所有Java入门者都会犯同样的错误 。 完全读取InputStream
的正确方法是,对其调用任何 read()
方法 ,直到返回-1
表示EOF(文件末尾)为止。 您可以在以下相关问题中找到大量示例和实用程序库快捷方式: 将InputStream转换为Java中的字节数组 。
下面是一个完整的重写readImage()
方法做正确的事,利用IOUtils
,你似乎已经在你的手(和Java 7的尝试-以资源与AutoCloseable
):
protected Binary readImage(final String viewItemURL) {
try (InputStream inputStream = new URL(viewItemURL).openStream()) {
return new Binary(IOUtils.toByteArray(inputStream));
}
catch (final IOException exception) {
LOGGER.error("", exception);
return null;
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.