首页 > 解决方案 > o:graphicImage 缓存可能吗?

问题描述

在我的顶部栏中,我有一个<o:graphicImage>要显示我的用户的图片。

<o:graphicImage dataURI="true" height="32" width="32" styleClass="img-circle"
    value="#{employeeProfileMenuPictureRequestController.getPicture_32_32(loginBean.currentEmployee)}" 
    lastModified="#{employeeProfileMenuPictureRequestController.lastUpdate}" />

我的后端 bean 如下:

@GraphicImageBean
public class EmployeeProfileMenuPictureRequestController implements Serializable {

    private Date lastUpdate = new Date();

    public byte[] getPicture_32_32(Employee employee) throws StorageAttachmentNotFoundException, IOException {
        try {

            String path = employeeProfilePictureService.findProfileImageByEmployee(employee, FileSizeType.SIZE_32_32.toString());

            if (employee == null || path == null || path.isEmpty()) {
                return Utils.toByteArray(Faces.getResourceAsStream("/resources/images/no-photo-icon.png"));
            }

            Path fileLocation = Paths.get(path);
            byte[] data = Files.readAllBytes(fileLocation);
            LOGGER.info("END getPicture_32_32");
            return data;
        catch (Exception e) {
            LOGGER.error(ExceptionUtils.getFullStackTrace(e));
        }

        return Utils.toByteArray(Faces.getResourceAsStream("/resources/images/no-photo-icon.png"));
    }

    public Date getLastUpdate() {
        return lastUpdate;
    }
}

不幸的getPicture_32_32(Employee)是,每个页面请求/页面导航都会调用。这意味着它也是每次对数据库的请求,这需要时间。

我已经尝试添加lastModified<o:graphicImage>,但每次页面请求时也会调用该函数。

有人可以帮我解决这个问题吗?

标签: jsfcachingomnifacesgraphicimage

解决方案


根据<o:graphicImage>文档:

数据 URI

[...]

但是,不建议将这种方法用于“永久”和/或“大”图像,因为它没有为浏览器提供任何缓存图像以供重复使用的机会,~10KB 通常是最大值甚至更少,所以如果有更多这样的图像在同一页上。

因此,它根本不支持缓存。技术原因是它基本上将图像的全部内容嵌入到 HTML 输出中。它不会在图像中嵌入 URL。基本lastModified无视。我可能应该更好地记录这一点。至少,您应该绝对删除该dataURI属性。它仅对上传图像的预览有用。

和,

图像流

[...]

如果属性是带参数的方法表达式,则每个参数都将转换为字符串 HTTP 请求参数,并使用类注册的转换器转换回实际对象,这些转换器可通过Application.createConverter(Class). 因此,大多数标准类型Long已经被隐式支持。如果您出于某种原因需要提供自定义对象作为参数,则需要通过@FacesConverter(forClass).

所以,因为你的方法有一个Employee参数,所以你基本上需要有一个@FacesConverter(forClass=Employee.class),以便 JSF 可以自动将它从和转换为String. 如何创建转换器可以在这里找到:“null Converter”的转换错误设置值 - 为什么我需要 JSF 中的转换器?

你应该得到这样的结果:

@FacesConverter(forClass=Employee.class)
public class EmployeeConverter implements Converter {

    @Override
    public String getAsString(FacesContext context, UIComponent component, Object modelValue) {
        // Write code here which converts Employee to its unique String representation.
    }

    @Override
    public Object getAsObject(FacesContext context, UIComponent component, String submittedValue) {
        // Write code here which coverts the Employee unique String representation
        // as created in above method back to the original Employee object.
    }

}

另一种方法是调整您的getPicture_32_32()方法以将员工 ID 作为例如Long而不是员工。那么你就不需要自定义转换器了。JSF 已经为Long.

public byte[] getPicture_32_32(Long employeeId) {
    // ...
}
<o:graphicImage
    value="#{employeeProfileMenuPictureRequestController.getPicture_32_32(loginBean.currentEmployee.id)}" />

回到缓存,文档说:

缓存

[...]

如果未指定,则将使用在 Mojarra 特定上下文参数com.sun.faces.defaultResourceMaxAge或 MyFaces 特定上下文参数中设置的“默认资源最大年龄” org.apache.myfaces.RESOURCE_MAX_TIME_EXPIRES否则将假定默认值为 1 周

因此,当您没有资源年龄设置时,默认情况下它已经缓存了 1 周。因此,这lastModified是可选的,并且仅当您在实际更改图像时实际跟踪同一数据库或文件系统中的时间戳时才有用。然后,您应该真正使用它来获得最佳缓存。“随机”日期绝对不是正确的方法。


推荐阅读