我在<p:graphicImage>
上显示以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>
编辑行时,<p:fileUpload>
上会显示<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();
}
}
根据唯一的行标识符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));
}
}
}
通过单击数据表最后一列中的定位符(由<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,然后按输入键)。
换句话说,当通过单击<p:rowEditor>
指示的刻度更新数据表中的行时,不会调用getImage()
方法(因此,不会从数据库中提取新图像)显示在<p:graphicImage>
)上。仅当通过按 F5 快捷键刷新/重新加载页面时才会调用此方法。
为什么会这样?如何在更新行后立即显示新更新的图像?
表面上看,这既不应该与Spring也不应该与JPA相关(点击勾选后更新操作会正确地传播到数据库)。这应该与Tomcat服务器相关。
答案 0 :(得分:1)
仅当通过按F5(在大多数浏览器上)刷新页面时,才会显示新更新的图像。它甚至不会显示在页面加载上(在地址栏中输入URL然后按回车键)。
Webbrowser正在缓存图像。通过响应头中设置的缓存相关指令,基于每个URL缓存资源。导致您的具体问题是因为资源URL仍然相同,并且Web浏览器不知道资源在服务器端已更改。 OmniFaces CacheControlFilter
showcase page详细解释了缓存(注意:过滤器不是解决此问题的方法)。
您基本上需要强制Web浏览器通过更改URL来重新请求资源。对于这种情况最常见的方法之一是,可缓存资源突然改变并且其更改需要立即反映到所有客户端,将图像的“最后修改”时间戳附加到URL的查询字符串。鉴于您正在使用JPA,所以应该这样做:
在lastModified
表中添加brand
列:
ALTER TABLE brand ADD COLUMN lastModified TIMESTAMP DEFAULT now();
使用适当的属性扩展Brand
实体,并设置@PreUpdate
设置它:
@Column @Temporal(TemporalType.TIMESTAMP)
private Date lastModified;
@PreUpdate
public void onUpdate() {
lastModified = new Date();
}
// +getter+setter
(JPA在每次@PreUpdate
查询之前调用UPDATE
带注释的方法
将其附加到图片网址(参数名称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
)到Image
。这也使得属性“图像”可以在webapp中的各种实体之间重用。
答案 1 :(得分:0)
HY,
我有同样的问题,但我的图像src是硬盘而不是DB。 当我使用随机数但我不读它时,我有结果问题。 一般来说,当这个参数是一个随机数时,我在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;
}
}
在我的页面中我有像这样的元素graphicImage:
<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"/>
in
我希望这种模式可以帮助您解决问题