📄 abstractjasperreportsview.java
字号:
}
}
/**
* Converts the exporter parameters passed in by the user which may be keyed
* by <code>String</code>s corresponding to the fully qualified name of the
* <code>JRExporterParameter</code> into parameters which are keyed by
* <code>JRExporterParameter</code>.
* @see #getExporterParameter(Object)
*/
protected final void convertExporterParameters() {
if (this.exporterParameters != null && !this.exporterParameters.isEmpty()) {
this.convertedExporterParameters = new HashMap(this.exporterParameters.size());
for (Iterator it = this.exporterParameters.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
this.convertedExporterParameters.put(getExporterParameter(entry.getKey()), entry.getValue());
}
}
}
/**
* Return a <code>JRExporterParameter</code> for the given parameter object,
* converting it from a String if necessary.
* @param parameter the parameter object, either a String or a JRExporterParameter
* @return a JRExporterParameter for the given parameter object
* @see #convertToExporterParameter(String)
*/
protected JRExporterParameter getExporterParameter(Object parameter) {
if (parameter instanceof JRExporterParameter) {
return (JRExporterParameter) parameter;
}
if (parameter instanceof String) {
return convertToExporterParameter((String) parameter);
}
throw new IllegalArgumentException(
"Parameter [" + parameter + "] is invalid type. Should be either String or JRExporterParameter.");
}
/**
* Convert the given fully qualified field name to a corresponding
* JRExporterParameter instance.
* @param fqFieldName the fully qualified field name, consisting
* of the class name followed by a dot followed by the field name
* (e.g. "net.sf.jasperreports.engine.export.JRHtmlExporterParameter.IMAGES_URI")
* @return the corresponding JRExporterParameter instance
*/
protected JRExporterParameter convertToExporterParameter(String fqFieldName) {
int index = fqFieldName.lastIndexOf('.');
if (index == -1 || index == fqFieldName.length()) {
throw new IllegalArgumentException(
"Parameter name [" + fqFieldName + "] is not a valid static field. " +
"The parameter name must map to a static field such as " +
"[net.sf.jasperreports.engine.export.JRHtmlExporterParameter.IMAGES_URI]");
}
String className = fqFieldName.substring(0, index);
String fieldName = fqFieldName.substring(index + 1);
try {
Class cls = ClassUtils.forName(className);
Field field = cls.getField(fieldName);
if (JRExporterParameter.class.isAssignableFrom(field.getType())) {
try {
return (JRExporterParameter) field.get(null);
}
catch (IllegalAccessException ex) {
throw new IllegalArgumentException(
"Unable to access field [" + fieldName + "] of class [" + className + "]. " +
"Check that it is static and accessible.");
}
}
else {
throw new IllegalArgumentException("Field [" + fieldName + "] on class [" + className +
"] is not assignable from JRExporterParameter - check the type of this field.");
}
}
catch (ClassNotFoundException ex) {
throw new IllegalArgumentException(
"Class [" + className + "] in key [" + fqFieldName + "] could not be found.");
}
catch (NoSuchFieldException ex) {
throw new IllegalArgumentException("Field [" + fieldName + "] in key [" + fqFieldName +
"] could not be found on class [" + className + "].");
}
}
/**
* Loads a <code>JasperReport</code> from the specified <code>Resource</code>. If
* the <code>Resource</code> points to an uncompiled report design file then the
* report file is compiled dynamically and loaded into memory.
* @param resource the <code>Resource</code> containing the report definition or design
* @return a <code>JasperReport</code> instance
*/
private JasperReport loadReport(Resource resource) throws ApplicationContextException {
try {
String fileName = resource.getFilename();
if (fileName.endsWith(".jasper")) {
// Load pre-compiled report.
if (logger.isInfoEnabled()) {
logger.info("Loading pre-compiled Jasper Report from " + resource);
}
return (JasperReport) JRLoader.loadObject(resource.getInputStream());
}
else if (fileName.endsWith(".jrxml")) {
// Compile report on-the-fly.
if (logger.isInfoEnabled()) {
logger.info("Compiling Jasper Report loaded from " + resource);
}
JasperDesign design = JRXmlLoader.load(resource.getInputStream());
return getReportCompiler().compileReport(design);
}
else {
throw new IllegalArgumentException(
"Report URL [" + getUrl() + "] must end in either .jasper or .jrxml");
}
}
catch (IOException ex) {
throw new ApplicationContextException(
"Could not load JasperReports report for URL [" + getUrl() + "]", ex);
}
catch (JRException ex) {
throw new ApplicationContextException(
"Could not parse JasperReports report for URL [" + getUrl() + "]", ex);
}
}
/**
* Finds the report data to use for rendering the report and then invokes the
* <code>renderReport</code> method that should be implemented by the subclass.
* @param model the model map, as passed in for view rendering. Must contain
* a report data value that can be converted to a <code>JRDataSource</code>,
* acccording to the <code>getReportData</code> method.
* @see #getReportData
*/
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response)
throws Exception {
response.reset();
response.setContentType(getContentType());
// Populate HTTP headers.
populateHeaders(response);
if (this.subReports != null) {
// Expose sub-reports as model attributes.
model.putAll(this.subReports);
// Transform any collections etc into JRDataSources for sub reports.
if (this.subReportDataKeys != null) {
for (int i = 0; i < this.subReportDataKeys.length; i++) {
String key = this.subReportDataKeys[i];
model.put(key, convertReportData(model.get(key)));
}
}
}
// Expose Spring-managed Locale and MessageSource.
exposeLocalizationContext(model, request);
// Fill and render the report.
JasperPrint filledReport = fillReport(model);
postProcessReport(filledReport, model);
renderReport(filledReport, model, response);
}
/**
* Expose current Spring-managed Locale and MessageSource to JasperReports i18n
* ($R expressions etc). The MessageSource should only be exposed as JasperReports
* resource bundle if no such bundle is defined in the report itself.
* <p>Default implementation exposes the Spring RequestContext Locale and a
* MessageSourceResourceBundle adapter for the Spring ApplicationContext,
* analogous to the <code>JstlUtils.exposeLocalizationContext</code> method.
* @see org.springframework.web.servlet.support.RequestContextUtils#getLocale
* @see org.springframework.context.support.MessageSourceResourceBundle
* @see #getApplicationContext()
* @see net.sf.jasperreports.engine.JRParameter#REPORT_LOCALE
* @see net.sf.jasperreports.engine.JRParameter#REPORT_RESOURCE_BUNDLE
* @see org.springframework.web.servlet.support.JstlUtils#exposeLocalizationContext
*/
protected void exposeLocalizationContext(Map model, HttpServletRequest request) {
Locale locale = RequestContextUtils.getLocale(request);
model.put(JRParameter.REPORT_LOCALE, locale);
if (this.report.getResourceBundle() == null) {
ResourceBundle bundle = new MessageSourceResourceBundle(getApplicationContext(), locale);
model.put(JRParameter.REPORT_RESOURCE_BUNDLE, bundle);
}
}
/**
* Creates a populated <code>JasperPrint</code> instance from the configured
* <code>JasperReport</code> instance. By default, will use any <code>JRDataSource</code>
* instance (or wrappable <code>Object</code>) that can be located using
* <code>getReportData(Map)</code>. If no <code>JRDataSource</code> can be found, will use a
* <code>Connection</code> obtained from the configured <code>javax.sql.DataSource</code>.
* @param model the model for this request
* @throws IllegalArgumentException if no <code>JRDataSource</code> can be found
* and no <code>javax.sql.DataSource</code> is supplied
* @throws SQLException if there is an error when populating the report using
* the <code>javax.sql.DataSource</code>
* @throws JRException if there is an error when populating the report using
* a <code>JRDataSource</code>
* @return the populated <code>JasperPrint</code> instance
* @see #getReportData
* @see #setJdbcDataSource
*/
protected JasperPrint fillReport(Map model) throws IllegalArgumentException, SQLException, JRException {
// Determine JRDataSource for main report.
JRDataSource jrDataSource = getReportData(model);
if (jrDataSource == null && this.jdbcDataSource == null) {
throw new IllegalArgumentException(
"No report data source found in model and no [javax.sql.DataSource] specified in configuration");
}
if (jrDataSource != null) {
// Use the JasperReports JRDataSource.
if (logger.isDebugEnabled()) {
logger.debug("Filling report with JRDataSource [" + jrDataSource + "].");
}
return JasperFillManager.fillReport(this.report, model, jrDataSource);
}
else {
// Use the JDBC DataSource.
if (logger.isDebugEnabled()) {
logger.debug("Filling report with JDBC DataSource [" + this.jdbcDataSource + "].");
}
Connection con = this.jdbcDataSource.getConnection();
try {
return JasperFillManager.fillReport(this.report, model, con);
}
finally {
try {
con.close();
}
catch (SQLException ex) {
logger.warn("Could not close JDBC Connection", ex);
}
}
}
}
/**
* Populates the headers in the <code>HttpServletResponse.</code> with the
* headers supplied by the user.
*/
private void populateHeaders(HttpServletResponse response) {
// Apply the headers to the response.
for (Enumeration en = this.headers.propertyNames(); en.hasMoreElements();) {
String key = (String) en.nextElement();
response.addHeader(key, this.headers.getProperty(key));
}
}
/**
* Find an instance of <code>JRDataSource</code> in the given model map or create an
* appropriate JRDataSource for passed-in report data.
* <p>The default implementation checks for a model object under the
* specified "reportDataKey" first, then falls back to looking for a value
* of type <code>JRDataSource</code>, <code>java.util.Collection</code>,
* object array (in that order).
* @param model the model map, as passed in for view rendering
* @return the <code>JRDataSource</code> or <code>null</code> if the data source is not found
* @see #setReportDataKey
* @see #convertReportData
* @see #getReportDataTypes
*/
protected JRDataSource getReportData(Map model) {
// Try model attribute with specified name.
if (this.reportDataKey != null) {
Object value = model.get(this.reportDataKey);
return convertReportData(value);
}
// Try to find matching attribute, of given prioritized types.
Object value = CollectionUtils.findValueOfType(model.values(), getReportDataTypes());
if (value != null) {
return convertReportData(value);
}
return null;
}
/**
* Convert the given report data value to a <code>JRDataSource</code>.
* <p>The default implementation delegates to <code>JasperReportUtils</code> unless
* the report data value is an instance of <code>JRDataSourceProvider</code>.
* A <code>JRDataSource</code>, <code>JRDataSourceProvider</code>,
* <code>java.util.Collection</code> or object array is detected.
* <code>JRDataSource</code>s are returned as is, whilst <code>JRDataSourceProvider</code>s
* are used to create an instance of <code>JRDataSource</code> which is then returned.
* The latter two are converted to <code>JRBeanCollectionDataSource</code> or
* <code>JRBeanArrayDataSource</code>, respectively.
* @param value the report data value to convert
* @return the JRDataSource
* @throws IllegalArgumentException if the value could not be converted
* @see org.springframework.ui.jasperreports.JasperReportsUtils#convertReportData
* @see net.sf.jasperreports.engine.JRDataSource
* @see net.sf.jasperreports.engine.JRDataSourceProvider
* @see net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
* @see net.sf.jasperreports.engine.data.JRBeanArrayDataSource
*/
protected JRDataSource convertReportData(Object value) throws IllegalArgumentException {
if (value instanceof JRDataSourceProvider) {
try {
return ((JRDataSourceProvider) value).create(this.report);
}
catch (JRException ex) {
throw new IllegalArgumentException("Supplied JRDataSourceProvider is invalid: " + ex);
}
}
else {
return JasperReportsUtils.convertReportData(value);
}
}
/**
* Return the value types that can be converted to a <code>JRDataSource</code>,
* in prioritized order. Should only return types that the
* <code>convertReportData</code> method is actually able to convert.
* <p>Default value types are: <code>JRDataSource</code>,
* <code>JRDataSourceProvider</code> <code>java.util.Collection</code>
* and <code>Object</code> array.
* @return the value types in prioritized order
* @see #convertReportData
*/
protected Class[] getReportDataTypes() {
return new Class[] {JRDataSource.class, JRDataSourceProvider.class, Collection.class, Object[].class};
}
/**
* Allows sub-classes to get access to the <code>JasperReport</code> instance
* loaded by Spring.
* @return an instance of <code>JasperReport</code>
*/
protected JasperReport getReport() {
return this.report;
}
/**
* Template method to be overridden for custom post-processing of the
* populated report. Invoked after filling but before rendering.
* <p>The default implementation is empty.
* @param populatedReport the populated <code>JasperPrint</code>
* @param model the map containing report parameters
* @throws Exception if post-processing failed
*/
protected void postProcessReport(JasperPrint populatedReport, Map model) throws Exception {
}
/**
* Subclasses should implement this method to perform the actual rendering process.
* @param populatedReport the populated <code>JasperPrint</code> to render
* @param model the map containing report parameters
* @param response the HTTP response the report should be rendered to
* @throws Exception if rendering failed
*/
protected abstract void renderReport(JasperPrint populatedReport, Map model, HttpServletResponse response)
throws Exception;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -