com.I には、ユーザーが画像をアップロードする SWF アプリがあり、その画像は次のフロー状態で表示する必要があります。フローは、ユーザーが入力したすべてのデータを格納する会話スコープ Bean (実際には JPA エンティティ) を使用します。画像をアップロードして Bean に保存することはできますが、PrimeFaces の graphicImage facelet ではレンダリングされません。いくつかの調査を行ったところ、PF GI コンポーネントのレンダリング中に、セッションで評価される EL 式が格納され、その後の ResourceHandler への呼び出し (レンダリングされた HTML の IMG タグによって行われる) によって、同じ EL 式がフェッチされ、実際に評価されるようです。問題は、 ResourceHandler がすべてのデータを保存するフロー変数にアクセスできないため、画像をレンダリングできないことです。
PF GI コンポーネントを拡張して、EL 式の代わりにセッションで実際の画像を保存しましたが、パフォーマンスに明らかな影響があります。バイナリ データをセッションに保存することはお勧めできません。また、セキュリティ上の理由から、すべてのデータをセッションではなくフロー/会話スコープに保持したいと思います。
PF GI コンポーネントがフロー変数にアクセスできるようにするクリーンな方法はありますか?
以下の私のコードのスニペット
流れ:
<on-start>
<evaluate expression="new my.models.Customers()" result="conversationScope.customer"></evaluate>
</on-start>
<view-state id="scanImage" view="s1-scan.xhtml" model="customer" >
<secured attributes="ROLE_WEB" />
<transition on="submit" to="verifyImage"></transition>
<transition on="cancel" to="canceled"></transition>
</view-state>
<view-state id="verifyImage" view="s2-verifyscan.xhtml" model="customer">
<secured attributes="ROLE_WEB" />
<transition on="submit" to="enterDetails"></transition>
<transition on="back" to="scanImage"></transition>
<transition on="cancel" to="canceled"></transition>
</view-state>
画像のレンダリング:
<p:graphicImage value="#{customer.getImageSC()}"></p:graphicImage>
パッチを適用した GraphicImageRenderer.getImageSrc()
protected String getImageSrc(FacesContext context, GraphicImage image) {
String src = null;
String name = image.getName();
if(name != null) {
String libName = image.getLibrary();
ResourceHandler handler = context.getApplication().getResourceHandler();
Resource res = handler.createResource(name, libName);
if(res == null) {
return "RES_NOT_FOUND";
}
else {
String requestPath = res.getRequestPath();
return context.getExternalContext().encodeResourceURL(requestPath);
}
}
else {
Object value = image.getValue();
if(value == null) {
return "";
}
else if(value instanceof String) {
src = getResourceURL(context, (String) value);
}
else if(value instanceof StreamedContent) {
StreamedContent streamedContent = (StreamedContent) value;
Resource resource = context.getApplication().getResourceHandler().createResource("dynamiccontent", "primefaces", streamedContent.getContentType());
String resourcePath = resource.getRequestPath();
String rid = createUniqueContentId(context);
StringBuilder builder = new StringBuilder(resourcePath);
builder.append("&").append(Constants.DYNAMIC_CONTENT_PARAM).append("=").append(rid);
for(UIComponent kid : image.getChildren()) {
if(kid instanceof UIParameter) {
UIParameter param = (UIParameter) kid;
builder.append("&").append(param.getName()).append("=").append(param.getValue());
}
}
src = builder.toString();
context.getExternalContext().getSessionMap().put(rid, value);
// context.getExternalContext().getSessionMap().put(rid, image.getValueExpression("value").getExpressionString());
}
if(!image.isCache()) {
src += src.contains("?") ? "&" : "?";
src += "primefaces_image=" + UUID.randomUUID().toString();
}
src = context.getExternalContext().encodeResourceURL(src);
}
return src;
}
ハンドラ:
public void handleResourceRequest(FacesContext context) throws IOException {
Map<String,String> params = context.getExternalContext().getRequestParameterMap();
String library = params.get("ln");
String dynamicContentId = params.get(Constants.DYNAMIC_CONTENT_PARAM);
if(dynamicContentId != null && library != null && library.equals("primefaces")) {
Map<String,Object> session = context.getExternalContext().getSessionMap();
StreamedContent streamedContent = null;
try {
Object dynamicContentEL = (Object) session.get(dynamicContentId);
//String dynamicContentEL = (String) session.get(dynamicContentId);
//ELContext eLContext = context.getELContext();
//ValueExpression ve = context.getApplication().getExpressionFactory().createValueExpression(context.getELContext(), dynamicContentEL, StreamedContent.class);
//streamedContent = (StreamedContent) ve.getValue(eLContext);
streamedContent = (StreamedContent) dynamicContentEL;
ExternalContext externalContext = context.getExternalContext();
externalContext.setResponseStatus(200);
externalContext.setResponseContentType(streamedContent.getContentType());
byte[] buffer = new byte[2048];
int length;
InputStream inputStream = streamedContent.getStream();
while ((length = (inputStream.read(buffer))) >= 0) {
externalContext.getResponseOutputStream().write(buffer, 0, length);
}
externalContext.responseFlushBuffer();
context.responseComplete();
} catch(Exception e) {
logger.log(Level.SEVERE, "Error in streaming dynamic resource. {0}", new Object[]{e.getMessage()});
}
finally {
//cleanup
session.remove(dynamicContentId);
if(streamedContent != null) {
streamedContent.getStream().close();
}
}
}
else {
super.handleResourceRequest(context);
}
}
顔構成:
<application>
<el-resolver>org.springframework.web.jsf.el.SpringBeanFacesELResolver</el-resolver>
<resource-handler>com.my.PrimeResourceHandler</resource-handler>
</application>
<render-kit>
<renderer>
<component-family>org.primefaces.component</component-family>
<renderer-type>org.primefaces.component.graphicimage.GraphicImageRenderer</renderer-type>
<renderer-class>com.my.GraphicImageRenderer</renderer-class>
</renderer>
</render-kit>
Webflow コンテキストを EL と一緒に Session オブジェクトに保存し、EL を評価するときにそのコンテキストを使用するようにリソース ハンドラーを作成することが可能であると思われます...