【问题标题】:BLOB images are displayed only on refreshing a page after an update via p:dataTable is made in PrimeFacesBLOB 图像仅在通过 p:dataTable 在 PrimeFaces 中进行更新后刷新页面时显示
【发布时间】:2014-07-19 18:05:03
【问题描述】:

我在<p:graphicImage> 上显示以 BLOB 形式存储在 MySQL 中的图像,如下所示。

<p:dataTable var="row" value="#{testManagedBean}" lazy="true" editable="true" rows="10">
    <p:column headerText="id">
        <h:outputText value="#{row.brandId}"/>
    </p:column>

    <p:column headerText="Image">
        <p:cellEditor>
            <f:facet name="output">
                <p:graphicImage value="#{brandBean.image}" height="100" width="100">
                    <f:param name="id" value="#{row.brandId}"/>
                </p:graphicImage>
            </f:facet>
            <f:facet name="input">
                <p:graphicImage id="image" value="#{brandBean.image}" height="100" width="100">
                    <f:param name="id" value="#{row.brandId}"/>
                </p:graphicImage>
            </f:facet>
        </p:cellEditor>
    </p:column>

    <p:column headerText="Edit" width="50">
        <p:rowEditor/>
    </p:column>
</p:dataTable>

编辑行时,&lt;p:fileUpload&gt; 会显示在 &lt;p:overlayPanel&gt; 上。为简单起见,本示例中省略了这一点和许多其他内容,因为它们与具体问题无关。

关联的 JSF 托管 bean:

@ManagedBean
@ViewScoped
public final class TestManagedBean extends LazyDataModel<Brand> implements Serializable
{
    @EJB
    private final TestBeanLocal service=null;
    private static final long serialVersionUID = 1L;

    @Override
    public List<Brand> load(int first, int pageSize, String sortField, SortOrder sortOrder, Map<String, Object> filters) {
        setRowCount(3);
        return service.getList();
    }
}

根据唯一行标识符 - BrandBean 从数据库中检索图像的 bean。

@ManagedBean
@ApplicationScoped
public final class BrandBean
{
    @EJB
    private final BrandBeanLocal service=null;
    public BrandBean() {}

    public StreamedContent getImage() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();

        if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) {
            return new DefaultStreamedContent();
        }
        else {
            String id = context.getExternalContext().getRequestParameterMap().get("id");
            System.out.println("id = "+id);
            byte[] bytes = service.findImageById(Long.parseLong(id));
            return bytes==null? new DefaultStreamedContent(new ByteArrayInputStream(new byte[0])):new DefaultStreamedContent(new ByteArrayInputStream(bytes));
        }
    }
}

当通过单击位于数据表最后一列中的勾号(由&lt;p:rowEditor&gt; 指示)来更新(在编辑之后)行时,将调用BrandBean 中的getImage() 方法,因为它应该.

这在使用 PrimeFaces 5.0 和 JSF 2.2.6 在 GlassFish server 4.0 上运行的应用程序中正确发生。

在数据表中(并因此在数据库中)更新一行后,新图像将立即显示在数据表中。


在 Tomcat 服务器 8.0.5 上使用 Spring 4.0.0 GA 运行另一个应用程序,其中 getImage() 方法没有被调用在更新数据表保存的行后导致仍然在数据表中显示旧图像(不是新更新的图像)(即使更改已正确传播到数据库)。

仅当按F5(在大多数浏览器上)刷新页面时,才会显示新更新的图像。它甚至不会在页面加载时显示(在地址栏中输入 URL,然后按 enter 键)。

换句话说,当通过单击&lt;p:rowEditor&gt; 指示的勾号来更新数据表中的行时,不会调用getImage() 方法(因此,不会从数据库中获取要显示的新图像&lt;p:graphicImage&gt;)。此方法仅在按 F5 快捷键刷新/重新加载页面时调用。


为什么会这样?如何在更新一行后立即显示新更新的图像?

从表面上看,这应该既与Spring无关,也与JPA无关(点击打勾后更新操作正确传播到数据库)。这应该与Tomcat服务器有关。

【问题讨论】:

  • 也许你应该在tomcat邮件列表中问这个

标签: jsf tomcat primefaces jsf-2.2 graphicimage


【解决方案1】:

新更新的图像仅在按 F5 刷新页面时显示(在大多数浏览器上)。它甚至不会在页面加载时显示(在地址栏中输入 URL,然后按 Enter 键)。

图片正在被网络浏览器缓存。资源通过响应标头中设置的缓存相关指令基于每个 URL 进行缓存。您的具体问题是因为资源 URL 仍然相同并且网络浏览器不知道资源在服务器端发生了变化。 OmniFaces CacheControlFilter showcase page 详细解释了缓存(注意:过滤器不是解决这个问题的方法)。

您基本上需要通过更改 URL 来强制网络浏览器重新请求资源。对于这种情况,一种最常见的方法是在 URL 的查询字符串中附加图像的“最后修改”时间戳,即突然更改可缓存资源并且需要立即将其更改反映给所有客户端。鉴于您使用的是 JPA,所以应该这样做:

  • 在brand 表中添加lastModified 列:

    ALTER TABLE brand ADD COLUMN lastModified TIMESTAMP DEFAULT now();
    
  • 使用适当的属性和设置它的@PreUpdate 扩展Brand 实体:

    @Column @Temporal(TemporalType.TIMESTAMP)
    private Date lastModified;
    
    @PreUpdate
    public void onUpdate() {
        lastModified = new Date();
    }
    
    // +getter+setter
    

    (在每个 UPDATE 查询之前,JPA 都会调用 @PreUpdate 注释方法)

  • 将其附加到图像URL(参数名称v是“版本”的提示):

    <p:graphicImage value="#{brandBean.image}" ...>
        <f:param name="id" value="#{row.brandId}" />
        <f:param name="v" value="#{row.lastModified.time}" />
    </p:graphicImage>
    

    (为了清楚起见,我在这里将 row 重命名为 brand,将 brandId 重命名为 id 以进行重复数据删除)

  • 最后,如果您使用的是 PrimeFaces 5.0 或更新版本,那么您还需要禁用服务器端缓存:

    <p:graphicImage value="#{brandBean.image}" cache="false" ...>
    

设计注意事项:如果图像不一定在每次更新Brand 时更新,则将其拆分到另一个表Image 并让Brand 有一个FK(@ManyToOne 或@OneToOne)到@ 987654344@。这也使得属性“图像”可以在 web 应用程序中的各种实体中重复使用。

【讨论】:

    【解决方案2】:

    你,

    我有同样的问题,但我的图像 src 在硬盘中而不是在数据库中。 当我使用随机数但我没有阅读它时,我遇到了问题。 一般来说,当这个参数是一个随机数时,我会在 src 图像中添加一个参数。

    我的解决方案是这样的:

    public class UserPage {
      private String fotoCVPath;
      //all variabile
        private String getRandomImageName() {
            int i = (int) (Math.random() * 10000000);
    
            return String.valueOf(i);
        }
     public void editImage() {
    //init the fotoCVPath
    fotoCVPath = fotoCVPath + "?tmpVal=" + getRandomImageName();
    }
      /**
         * @return the fotoCVPath <br>
         * 
         * @author  - asghaier <br>
         * 
         *         Created on 29/mag/2014
         */
        public String getFotoCVPath() {
    
            return fotoCVPath;
        }
    
        /**
         * @param fotoCVPath the fotoCVPath to set <br>
         * 
         * @author- asghaier <br>
         * 
         *         Created on 29/mag/2014
         */
        public void setFotoCVPath(String fotoCVPath) {
            this.fotoCVPath = fotoCVPath;
        }
    }
    

    在你我的页面中,我有这样的元素 graphicsImage:

    <h:panelGrid ...al param >
        <h:column>
           <p:graphicImage id="imgCV" value="#{userPage.fotoCVPath}" styleClass="imgCVStyle" />
        </h:column>
    </h:panelGrid>
    

    当我喜欢重新加载图像时,更新组件 panelGrid。

    对于我的例子,我使用了

    <p:ajax event="click" onstart="PF('uploadImgCV').show();" update ="idPanelGrid"/>
    

    在

    我希望这个模式可以帮助你解决你的问题

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-09-06
      • 2023-03-11
      • 2018-04-26
      相关资源
      最近更新 更多