在基于WebSphere JSF 1.2 Portlet Bridge的JSF Portlet中实现文件下载

来源:互联网 发布:java发送qq消息接口 编辑:程序博客网 时间:2024/05/16 23:01

本文讨论在基于WebSphere JSF 1.2 Portlet Bridge的JSF Portlet中实现文件下载。

JSR 286规范提供了一个基于resource serving的文件下载机制,但由于JSF 1.2 Portlet Bridge并没有提供相应的支持,所以必须在混合使用portlet和JSF来实现这个机制。

具体的实现包含三部分: 一个继承FacesPortlet并实现serveResource方法的portlet类, 一个显示下载链接的JSF页面, 以及一个提供文件内容的JSF managed bean。

portlet类

package demo;import java.io.IOException;import java.io.OutputStream;import javax.el.ExpressionFactory;import javax.el.ValueExpression;import javax.faces.context.FacesContext;import javax.faces.lifecycle.Lifecycle;import javax.portlet.PortletException;import javax.portlet.PortletSession;import javax.portlet.ResourceRequest;import javax.portlet.ResourceResponse;import com.ibm.faces.portlet.FacesPortlet;import com.ibm.faces.portlet.httpbridge.PortletRequestWrapper;import com.ibm.faces.portlet.httpbridge.PortletResponseWrapper;import com.ibm.faces.portlet.httpbridge.ResourceRequestWrapper;import com.ibm.faces.portlet.httpbridge.ResourceResponseWrapper;public class JSFPortlet extends FacesPortlet {@Overridepublic void serveResource(ResourceRequest request, ResourceResponse response)throws PortletException, IOException {super.serveResource(request, response);TestBean testBean = (TestBean) getJSFManagedBean(request, response, TestBean.BEAN_NAME, TestBean.class);final OutputStream out = response.getPortletOutputStream();byte[] bytes = testBean.getCsv();response.setContentType("text/csv");response.setProperty("Content-Disposition","attachment; filename=download.csv");response.setProperty("Content-length", String.valueOf(bytes.length));out.write(bytes);out.flush();out.close();}public Object getJSFManagedBean(ResourceRequest request,ResourceResponse response, String beanName, Class beanClass)throws PortletException {PortletSession portletSession = request.getPortletSession();Object jsfBean = (TestBean) portletSession.getAttribute(beanName);if (jsfBean == null) {PortletRequestWrapper requestWrapper = new ResourceRequestWrapper(request);requestWrapper.setPortletContext(getPortletContext());PortletResponseWrapper responseWrapper = new ResourceResponseWrapper(response);Lifecycle lifecycle = getLifecycle(requestWrapper);FacesContext context = getFacesContext(requestWrapper,responseWrapper, lifecycle);final ExpressionFactory expressionFactory = context.getApplication().getExpressionFactory();final ValueExpression valueExpression = expressionFactory.createValueExpression(context.getELContext(), "#{" + beanName + "}", beanClass);jsfBean = (TestBean) valueExpression.getValue(context.getELContext());}return jsfBean;}}

JSF页面

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%><%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%><%@ taglib uri="http://java.sun.com/portlet_2_0" prefix="portlet"%>               <%@taglib uri="http://www.ibm.com/xmlns/prod/websphere/portal/v6.1/portlet-client-model"          prefix="portlet-client-model" %>              <%@ page language="java" contentType="text/html" pageEncoding="ISO-8859-1" session="false"%><portlet:defineObjects /><portlet-client-model:init>      <portlet-client-model:require module="ibm.portal.xml.*"/>      <portlet-client-model:require module="ibm.portal.portlet.*"/>   </portlet-client-model:init>          <f:view>    <portlet:resourceURL var="resourceUrl" > <portlet:param name="action" value="csv" />  </portlet:resourceURL>  <a href="<%=resourceUrl%>">Download CSV</a>  </f:view>

JSF managed bean

package demo;import java.util.Date;public class TestBean {public static final String BEAN_NAME = "testBean";public byte[] getCsv() {    return new Date().toString().getBytes();  }public String getText() {return "Hello";}}

开发中的一些发现:

- IBM JSF 1.2 Portlet Bridge没有提供portlet tag的对应Facelet taglib xml, 因此不能在基于Facelet的JSF页面中使用<portlet:resourceURL>。 这个问题已经在IBM JSF 2 Portlet Bridge中得到解决。

- <portlet:resourceURL> tag提供一个var属性, 可以用来定义一个变量来保存resource URL供页面上得其他代码使用。 JSR 286规范将该变量定义于JSP page scope中。 由于JSF无法访问JSP page scope, 因此页面上的JSF组件也无法使用该变量。

- 在传统的Servlet编程中,我们使用response.setHeader方法来设置HTTP response的头信息,包括Content-DispositionContent-length, 而在portlet中,我们使用ResourceResponse.setProperty方法。

-在portlet中可以通过两种方法来访问JSF managed beans, 如果要访问的JSF managed bean是一个session scope bean 且已存在于session只用, 那么可以使用portletSession.getAttribute(BEAN_NAME)来获取该bean, 否则的话, 就必须从FacesContext中使用JSF value expression表达式来创建和获取该bean。 由于IBM JSF 1.2 Portlet Bridge并没有提供一个直接的方法来获取FacesContext, 必须使用一些内部代码来实现该功能。

原创粉丝点击