001/* 002 * Copyright 2002-2014 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.web.servlet.view.jasperreports; 018 019import java.io.ByteArrayOutputStream; 020import java.util.Map; 021import javax.servlet.http.HttpServletResponse; 022 023import net.sf.jasperreports.engine.JasperPrint; 024 025import org.springframework.ui.jasperreports.JasperReportsUtils; 026import org.springframework.util.CollectionUtils; 027import org.springframework.web.util.WebUtils; 028 029/** 030 * Extends {@code AbstractJasperReportsView} to provide basic rendering logic 031 * for views that use a fixed format, e.g. always PDF or always HTML. 032 * 033 * <p>Subclasses need to implement two template methods: {@code createExporter} 034 * to create a JasperReports exporter for a specific output format, and 035 * {@code useWriter} to determine whether to write text or binary content. 036 * 037 * <p><b>This class is compatible with classic JasperReports releases back until 2.x.</b> 038 * As a consequence, it keeps using the {@link net.sf.jasperreports.engine.JRExporter} 039 * API which got deprecated as of JasperReports 5.5.2 (early 2014). 040 * 041 * @author Rob Harrop 042 * @author Juergen Hoeller 043 * @since 1.1.5 044 * @see #createExporter() 045 * @see #useWriter() 046 */ 047@SuppressWarnings({"deprecation", "rawtypes"}) 048public abstract class AbstractJasperReportsSingleFormatView extends AbstractJasperReportsView { 049 050 @Override 051 protected boolean generatesDownloadContent() { 052 return !useWriter(); 053 } 054 055 /** 056 * Perform rendering for a single Jasper Reports exporter, that is, 057 * for a pre-defined output format. 058 */ 059 @Override 060 @SuppressWarnings("unchecked") 061 protected void renderReport(JasperPrint populatedReport, Map<String, Object> model, HttpServletResponse response) 062 throws Exception { 063 064 net.sf.jasperreports.engine.JRExporter exporter = createExporter(); 065 066 Map<net.sf.jasperreports.engine.JRExporterParameter, Object> mergedExporterParameters = getConvertedExporterParameters(); 067 if (!CollectionUtils.isEmpty(mergedExporterParameters)) { 068 exporter.setParameters(mergedExporterParameters); 069 } 070 071 if (useWriter()) { 072 renderReportUsingWriter(exporter, populatedReport, response); 073 } 074 else { 075 renderReportUsingOutputStream(exporter, populatedReport, response); 076 } 077 } 078 079 /** 080 * We need to write text to the response Writer. 081 * @param exporter the JasperReports exporter to use 082 * @param populatedReport the populated {@code JasperPrint} to render 083 * @param response the HTTP response the report should be rendered to 084 * @throws Exception if rendering failed 085 */ 086 protected void renderReportUsingWriter(net.sf.jasperreports.engine.JRExporter exporter, 087 JasperPrint populatedReport, HttpServletResponse response) throws Exception { 088 089 // Copy the encoding configured for the report into the response. 090 String contentType = getContentType(); 091 String encoding = (String) exporter.getParameter(net.sf.jasperreports.engine.JRExporterParameter.CHARACTER_ENCODING); 092 if (encoding != null) { 093 // Only apply encoding if content type is specified but does not contain charset clause already. 094 if (contentType != null && !contentType.toLowerCase().contains(WebUtils.CONTENT_TYPE_CHARSET_PREFIX)) { 095 contentType = contentType + WebUtils.CONTENT_TYPE_CHARSET_PREFIX + encoding; 096 } 097 } 098 response.setContentType(contentType); 099 100 // Render report into HttpServletResponse's Writer. 101 JasperReportsUtils.render(exporter, populatedReport, response.getWriter()); 102 } 103 104 /** 105 * We need to write binary output to the response OutputStream. 106 * @param exporter the JasperReports exporter to use 107 * @param populatedReport the populated {@code JasperPrint} to render 108 * @param response the HTTP response the report should be rendered to 109 * @throws Exception if rendering failed 110 */ 111 protected void renderReportUsingOutputStream(net.sf.jasperreports.engine.JRExporter exporter, 112 JasperPrint populatedReport, HttpServletResponse response) throws Exception { 113 114 // IE workaround: write into byte array first. 115 ByteArrayOutputStream baos = createTemporaryOutputStream(); 116 JasperReportsUtils.render(exporter, populatedReport, baos); 117 writeToResponse(response, baos); 118 } 119 120 121 /** 122 * Create a JasperReports exporter for a specific output format, 123 * which will be used to render the report to the HTTP response. 124 * <p>The {@code useWriter} method determines whether the 125 * output will be written as text or as binary content. 126 * @see #useWriter() 127 */ 128 protected abstract net.sf.jasperreports.engine.JRExporter createExporter(); 129 130 /** 131 * Return whether to use a {@code java.io.Writer} to write text content 132 * to the HTTP response. Else, a {@code java.io.OutputStream} will be used, 133 * to write binary content to the response. 134 * @see javax.servlet.ServletResponse#getWriter() 135 * @see javax.servlet.ServletResponse#getOutputStream() 136 */ 137 protected abstract boolean useWriter(); 138 139}