Tin*_*iny 7 jsf tomcat primefaces graphicimage jsf-2.2
我在MySQL上显示以BLOB形式存储的图像<p:graphicImage>
,如下所示.
<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>
Run Code Online (Sandbox Code Playgroud)
编辑行时,<p:fileUpload>
会显示a <p:overlayPanel>
.为简单起见,在这个例子中省略了这个和许多其他的东西,因为它们与具体问题无关.
关联的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();
}
}
Run Code Online (Sandbox Code Playgroud)
根据唯一行标识符从数据库中检索图像的bean - BrandBean
.
@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));
}
}
}
Run Code Online (Sandbox Code Playgroud)
通过单击<p:rowEditor>
数据表的最后一列中的定位(由...指示)更新行(在编辑之后),将调用该行中的getImage()
方法BrandBean
.
这在使用PrimeFaces 5.0和JSF 2.2.6在GlassFish Server 4.0上运行的应用程序中正确发生.
在数据表中更新行(并因此在数据库中)后,将立即在数据表中显示新图像.
使用Spring 4.0.0 GA在Tomcat服务器8.0.5上运行另一个应用程序,其中在getImage()
更新数据表保持的行之后不调用该方法,导致仍然显示旧映像(而不是新更新的映像).数据表(即使更改已正确传播到数据库).
仅当按下F5(在大多数浏览器上)刷新页面时,才会显示新更新的图像.它甚至不会在页面加载时显示(在地址栏中输入URL然后enter按键).
换句话说,当通过单击指示的刻度来更新数据表中的行时,不调用<p:rowEditor>
该getImage()
方法(因此,不从数据库中提取新图像以显示在其上<p:graphicImage>
).仅当通过F5按快捷键刷新/重新加载页面时才调用此方法.
为什么会这样?如何在更新行后立即显示新更新的图像?
从表面上看,这既不应该与Spring也不应该与JPA相关(点击勾选后更新操作会正确地传播到数据库).这应该与Tomcat服务器相关.
仅当按 F5(在大多数浏览器上)刷新页面时才会显示新更新的图像。它甚至不会在页面加载时显示(在地址栏中输入 URL,然后按 Enter 键)。
该图像正在被网络浏览器缓存。通过响应标头中设置的与缓存相关的指令,以每个 URL 为基础对资源进行缓存。您的具体问题是由于资源 URL 仍然相同而 Web 浏览器不知道资源在服务器端已更改而引起的。OmniFaces展示页面详细解释了缓存(注意:过滤器不是此问题的解决方案)。CacheControlFilter
您基本上需要通过更改 URL 来强制网络浏览器重新请求资源。对于这种情况(可缓存资源突然更改并且其更改需要立即反映到所有客户端),最常见的方法之一是将图像的“上次修改”时间戳附加到 URL 的查询字符串。鉴于您正在使用 JPA,因此应该这样做:
向表中添加一lastModified
列brand
:
ALTER TABLE brand ADD COLUMN lastModified TIMESTAMP DEFAULT now();
Run Code Online (Sandbox Code Playgroud)Brand
使用适当的属性扩展实体并@PreUpdate
设置它:
@Column @Temporal(TemporalType.TIMESTAMP)
private Date lastModified;
@PreUpdate
public void onUpdate() {
lastModified = new Date();
}
// +getter+setter
Run Code Online (Sandbox Code Playgroud)
(@PreUpdate
JPA 在每次查询之前调用带注释的方法UPDATE
)
将其附加到图像 URL(参数名称v
是“版本”的提示):
<p:graphicImage value="#{brandBean.image}" ...>
<f:param name="id" value="#{row.brandId}" />
<f:param name="v" value="#{row.lastModified.time}" />
</p:graphicImage>
Run Code Online (Sandbox Code Playgroud)
(为了清楚起见,我在这里将row
其重命名为to以消除重复)brand
brandId
id
最后,如果您使用的是 PrimeFaces 5.0 或更高版本,那么您还需要禁用服务器端缓存:
<p:graphicImage value="#{brandBean.image}" cache="false" ...>
Run Code Online (Sandbox Code Playgroud)设计注意事项:如果图像不一定在每次更新时都更新Brand
,则将其拆分到另一个表中Image
,并让Brand
具有 FK(@ManyToOne
或@OneToOne
)Image
。这也使得属性“image”可以在 web 应用程序中的各个实体之间重复使用。
归档时间: |
|
查看次数: |
1387 次 |
最近记录: |