001/* 002 * Copyright 2002-2018 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.document; 018 019import java.io.ByteArrayOutputStream; 020import java.io.IOException; 021import java.util.Map; 022import javax.servlet.http.HttpServletRequest; 023import javax.servlet.http.HttpServletResponse; 024 025import com.lowagie.text.pdf.PdfReader; 026import com.lowagie.text.pdf.PdfStamper; 027 028import org.springframework.web.servlet.view.AbstractUrlBasedView; 029 030/** 031 * Abstract superclass for PDF views that operate on an existing 032 * document with an AcroForm. Application-specific view classes 033 * will extend this class to merge the PDF form with model data. 034 * 035 * <p>This view implementation uses Bruno Lowagie's 036 * <a href="https://www.lowagie.com/iText">iText</a> API. 037 * Known to work with the original iText 2.1.7 as well as its fork 038 * <a href="https://github.com/LibrePDF/OpenPDF">OpenPDF</a>. 039 * <b>We strongly recommend OpenPDF since it is actively maintained 040 * and fixes an important vulnerability for untrusted PDF content.</b> 041 * 042 * <p>Thanks to Bryant Larsen for the suggestion and the original prototype! 043 * 044 * @author Juergen Hoeller 045 * @since 2.5.4 046 * @see AbstractPdfView 047 */ 048public abstract class AbstractPdfStamperView extends AbstractUrlBasedView { 049 050 public AbstractPdfStamperView(){ 051 setContentType("application/pdf"); 052 } 053 054 055 @Override 056 protected boolean generatesDownloadContent() { 057 return true; 058 } 059 060 @Override 061 protected final void renderMergedOutputModel( 062 Map<String, Object> model, HttpServletRequest request, HttpServletResponse response) throws Exception { 063 064 // IE workaround: write into byte array first. 065 ByteArrayOutputStream baos = createTemporaryOutputStream(); 066 067 PdfReader reader = readPdfResource(); 068 PdfStamper stamper = new PdfStamper(reader, baos); 069 mergePdfDocument(model, stamper, request, response); 070 stamper.close(); 071 072 // Flush to HTTP response. 073 writeToResponse(response, baos); 074 } 075 076 /** 077 * Read the raw PDF resource into an iText PdfReader. 078 * <p>The default implementation resolve the specified "url" property 079 * as ApplicationContext resource. 080 * @return the PdfReader instance 081 * @throws IOException if resource access failed 082 * @see #setUrl 083 */ 084 protected PdfReader readPdfResource() throws IOException { 085 return new PdfReader(getApplicationContext().getResource(getUrl()).getInputStream()); 086 } 087 088 /** 089 * Subclasses must implement this method to merge the PDF form 090 * with the given model data. 091 * <p>This is where you are able to set values on the AcroForm. 092 * An example of what can be done at this level is: 093 * <pre class="code"> 094 * // get the form from the document 095 * AcroFields form = stamper.getAcroFields(); 096 * 097 * // set some values on the form 098 * form.setField("field1", "value1"); 099 * form.setField("field2", "Vvlue2"); 100 * 101 * // set the disposition and filename 102 * response.setHeader("Content-disposition", "attachment; FILENAME=someName.pdf");</pre> 103 * <p>Note that the passed-in HTTP response is just supposed to be used 104 * for setting cookies or other HTTP headers. The built PDF document itself 105 * will automatically get written to the response after this method returns. 106 * @param model the model Map 107 * @param stamper the PdfStamper instance that will contain the AcroFields. 108 * You may also customize this PdfStamper instance according to your needs, 109 * e.g. setting the "formFlattening" property. 110 * @param request in case we need locale etc. Shouldn't look at attributes. 111 * @param response in case we need to set cookies. Shouldn't write to it. 112 * @throws Exception any exception that occurred during document building 113 */ 114 protected abstract void mergePdfDocument(Map<String, Object> model, PdfStamper stamper, 115 HttpServletRequest request, HttpServletResponse response) throws Exception; 116 117}