<p:graphicImage>在DataTable列表页不显示图片但详情页正常的问题
问题解决:PrimeFaces DataTable中无法显示数据库BLOB图片
问题根源
<p:graphicImage>会发起独立的HTTP请求获取图片资源,而你当前直接绑定#{artWork.picBits}的方式存在两个核心问题:
- 当图片请求发起时,原请求作用域的
ArtWorkTblBean已销毁,迭代上下文里的artWork对象无法被获取,导致getPicBits()从未被调用。 - 直接传递字节数组不符合HTTP资源请求的规范,需要通过流的方式返回图片内容。
解决方案步骤
1. 完善ArtWork实体(补充主键及必要方法)
确保实体有唯一标识,用于图片请求时定位资源:
@Entity @Table(schema = "APP",name = "ART_WORK", uniqueConstraints = {@UniqueConstraint(columnNames={"TITLE", "ARTIST_ID"})}) public class ArtWork implements Serializable, Comparable<ArtWork>{ @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 唯一主键 @Lob @Column(name = "PIC_BYTES") private byte[] picBits; // 图片MIME类型(可选,用于精准返回资源类型) @Column(name = "IMAGE_TYPE") private String imageType; // Getter & Setter public Long getId() { return id; } public void setId(Long id) { this.id = id; } public byte[] getPicBits() { return picBits; } public void setPicBits(byte[] picBits) { this.picBits = picBits; } public String getImageType() { return imageType; } public void setImageType(String imageType) { this.imageType = imageType; } }
2. 修改ArtWorkTblBean(添加图片流处理方法)
将Bean改为视图作用域,确保页面生命周期内状态保留;新增方法通过ID加载并返回图片流:
@Named @ViewScoped public class ArtWorkTblBean implements Serializable { private Artist artist; private List<ArtWork> works; @PersistenceContext private EntityManager em; public List<ArtWork> getArtWorks() { if (works == null) { works = new ArrayList<>(); if (artist != null && !artist.getArtWork().isEmpty()) { works.addAll(artist.getArtWork()); } } return works; } // 处理图片请求的核心方法 public StreamedContent getArtWorkImage() { FacesContext context = FacesContext.getCurrentInstance(); // 渲染页面阶段返回空内容,避免提前加载 if (context.getCurrentPhaseId() == PhaseId.RENDER_RESPONSE) { return new DefaultStreamedContent(); } // 从请求参数中获取作品ID String artWorkId = context.getExternalContext().getRequestParameterMap().get("artWorkId"); if (artWorkId == null) { return new DefaultStreamedContent(); } // 从数据库加载对应作品 ArtWork artWork = em.find(ArtWork.class, Long.parseLong(artWorkId)); if (artWork == null || artWork.getPicBits() == null) { return new DefaultStreamedContent(); } // 返回图片流,使用实体中存储的MIME类型(若无则默认image/jpeg) String mimeType = artWork.getImageType() != null ? artWork.getImageType() : "image/jpeg"; return new DefaultStreamedContent(new ByteArrayInputStream(artWork.getPicBits()), mimeType); } // Getter & Setter public Artist getArtist() { return artist; } public void setArtist(Artist artist) { this.artist = artist; } }
3. 修改DataTable页面代码
通过<f:param>传递作品ID,让图片请求能定位到对应资源:
<p:dataTable id="artWorkTbl" value="#{artWorkTblBean.artWorks}" var="artWork" styleClass="table"> <f:facet name="header"> <h:outputText value="Art Work" /> </f:facet> <p:column headerText="Picture"> <p:graphicImage value="#{artWorkTblBean.artWorkImage}" width="50" height="50" alt="No Image found" cache="false"> <f:param name="artWorkId" value="#{artWork.id}" /> </p:graphicImage> </p:column> </p:dataTable>
关键注意事项
- 若必须使用
@RequestScoped,需确保在getArtWorkImage()方法中重新从数据库加载ArtWork(而非依赖内存中的列表)。 - 图片MIME类型需与实际存储的图片格式匹配,避免浏览器无法解析。
- 确认数据库中
PIC_BYTES字段已正确存储图片的字节数据,无损坏或截断。
内容的提问来源于stack exchange,提问作者Ted Mitchell
相关产品推荐
相关产品推荐

