在struts2中添加自定义的result的type类型,只需要两步即可在应用中使用了,首先编写自定义类型的类,然后在struts.xml中进行注册即可,若自定义类型带有重定向性质时,就涉及到参数的传递,可参考ServletActionRedirectResult(org.apache.struts2.dispatcher)类,具体可参阅OGNL、ValueStack相关内容。
1、编写自定义类型的处理类
package com.csmn.base.action;
import java.io.File;
import java.io.OutputStream;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.servlet.RequestDispatcher;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.PageContext;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.StrutsResultSupport;
import org.apache.struts2.views.util.UrlHelper;
import org.xhtmlrenderer.pdf.ITextFontResolver;
import org.xhtmlrenderer.pdf.ITextRenderer;
import com.lowagie.text.pdf.BaseFont;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.config.entities.ResultConfig;
import com.opensymphony.xwork2.util.TextParseUtil;
/**
* <p>
* PdfResult類主要用於-导出到PDF.
* </p>
* <p>
* 創建時間 2013-12-7 - 下午08:05:52
* </p>
* <blockquote>
* <h4>歷史修改記錄</h4>
* <ul>
* <li>城邑耕夫 2017-02-02 添加动态参数传递(主要用于处理文件名)
* </ul>
* </blockquote>
* <p>
* copyright cdthgk 2010-2013, all rights reserved.
* </p>
*
* @author 車水碼農
* @author cdthgk r&d
* @since 1.0
* @version 1.0
*/
public class PdfResult extends StrutsResultSupport {
private static final long serialVersionUID = -6588129708854890330L;
private static final Log log = LogFactory.getLog(PdfResult.class);
public PdfResult() {
super();
init();
}
public PdfResult(String location) {
super(location);
init();
}
/**
* Dispatches to the given location. Does its forward via a
* RequestDispatcher. If the dispatch fails a 404 error will be sent back in
* the http response.
*
* @param finalLocation
* the location to dispatch to.
* @param invocation
* the execution state of the action
* @throws Exception
* if an error occurs. If the dispatch fails the error will go
* back via the HTTP request.
*/
public void doExecute(String finalLocation, ActionInvocation invocation)
throws Exception {
log.debug("Forwarding to location " + finalLocation);
PageContext pageContext = ServletActionContext.getPageContext();
if (pageContext != null) {
pageContext.include(finalLocation);
} else {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
RequestDispatcher dispatcher = request.getRequestDispatcher(finalLocation);
// if the view doesn't exist, let's do a 404
if (dispatcher == null) {
response.sendError(404, "result '" + finalLocation + "' not found");
return;
}
//[
StringWriter sw = new StringWriter();
HttpResponseWrapper rw = new HttpResponseWrapper(response, sw);
//]
// If we're included, then include the view
// Otherwise do forward
// This allow the page to, for example, set content type
if (!response.isCommitted() && (request.getAttribute("javax.servlet.include.servlet_path") == null)) {
request.setAttribute("struts.view_uri", finalLocation);
request.setAttribute("struts.request_uri", request.getRequestURI());
// 处理参数
ResultConfig resultConfig = invocation.getProxy().getConfig().getResults().get(invocation.getResultCode());
if (resultConfig != null ) {
Map<String, String> resultConfigParams = resultConfig.getParams();
for (Iterator<Entry<String, String>> i = resultConfigParams.entrySet().iterator(); i.hasNext();) {
Map.Entry<String, String> e = i.next();
String param = e.getKey().toString();
if (!getProhibitedResultParams().contains(param)) {
String potentialValue = (e.getValue() == null ? "" : conditionalParse(e.getValue().toString(), invocation));
requestParameters.put(param, potentialValue);
}
}
}
StringBuilder tmpLocation = new StringBuilder(finalLocation);
UrlHelper.buildParametersString(requestParameters, tmpLocation, "&");
finalLocation = response.encodeRedirectURL(tmpLocation.toString());
dispatcher.forward(request, rw);
} else {
dispatcher.include(request, rw);
}
rw.getWriter().close();
// pdf文件内容
// log.debug(sw.toString());
// 通过ValueStack处理后的文件名,再编码
fileName = new String(requestParameters.get("fileName").getBytes(),"ISO8859-1");
ITextRenderer renderer = new ITextRenderer();
renderer.setDocumentFromString(sw.toString());
if (request.getHeader("User-Agent").indexOf("MSIE 5.5") != -1) {
response.setHeader("Content-Disposition", "filename=" + fileName);
} else {
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
}
response.setHeader("Content-Type", "application/octet-stream;charset=ISO8859-1");
// 解决中文支持问题
ITextFontResolver fontResolver = renderer.getFontResolver();
fontResolver.addFont(new File(this.getClass().getResource("SIMSUN.TTC").getFile()).getAbsolutePath(), BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
// 解决图片的相对路径问题
//renderer.getSharedContext().setBaseURL("file:/E:/workspace/eclipse_utf-8_workspace/PdfTest/src/flyingsaucer/start/");
renderer.layout();
OutputStream os = response.getOutputStream();
renderer.createPDF(os);
os.close();
}
}
// ********************************************************************
// private & protected
// ********************************************************************
private void init(){
try {
this.fileName = new String("未命名文件.pdf".getBytes(),"ISO8859-1");
} catch (UnsupportedEncodingException e) {
log.debug(ExceptionUtils.getStackTrace(e));
this.fileName = new String("未命名文件.pdf");
}
}
protected List<String> getProhibitedResultParams() {
return Arrays.asList(new String[]{
DEFAULT_PARAM, "namespace", "method", "encode", "parse", "location",
"prependServletContext", "supressEmptyParameters"});
}
protected String conditionalParse(String param, ActionInvocation invocation) {
if (param != null && invocation != null) {
String finalValue = TextParseUtil.translateVariables(param, invocation.getStack());
log.debug(param + "通过值栈解析后的参数:" + finalValue);
return finalValue;
} else {
return param;
}
}
// ********************************************************************
// setter and getter
// ********************************************************************
private String fileName;
protected Map<String, String> requestParameters = new LinkedHashMap<String, String>();
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
try {
this.fileName = new String(fileName.getBytes(),"ISO8859-1");
} catch (UnsupportedEncodingException e) {
this.fileName = fileName;
log.debug(ExceptionUtils.getStackTrace(e));
}
}
public Map<String, String> getRequestParameters() {
return requestParameters;
}
public void setRequestParameters(Map<String, String> requestParameters) {
this.requestParameters = requestParameters;
}
}
2、在struts.xml中注册自定义类型
<package name="csmn.default" extends="struts-default">
<result-types>
<result-type name="pdf" class="com.csmn.base.action.PdfResult"/>
……
</result-types>
<!-- 全局结果 -->
<global-results>
……
</global-results>
<!-- 全局异常 -->
<global-exception-mappings>
……
</global-exception-mappings>
</package>
3、应用中使用自定义类型
<action name="use_*" method="{1}" class="yy.disposableUseAction">
<result name="success">/com/csmn/ext/yy/disposable/use_{1}.jsp</result>
<result name="yearMonthGoodsUseList_pdf" type="pdf">
<param name="location">/com/csmn/ext/yy/disposable/use_yearMonthGoodsUseList.jsp</param>
<param name="fileName">医院${goodsUseDto.year}年${goodsUseDto.month}月一次性无菌物品出入库情况一栏表.pdf</param>
</result>
</action>
上面的type="pdf"即为第二步中result-types下的name="pdf",参数${goodsUseDto.year}、${goodsUseDto.month}则通过第一步中TextParseUtil.translateVariables(param, invocation.getStack())处理为实际数据。