为什么graphicImage中的图像没有完全加载(PrimeFaces mobile)? [英] Why does an image in graphicImage not load fully (PrimeFaces mobile)?

查看:15
本文介绍了为什么graphicImage中的图像没有完全加载(PrimeFaces mobile)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个应用程序,它使用 PrimeFaces Mobile 来显示图像.

I have an application, which uses PrimeFaces Mobile to display images.

有时,但并非总是如此,图像未完全显示 - 仅显示顶部.

Sometimes, but not always, the image is not displayed fully - only the top part.

带有该图像的页面的 XHTML 代码如下所示:

The XHTML code of the page with that image looks like this:

<!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 具有以下代码:

And the main bean has following code:

@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));
        }
    }

    [...]
}

我该如何解决这个错误?

How can I fix this error?

更新 1 (03.11.2014 23:21 MSK):

我已尝试通过以下方法修复错误:

I've tried following to fix the error:

1) 为该 Primefaces 页面的所有元素禁用缓存.

1) Disabling cache for all elements of that Primefaces page.

2) 通过将 maxExtensionSizemaxTrailerSize (server.xml) 设置为 -1 来禁用响应分块.

2) Disabling response chunking by setting maxExtensionSize and maxTrailerSize (server.xml) to -1.

3) 使用以下 doFilter 添加过滤器:

3) Adding a filter with following 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 方法更改为

4) Changing the currentImage method to

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),它显示了来自同一来源的图像.

But it still doesn't work. I wrote a piece of code in another web application and using different framework (Vaadin), which displays images from the same source.

我遇到了同样的错误(图像只显示了一部分).

I get the same error (images are displayed only partially).

由此我得出结论,错误一定发生

From this I conclude that the error must occur

  1. 从特定和/或检索图像时
  2. 当图像保存在 MongoDB 中时.

用于从 URL 检索图像的代码

如果在读取图像时出现错误,则发生在以下方法中:

If the error occurs during reading the image, it occurs in the following method:

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中保存图片的代码

如果是在数据库中保存图片的问题,出现在以下方法中:

If the problem is with saving images in the database, it occurs in the following method:

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() 方法有一个主要错误:

Your readImage() method has a major bug:

byte bytes[] = new byte[inputStream.available()];

InputStream#available() 并没有像你想象的那样做.它不返回总内容长度,这是代码的其余部分所期望的.它返回可用于读取的字节数,而不会阻塞所有其他线程(即当前已放入硬件缓冲区的字节).这完全解释了为什么您只能显示图像的 部分.

不必感到羞耻.几乎所有 Java 初学者都会犯同样的错误.完整读取 InputStream 的正确方法是调用 任何 read() method 直到它返回 -1 表示 EOF (文件结束).您可以在这个相关问题中找到一堆示例和实用程序库快捷方式:Convert InputStream到 Java 中的字节数组.

No need to be ashamed. Practically all Java starters make the same mistake. The right way to read an InputStream fully is to invoke any read() method on it as long as until it returns -1 indicating EOF (end of file). You can find a bunch of examples and utility library shortcuts in this related question: Convert InputStream to byte array in Java.

这是对 readImage() 方法做正确事情的完全重写,利用了您似乎已经拥有的 IOUtils(以及 Java 7 的 try-with-resources 和 AutoCloseable):

Here's a full rewrite of readImage() method doing the right thing, making use of IOUtils which you appear to already have at your hands (and Java 7's try-with-resources with 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;
    }
}

这篇关于为什么graphicImage中的图像没有完全加载(PrimeFaces mobile)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆