`

自定义struts2 plugin(jasper-plugin扩展)

 
阅读更多

  因需要实现页面上导出Excel时能够隐藏某些Excel列,(jasperreports6.3.1)尝试修改Jasperreports的jrxml模板文件,比如在jrxml元素table或者文本元素的reportElement标签里添加属性net.sf.jasperreports.export.xls.cell.hidden,结论是无论是xls格式还是xlsx格式都不奏效。

  (但是,net.sf.jasperreports.export.xls.freeze.column.edge这个属性实现冻结行列却能生效,不知为何)

  于是借助第三方API:JXL、POI,在Excel文件生成后解除这些API修改生成的Excel以实现Web页面导出时就隐藏某些列。

  项目基于struts2框架,基于编译好的jasper模板使用struts2-jasperreports-plugin填充数据在web上实现导出Excel文件,

 

  基本流程:

一,使用iReport(5.6)设计基础模板;

    过程略;

二,重写/扩展struts2的类似struts2-jasperreports-plugin的自定义result处理过程;

  1,获取jasper模板(location)、Struts2的dataSource、format、值栈数据、值栈参数

  2,设定HttpServletResponse的response类型(本质上就是对HttpServletResponse对象设置以响应HttpServletRequest)

  3,填充数据生成JasperPrint

  4,JRXlsxExporter/JRXlsExporter导出Excel文件

  5,使用POI/Jxl修改Excel工作簿行列隐藏属性(使用struts值栈传递参数),写入字节流

自定义Result代码:

 

public class JasperReportsResult extends StrutsResultSupport implements JasperReportConstants {

    private static final long serialVersionUID = -2523174799621182907L;

    private final static Logger LOG = LoggerFactory.getLogger(JasperReportsResult.class);

    protected String dataSource;
    protected String format;
    protected String documentName;
    protected String contentDisposition;
    protected String delimiter;
    protected String imageServletUrl = "/images/";
    protected String timeZone;
    
	/**
     * Connection which can be passed to the report
     * instead od dataSource.
     */
    protected String connection;

    /**
     * Names a report parameters map stack value, allowing
     * additional report parameters from the action.
     */
    protected String reportParameters;

    /**
     * Names an exporter parameters map stack value,
     * allowing the use of custom export parameters.
     */
    protected String exportParameters;

    /**
     * Default ctor.
     */
    public JasperReportsResult() {
        super();
    }

    /**
     * Default ctor with location.
     *
     * @param location Result location.
     */
    public JasperReportsResult(String location) {
        super(location);
    }

    public String getImageServletUrl() {
        return imageServletUrl;
    }

    public void setImageServletUrl(final String imageServletUrl) {
        this.imageServletUrl = imageServletUrl;
    }

    public void setDataSource(String dataSource) {
        this.dataSource = dataSource;
    }

    public void setFormat(String format) {
        this.format = format;
    }

    public void setDocumentName(String documentName) {
        this.documentName = documentName;
    }

    public void setContentDisposition(String contentDisposition) {
        this.contentDisposition = contentDisposition;
    }

    public void setDelimiter(String delimiter) {
        this.delimiter = delimiter;
    }
        

    /**
     * set time zone id
     *
     * @param timeZone
     */
    public void setTimeZone(final String timeZone) {
        this.timeZone = timeZone;
    }

    public String getReportParameters() {
        return reportParameters;
    }

    public void setReportParameters(String reportParameters) {
        this.reportParameters = reportParameters;
    }

    public String getExportParameters() {
        return exportParameters;
    }

    public void setExportParameters(String exportParameters) {
        this.exportParameters = exportParameters;
    }

    public String getConnection() {
        return connection;
    }

    public void setConnection(String connection) {
        this.connection = connection;
    }
        
    private String tmppath;
    
    private String hiddencs;

    protected void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
        // Will throw a runtime exception if no "datasource" property. TODO Best place for that is...?
        initializeProperties(invocation);

        if (LOG.isDebugEnabled()) {
            LOG.debug("Creating JasperReport for dataSource = " + dataSource + ", format = " + format);
        }

        HttpServletRequest request = (HttpServletRequest) invocation.getInvocationContext().get(ServletActionContext.HTTP_REQUEST);
        HttpServletResponse response = (HttpServletResponse) invocation.getInvocationContext().get(ServletActionContext.HTTP_RESPONSE);

        // Handle IE special case: it sends a "contype" request first.
        // TODO Set content type to config settings?
        if ("contype".equals(request.getHeader("User-Agent"))) {
            try {
               // response.setContentType("application/pdf");
           	response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");//xlsx
            //	response.setContentType("application/vnd.ms-excel");//xls
                response.setContentLength(0);

                ServletOutputStream outputStream = response.getOutputStream();
                outputStream.close();
            } catch (IOException e) {
                LOG.error("Error writing report output", e);
                throw new ServletException(e.getMessage(), e);
            }
            return;
        }

        // Construct the data source for the report.
        ValueStack stack = invocation.getStack();
        ValueStackDataSource stackDataSource = null;
        
        /**
         * 获取值栈中的值
         * 
         * ****/
        this.hiddencs = (String) stack.findString("xlsxhidecolums");
        LOG.info("value stack, xlsxhidecolums: "+ hiddencs);        
        
        Connection conn = (Connection) stack.findValue(connection);
        if (conn == null)
            stackDataSource = new ValueStackDataSource(stack, dataSource);

        // Determine the directory that the report file is in and set the reportDirectory parameter
        // For WW 2.1.7:
        //  ServletContext servletContext = ((ServletConfig) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONFIG)).getServletContext();
        ServletContext servletContext = (ServletContext) invocation.getInvocationContext().get(ServletActionContext.SERVLET_CONTEXT);
        String systemId = servletContext.getRealPath(finalLocation);
        
        tmppath  = servletContext.getRealPath("/") + "/" + UUID.randomUUID()+String.valueOf(System.currentTimeMillis()) + ".xlsx";/////
        
        Map parameters = new ValueStackShadowMap(stack);
        File directory = new File(systemId.substring(0, systemId.lastIndexOf(File.separator)));
        parameters.put("reportDirectory", directory);
        parameters.put(JRParameter.REPORT_LOCALE, invocation.getInvocationContext().getLocale());

        // put timezone in jasper report parameter
        if (timeZone != null) {
            timeZone = conditionalParse(timeZone, invocation);
            final TimeZone tz = TimeZone.getTimeZone(timeZone);
            if (tz != null) {
                // put the report time zone
                parameters.put(JRParameter.REPORT_TIME_ZONE, tz);
            }
        }

        // Add any report parameters from action to param map.
        Map reportParams = (Map) stack.findValue(reportParameters);
        if (reportParams != null) {
            if (LOG.isDebugEnabled()) {
        	LOG.debug("Found report parameters; adding to parameters...");
            }
            parameters.putAll(reportParams);
        }
        
     //   String hide =  (String) stack.findValue(hidecolumns);
    //    LOG.info("hide str: "+hide);
        

        byte[] output;
        JasperPrint jasperPrint;

        // Fill the report and produce a print object
        try {
            JasperReport jasperReport = (JasperReport) JRLoader.loadObjectFromFile(systemId);
            if (conn == null)
                jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, stackDataSource);
            else
                jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, conn);
        } catch (JRException e) {
            LOG.error("Error building report for uri " + systemId, e);
            throw new ServletException(e.getMessage(), e);
        }

        // Export the print object to the desired output format
        try {
            if (contentDisposition != null || documentName != null) {
                final StringBuffer tmp = new StringBuffer();
                tmp.append((contentDisposition == null) ? "inline" : contentDisposition);

                if (documentName != null) {
                    tmp.append("; filename=");
                    tmp.append(documentName);
                    tmp.append(".");
                    tmp.append(format.toLowerCase());
                }

                response.setHeader("Content-disposition", tmp.toString());
            }

            JRExporter exporter;
            
            if ( format.equals(FORMAT_XLSX)){
            	
           	response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");//xlsx
            //	response.setContentType("application/vnd.ms-excel");//xls
            	exporter = new JRXlsxExporter(); //xlsx
            //	 exporter = new JRXlsExporter();//xls
            	
            }            
            else {
                throw new ServletException("Unknown report format: " + format);
            }

            Map exportParams = (Map) stack.findValue(exportParameters);
            if (exportParams != null) {
                if (LOG.isDebugEnabled()) {
                    LOG.debug("Found export parameters; adding to exporter parameters...");
                }
                exporter.getParameters().putAll(exportParams);
            }

            output = exportReportToBytes(jasperPrint, exporter);
        } catch (JRException e) {
            String message = "Error producing " + format + " report for uri " + systemId;
            LOG.error(message, e);
            throw new ServletException(e.getMessage(), e);
        }

        response.setContentLength(output.length);

        writeReport(response, output);
    }

    /**
     * Writes report bytes to response output stream.
     *
     * @param response Current response.
     * @param output   Report bytes to write.
     * @throws ServletException on stream IOException.
     */
    private void writeReport(HttpServletResponse response, byte[] output) throws ServletException {
        ServletOutputStream outputStream = null;
        try {
        	
        	
            outputStream = response.getOutputStream();
            outputStream.write(output);
            outputStream.flush();
        } catch (IOException e) {
            LOG.error("Error writing report output", e);
            throw new ServletException(e.getMessage(), e);
        } finally {
            try {
                if (outputStream != null) {
                    outputStream.close();
                }
            } catch (IOException e) {
                LOG.error("Error closing report output stream", e);
                throw new ServletException(e.getMessage(), e);
            }
        }
    }

    /**
     * Sets up result properties, parsing etc.
     *
     * @param invocation Current invocation.
     * @throws Exception on initialization error.
     */
    private void initializeProperties(ActionInvocation invocation) throws Exception {
        if (dataSource == null && connection == null) {
            String message = "No dataSource specified...";
            LOG.error(message);
            throw new RuntimeException(message);
        }
        if (dataSource != null)
            dataSource = conditionalParse(dataSource, invocation);

        format = conditionalParse(format, invocation);
        if (StringUtils.isEmpty(format)) {
            format = FORMAT_XLSX; //XLSX
        }

        if (contentDisposition != null) {
            contentDisposition = conditionalParse(contentDisposition, invocation);
        }

        if (documentName != null) {
            documentName = conditionalParse(documentName, invocation);
        }

        reportParameters = conditionalParse(reportParameters, invocation);
        exportParameters = conditionalParse(exportParameters, invocation);

    }

    /**
     * Run a Jasper report to CSV format and put the results in a byte array
     *
     * @param jasperPrint The Print object to render as CSV
     * @param exporter    The exporter to use to export the report
     * @return A CSV formatted report
     * @throws net.sf.jasperreports.engine.JRException
     *          If there is a problem running the report
     * @throws IOException 
     * @throws BiffException 
     * @throws WriteException 
     */
    private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws JRException, IOException, BiffException, WriteException {
    	
    	
    	ByteArrayOutputStream baos = new ByteArrayOutputStream();
    	
    	FileOutputStream tmpos = new FileOutputStream(this.tmppath);//
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, tmpos);
        exporter.exportReport();        
        boolean ifhide = false;   
                       
        org.apache.poi.ss.usermodel.Workbook wb = //new HSSFWorkbook(new FileInputStream(this.tmppath));//xls
        		new XSSFWorkbook(new FileInputStream(this.tmppath));//XLSX ;
               
        String hidden[] = this.hiddencs.split("\\,", -1);
        for (int i = 0; i < hidden.length; i++) {
        	wb.getSheetAt(0).setColumnHidden(Integer.valueOf(hidden[i]), true);//参数获取
		}
                
        wb.write(baos);
        tmpos.close();     
        wb.close();     	    	
        byte[] output;              
        File f = new File(this.tmppath);
        f.delete();
        if (delimiter != null) {
            exporter.setParameter(JRCsvExporterParameter.FIELD_DELIMITER, delimiter);
        }

        output = baos.toByteArray();

        return output;
    }



}

 

 

三,struts2项目中配置web.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>struts2plugintest1</display-name>
  
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>  

</web-app>

 

 

四,struts2项目配置struts.xml

1,struts2会按顺序加载struts-default.xml/struts-plugin.xml/struts.xml的配置项,struts.xml中配置:

 

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
	<constant name="struts.i18n.encoding" value="UTF-8" />
    <constant name="struts.devMode" value="true" />
    <constant name="struts.configuration.xml.reload" value="true" />    
    
    <package name="default" namespace="/" extends="jasperxlsxhide-default">    	
    	<action name="xlsxhide" class="merrick.action.TesthideAction"  >    	
    		<result type="jasperxlsxhide" name="getxlsx">
   		   			<param name="dataSource">dlst</param>
		   			<param name="location">/reports/report3.jasper</param>
		   			<param name="reportParameters">pmap</param>					
		   			<param name="format">XLSX</param>     		
    		</result>  		
    	</action>    	    
    </package>
</struts>

 

 

2,自定义(扩展/重写)的Reslut类型(jasperxlsxhide),需要配置在插件jar包中的struts-plugin.xml文件中:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC
	"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
	"http://struts.apache.org/dtds/struts-2.3.dtd">    
<struts>
    <package name="jasperxlsxhide-default" extends="struts-default">
    
    	<result-types>
    		<result-type name="jasperxlsxhide" class="struts2plugin.merrick.xlsxhide.japser.JasperReportsResult"/>
    	</result-types>
    </package>
</struts>

 

五,struts2的Action调用部分

 

	public String execute() throws Exception {// TEST SUCCESSFUL


		Map param = new HashMap<String , Object>();
		param.put("parameterA", "11");
		param.put("paramtitle", "HELLO");//
		param.put("displayCol4", true);//work
		this.setPmap(param);
		ArrayList<DataBean> dataList = new ArrayList<DataBean>();
		setListdata(dataList);
		this.setDlst(dataList);
		//http://localhost:8080/struts2plugintest1/xlsxhide.action		
		
		ctx.getActionInvocation().getStack().set("xlsxhidecolums", "3,4");//
			
		return "getxlsx";
	}

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics