Hi guys, if you use jasper report in a web app with Struts2 and you deploy it in Tomcat with unpacked option set to true, it doesn't work because it's impossible to find the ation's relative path; I've modify the class org.apache.struts2.views.jasperreports.JasperReportsResult so you ca use absolute path in the result's location tag. If you set tag locationAbsolute to true (default false), jasper use the path of location tag without add at the beginning the action's absolute path:
<result name="pdf" type="jasper">
<param name="locationAbsolute">true</param>
<param name="location">/home/nicosia/report/fileJasper.jasper</param>
......
</result>
Here there is the new version of the source class:
/*
- $Id: JasperReportsResult.java,v 1.1 2012/05/10 16:06:15 34200007 Exp $
* - Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
* - http://www.apache.org/licenses/LICENSE-2.0
* - Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
*/
package org.apache.struts2.views.jasperreports;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.util.ValueStack;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporter;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JRParameter;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRCsvExporter;
import net.sf.jasperreports.engine.export.JRCsvExporterParameter;
import net.sf.jasperreports.engine.export.JRHtmlExporter;
import net.sf.jasperreports.engine.export.JRHtmlExporterParameter;
import net.sf.jasperreports.engine.export.JRPdfExporter;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXmlExporter;
import net.sf.jasperreports.engine.util.JRLoader;
import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.dispatcher.StrutsResultSupport;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.sql.Connection;
import java.util.HashMap;
import java.util.Map;
import java.util.TimeZone;
/**
- <!-- START SNIPPET: description -->
- <p/>
- Generates a JasperReports report using the specified format or PDF if no
- format is specified.
- <p/>
- <!-- END SNIPPET: description -->
- <p />
- <b>This result type takes the following parameters:</b>
- <p/>
- <!-- START SNIPPET: params -->
- <p/>
- <ul>
- <p/>
- <li><b>locationAbsolute (optional, boolean, default false)</b> - specify if location path is
- absolute or relative from current URL.</li>
- <li><b>location (default)</b> - the location where the compiled jasper report
- definition is (foo.jasper), relative from current URL if locationAbsolute is not true.</li>
- <p/>
- <li><b>dataSource (required)</b> - the EL expression used to retrieve the
- datasource from the value stack (usually a List).</li>
- <p/>
- <li><b>parse</b> - true by default. If set to false, the location param will
- not be parsed for EL expressions.</li>
- <p/>
- <li><b>format</b> - the format in which the report should be generated. Valid
- values can be found in
Unknown macro: {@link JasperReportConstants}. If no format is
- specified, PDF will be used.</li>
- <p/>
- <li><b>contentDisposition</b> - disposition (defaults to "inline", values are
- typically <i>filename="document.pdf"</i>).</li>
- <p/>
- <li><b>documentName</b> - name of the document (will generate the http header
- <code>Content-disposition = X; filename=X.[format]</code>).</li>
- <p/>
- <li><b>delimiter</b> - the delimiter used when generating CSV reports. By
- default, the character used is ",".</li>
- <p/>
- <li><b>imageServletUrl</b> - name of the url that, when prefixed with the
- context page, can return report images.</li>
- <p/>
- <li>
- <b>reportParameters</b> - (2.1.2+) OGNL expression used to retrieve a map of
- report parameters from the value stack. The parameters may be accessed
- in the report via the usual JR mechanism and might include data not
- part of the dataSource, such as the user name of the report creator, etc.
- </li>
- <p/>
- <li>
- <b>exportParameters</b> - (2.1.2+) OGNL expression used to retrieve a map of
- JR exporter parameters from the value stack. The export parameters are
- used to customize the JR export. For example, a PDF export might enable
- encryption and set the user password to a string known to the report creator.
- </li>
- <p/>
- <li>
- <b>connection</b> - (2.1.7+) JDBC Connection which can be passed to the
- report instead of dataSource
- </li>
- <p/>
- </ul>
- <p/>
- <p>
- This result follows the same rules from
Unknown macro: {@link StrutsResultSupport}.
- Specifically, all parameters will be parsed if the "parse" parameter
- is not set to false.
- </p>
- <!-- END SNIPPET: params -->
- <p/>
- <b>Example:</b>
- <p/>
- <pre><!-- START SNIPPET: example1 -->
- <result name="success" type="jasper">
- <param name="location">foo.jasper</param>
- <param name="dataSource">mySource</param>
- <param name="format">CSV</param>
- </result>
- <!-- END SNIPPET: example1 --></pre>
- or for pdf
- <pre><!-- START SNIPPET: example2 -->
- <result name="success" type="jasper">
- <param name="location">foo.jasper</param>
- <param name="dataSource">mySource</param>
- </result>
- <!-- END SNIPPET: example2 --></pre>
*/
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;
protected boolean locationAbsolute = false;
public void setLocationAbsolute(boolean locationAbsolute)
/**
- 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()Unknown macro: { super(); }
/**
- Default ctor with location.
* - @param location Result location.
*/
public JasperReportsResult(String location)Unknown macro: { super(location); }
public String getImageServletUrl()
public void setImageServletUrl(final String imageServletUrl)
public void setDataSource(String dataSource)
public void setFormat(String format)
public void setDocumentName(String documentName)
public void setContentDisposition(String contentDisposition)
public void setDelimiter(String delimiter)
/**
- set time zone id
* - @param timeZone
*/
public void setTimeZone(final String timeZone)Unknown macro: { this.timeZone = timeZone; }
public String getReportParameters()
public void setReportParameters(String reportParameters)
public String getExportParameters()
public void setExportParameters(String exportParameters)
public String getConnection()
public void setConnection(String connection)
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())
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
catch (IOException e)
return;
}
// Construct the data source for the report.
ValueStack stack = invocation.getStack();
ValueStackDataSource stackDataSource = null;
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 = null;
if(locationAbsolute == true)
else
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)
}
// Add any report parameters from action to param map.
Map reportParams = (Map) stack.findValue(reportParameters);
if (reportParams != null) {
if (LOG.isDebugEnabled())
parameters.putAll(reportParams);
}
byte[] output;
JasperPrint jasperPrint;
// Fill the report and produce a print object
try
catch (JRException 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)
response.setHeader("Content-disposition", tmp.toString());
}
JRExporter exporter;
if (format.equals(FORMAT_PDF))
else if (format.equals(FORMAT_CSV))
else if (format.equals(FORMAT_HTML))
else if (format.equals(FORMAT_XLS))
else if (format.equals(FORMAT_XML))
else if (format.equals(FORMAT_RTF))
else
Map exportParams = (Map) stack.findValue(exportParameters);
if (exportParams != null) {
if (LOG.isDebugEnabled())
exporter.getParameters().putAll(exportParams);
}
output = exportReportToBytes(jasperPrint, exporter);
} catch (JRException e)
response.setContentLength(output.length);
// Will throw ServletException on IOException.
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;
tryUnknown macro: { outputStream = response.getOutputStream(); outputStream.write(output); outputStream.flush(); }catch (IOException e)Unknown macro: { LOG.error("Error writing report output", e); throw new ServletException(e.getMessage(), e); }finally {
tryUnknown macro: { if (outputStream != null)catch (IOException e)Unknown macro: { outputStream.close(); }}Unknown macro: { 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)Unknown macro: { 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))
if (contentDisposition != null)
if (documentName != null)
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
*/
private byte[] exportReportToBytes(JasperPrint jasperPrint, JRExporter exporter) throws JRException {
byte[] output;
ByteArrayOutputStream baos = new ByteArrayOutputStream();
exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, baos);
if (delimiter != null)
exporter.exportReport();
output = baos.toByteArray();
return output;
}
}
1 Comment
Lukasz Lenart
Could you register an issue and attach a patch instead posting the code here ? It's very hard to catch it up :/