繁体   English   中英

为什么graphicImage中的图像无法完全加载(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)通过将maxExtensionSizemaxTrailerSizeserver.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)编写了一段代码,该框架显示来自同一源的图像。

我收到相同的错误(图像仅部分显示)。

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

  1. 从特定的和/或
  2. 将图像保存在MongoDB中时。

用于从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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM