为什么graphicalImage中的图像无法完全加载(PrimeFaces移动版)? [英] Why does an image in graphicImage not load fully (PrimeFaces mobile)?

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

问题描述

我有一个应用程序,该应用程序使用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));
        }
    }

    [...]
}

如何解决此错误?

更新1(2014年11月3日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方法更改为

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. 检索图像时
  3. 将图像保存在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() 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的

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

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

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