freemarker 下载pdf

版权声明: https://blog.csdn.net/qq_35193093/article/details/87717863

应公司要求,现学现卖,一遍过,没有进行优化,粗糙上线,如有差错欢迎指正。

1,

public abstract class AbstractPdfGenerator extends PDFDataUtils {

	public static final String DEFAULT_ENCODING	= "UTF-8";
	
	public void createPdfTemplate(HttpServletRequest req, HttpServletResponse resp, Map data, String tmpPath, String tmpName, String pdfName) throws IOException, TemplateException, DocumentException, com.itextpdf.text.DocumentException {
		Template template = this.loadTemplateFile(tmpName,tmpPath);
		String content = this.processTemplate(template, data);
		InputStream in=this.renderPDF(tmpPath,content);
		this.downLoadPdf(req,resp,in,pdfName);
	}
	
	/**
	 * pdf下载
	 */
	public void downLoadPdf(HttpServletRequest req, HttpServletResponse resp,InputStream in,String pdfName) {
		String contentType="application/pdf";
		OutputStream os=null;
		try {
			os = resp.getOutputStream();
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		resp.setContentType(contentType);
		resp.setHeader("Content-Disposition", "attachment; filename="+
				(StringUtils.isBlank(pdfName)?PdfDownLoadContant.PDF_DOWN_DEFAULT_NAME:pdfName));
		//resp.setHeader("Content-Disposition", "attachment; filename=aaaaa.pdf");
		resp.setHeader("Content-Type", contentType+"text/x-download; charset=UTF-8");
		try {
			byte[] buf = new byte[1024];
			int size;
			while (-1 != (size = in.read(buf))) {
				os.write(buf, 0, size);
			}
			// Flush
			os.flush();
		} catch (Exception e) {
			//throw new Exception("Something Wrong. In Class Of "+AbstractFileCreator.class.getName()+".");
			
		} finally {
			IOUtils.closeQuietly(in);
			IOUtils.closeQuietly(os);
		}
	
	}
	
	
	private InputStream renderPDF(String tmpPath,String content) throws IOException, com.itextpdf.text.DocumentException {
		InputStream in = null;
		ITextRenderer renderer = new ITextRenderer();
		PDFReplacedElementFactory replacedElementFactory = new PDFReplacedElementFactory(renderer.getOutputDevice());
		renderer.getSharedContext().setReplacedElementFactory(replacedElementFactory);
		renderer.setDocumentFromString(content);
		String fileUrl=tmpPath.substring(0,tmpPath.lastIndexOf("/"));
		String url = "" + FramarkerUtil.class.getResource(fileUrl) + "/";
		renderer.getSharedContext().setBaseURL(url);
        this.loadFonts(renderer);
		renderer.layout();
		ByteArrayOutputStream out = new ByteArrayOutputStream();
		try {
			renderer.createPDF(out, true);
			 in = new ByteArrayInputStream(out.toByteArray());
		} finally {
			IOUtils.closeQuietly(out);
		}
		return in;
	}
	
	
	private void loadFonts(ITextRenderer renderer){
		String fontsFilePath =PdfDownLoadContant.PDF_DOWN_FONTS_URL;
	    URL fontURL = FramarkerUtil.class.getResource(fontsFilePath);
	    File fontsFolder = new File(fontURL.getPath());
        if (fontsFolder.isDirectory()) {
            String[] font_files = fontsFolder.list();
            if (font_files != null && font_files.length > 0) {
                for (int i = 0; i < font_files.length; i++) {
                    String font = fontsFilePath + font_files[i];
                    try {
                        renderer.getFontResolver().addFont(font, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
                    } catch (Exception exc) {
                       // Debug.important(PdfDownLoadContant.LOG_CATEGORY, SERVICE_NAME, exc.toString());
                    }
                }
            }
        }
	}
	
	@SuppressWarnings("deprecation")
	private Template loadTemplateFile(String tmpName,String tmpPath) throws IOException {
		Configuration cfg = new Configuration();
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		cfg.setClassForTemplateLoading(this.getClass(), tmpPath);
		cfg.setDefaultEncoding(DEFAULT_ENCODING);
		Template template = null;
        template = cfg.getTemplate(tmpName,"UTF-8");
		return template;
	}
	
	private  String processTemplate(Template template, Map data) throws IOException, TemplateException {
		String str = null;
		StringWriter writer = new StringWriter();
		try {
			template.process(data, writer);
			str = writer.getBuffer().toString();
		} finally {
			IOUtils.closeQuietly(writer);
		}
		return str;
	}

}

2,

public abstract class PDFDataUtils {

    public <T> Map<String, Object> dataPage(Map<String, List<T>> groupByDc,int one,int newDc,int general) {

        // 排版规则(根据自身情况)因为我的需求,pdf头不一样
        final int onePage = one;
        
        final int newDcPage = newDc;
        
        final int generalPage = general;
        // 获取所有的key
        Set<String> keySet = groupByDc.keySet();


        int b = 0;
        List<PDFReport> lists = new ArrayList<>();
        for (String s : keySet) {

            List<T> list = groupByDc.get(s);
            int size = list.size();
            //for (BillingReportCommand entity : list) {
            int last = 0;
            int two = 0;
            int temp = 0;
//            PDFReport pdfReport = new PDFReport();
            if (b == 0) {
                // 最后一页有几条
                last = (size - onePage) % generalPage;
                // 有多少个第二页
                two = (size - onePage) / generalPage;
                temp = onePage;
                //b++;
            } else {
                // 最后一页有几条
                last = (size - newDcPage) % generalPage;
                // 有多少个第二页
                two = (size - newDcPage) / generalPage;
                temp = newDcPage;
            }

            // 第一种 第一页不大于8条
            if ((size <= onePage && b == 0)) {
                PDFReport pdfReport = new PDFReport();
                pdfReport.setList(list);
                pdfReport.setFlag("F");
                pdfReport.setEntity(list.get(0));
                lists.add(pdfReport);

                // 大于 8条
            } else if (size <= newDcPage && b != 0) {
                PDFReport pdfReport = new PDFReport();
                pdfReport.setList(list);
                pdfReport.setFlag("F");
                pdfReport.setEntity(list.get(0));
                lists.add(pdfReport);
            } else {
                // 超过两页
                int num = 0;
                // 判断是否是第一个dc  ,是--12,不是--14
                if (b == 0) {
                    num = onePage + generalPage;

                } else {
                    num = newDcPage + generalPage;
                }
                if (size > num) {
                    PDFReport pdfReport = new PDFReport();
                    // 判断是否是第一个dc
                    if (b == 0) {
                        pdfReport.setList(list.subList(0, onePage));
                        //b++;
                    } else {
                        pdfReport.setList(list.subList(0, newDcPage));
                    }

                    pdfReport.setFlag("F");
                    pdfReport.setEntity(list.get(0));

                    lists.add(pdfReport);

                    for (int j = 0; j <= two; j++) {
                        if (j <= two - 1) {
                            int temp1 = temp + generalPage;
                            PDFReport pdfReport1 = new PDFReport();
                            // 取第二,三 。。。页数据
                            pdfReport1.setList(list.subList(temp, temp1));
                            pdfReport1.setFlag("T");
                            pdfReport1.setEntity(list.get(0));
                            lists.add(pdfReport1);
                        } else {
                            PDFReport pdfReport2 = new PDFReport();
                            int temp1 = temp + last;
                            // 取第最后一页数据
                            pdfReport2.setList(list.subList(temp, temp1));
                            pdfReport2.setFlag("L");
                            pdfReport2.setEntity(list.get(0));
                            lists.add(pdfReport2);
                        }
                    }
                } else {
                    PDFReport pdfReport = new PDFReport();
                    // 第一页
                    pdfReport.setList(list.subList(0, temp));
                    pdfReport.setFlag("F");
                    pdfReport.setEntity(list.get(0));
                    lists.add(pdfReport);

                    // 最后一页有几条
                    int temp1 = temp + last;
                    PDFReport pdfReport1 = new PDFReport();
                    // 取第最后一页数据
                    pdfReport1.setList(list.subList(temp, temp1));
                    pdfReport1.setFlag("L");
                    pdfReport1.setEntity(list.get(0));
                    lists.add(pdfReport1);
                }
            }
            b++;
        }
        Map m = new HashMap();
        m.put("dataMap", lists);
        m.put("totalPage", lists.size());
        return m;
    }

}

3,

public class PDFReport  {

    private static final long serialVersionUID = 5298298168301894230L;

    private Object entity;

    private Object list;

    private String flag;

    public Object getEntity() {
        return entity;
    }

    public void setEntity(Object entity) {
        this.entity = entity;
    }

    public Object getList() {
        return list;
    }

    public void setList(Object list) {
        this.list = list;
    }

    public String getFlag() {
        return flag;
    }

    public void setFlag(String flag) {
        this.flag = flag;
    }


}

4,

public class PdfDownLoadContant {

	/**
	 *  PDF URL
	 */
	public static final String PDF_DOWN_URL="/tpl/pdf/template/";

	public static final String PDF_DOWN_FONTS_URL="/tpl/pdf/fonts/";
	public static final String PDF_DOWN_DEFAULT_NAME="download.pdf";

}

5,

public class PDFReplacedElementFactory extends ITextReplacedElementFactory {

	public PDFReplacedElementFactory(ITextOutputDevice outputDevice) {
		super(outputDevice);
	}

	public ReplacedElement createReplacedElement(LayoutContext c, BlockBox box, UserAgentCallback uac, int cssWidth, int cssHeight) {
		ReplacedElement sr = super.createReplacedElement(c, box, uac, cssWidth, cssHeight);
		if (sr != null)
			return sr;

		Element e = box.getElement();
		if (e == null) {
			return null;
		}
        
		String nodeName = e.getNodeName();
		Node node=null;
		if("bargenerator".equals(e.getAttribute("name"))) {
			node=e.getFirstChild();
			e=(Element)node;
		}
	//	if (nodeName.equals("input") && "barcode".equalsIgnoreCase(e.getAttribute(AsnPackTabAttribute.type.name()))) {
		if(node!=null) {
			String data = e.getAttribute(AsnPackTabAttribute.data.name());
			if (data == null || data.length() == 0)
				return null;
			String height = e.getAttribute(AsnPackTabAttribute.height.name());
			String width = e.getAttribute(AsnPackTabAttribute.width.name());
			String baseWidth = e.getAttribute(AsnPackTabAttribute.baseWidth.name());
			String multiplier = e.getAttribute(AsnPackTabAttribute.multiplier.name());
			String barType = e.getAttribute(AsnPackTabAttribute.barType.name());

			BarcodeAttributies at = new BarcodeAttributies(height, width, baseWidth, multiplier,c.getSharedContext().getDotsPerPixel(),c.getSharedContext().getDPI());

			if (barType == null || barType.length() == 0)
				barType = BAR_CODE_TYPE_CONTANT.TYPE_128;

			Barcode barcode = null;
			if (BAR_CODE_TYPE_CONTANT.TYPE_128.equals(barType)) {
				barcode = new Barcode128();
			}
			if (BAR_CODE_TYPE_CONTANT.TYPE_39.equals(barType)) {
				barcode = new Barcode39();
			}

			barcode.setFont(null);
			barcode.setBarHeight(at.height);
			barcode.setX(at.baseWidth);
			barcode.setN(at.multiplier);
			barcode.setCode(data);
			
			return new ITextBarcodeElement(barcode, at.width);
		}
		return null;
	}

	class BarcodeAttributies {
		int height = 500;
		int width = 1000;
		int baseWidth = 20;
		float multiplier = 2f;

		BarcodeAttributies(String height, String width, String baseWidth, String multiplier,int dotsPerPixel,float dpi) {
			if (height != null && height.length() > 0) {
				this.height = (int) (Double.parseDouble(height) / 25.4 * dpi);
			}
			if (width != null && width.length() > 0) {
				this.width = (int) (Double.parseDouble(width) / 25.4 * dpi);
			}
			if (baseWidth != null && baseWidth.length() > 0) {
				this.baseWidth = (int) (Double.parseDouble(baseWidth) * dotsPerPixel);
			}
			if (multiplier != null && multiplier.length() > 0) {
				this.multiplier = Float.parseFloat(multiplier);
			}
		}
	}
}

6,

public class ITextBarcodeElement  implements ITextReplacedElement {
	private Barcode barcode;
	private int width;
	 private Point _location = new Point(0, 0);
	public ITextBarcodeElement(Barcode barcode, int width){
		this.barcode = barcode;
		this.width=width;
	}
	public int getIntrinsicWidth() {
		return width;
	}

	public int getIntrinsicHeight() {
		return (int)barcode.getBarHeight();
	}

	public Point getLocation() {
		return _location;
	}

	public void setLocation(int x, int y) {
		_location = new Point(x, y);

	}

	public void detach(LayoutContext c) {

	}

	public boolean isRequiresInteractivePaint() {
		return false;
	}

	public boolean hasBaseline() {
		return false;
	}

	public int getBaseline() {
		return 0;
	}

	public void paint(RenderingContext c, ITextOutputDevice outputDevice, BlockBox box) {
		Rectangle contentBounds = box.getContentAreaEdge(box.getAbsX(), box.getAbsY(), c);
			Image image = barcode.createImageWithBarcode(outputDevice.getCurrentPage(), null, null);
			outputDevice.drawImage(new ITextFSImage(image),contentBounds.x, contentBounds.y);
		
	}
 
}

7,

public class FramarkerUtil {
	private Map<String, Object> data;

	public FramarkerUtil(Map<String, Object> data) {
		this.data = data;
	}
	
	public String templateContentWithClassPath(String classPath){
		try {
			File res = new ClassPathResource(classPath).getFile();
			return templateContent(res.getParentFile(), res.getName());
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		return null;
	}
	public String templateContent(File baseTemplatePath,String templateFileName){
		Configuration cfg = new Configuration();
		cfg.setDefaultEncoding("UTF-8");
		cfg.setObjectWrapper(new DefaultObjectWrapper());
		try {
			cfg.setDirectoryForTemplateLoading(baseTemplatePath);
			Template templet = cfg.getTemplate(templateFileName,"UTF-8");
			StringWriter writer=new StringWriter();  
			templet.process(data, writer);  
			return writer.getBuffer().toString();
		} catch (IOException e) {
			e.printStackTrace();
		} catch (TemplateException e) {
			e.printStackTrace();
		}
		return null;
	}

}

8,

public class BAR_CODE_TYPE_CONTANT {
	public static final String	TYPE_128	= "128";
	public static final String	TYPE_417	= "417";
	public static final String	TYPE_QR		= "qr";
	public static final String	TYPE_25		= "25";
	public static final String	TYPE_39		= "39";
	public static final String TYPE_Datamatrix = "datamatrix";

}

调用:

// m 为分页规则(按照自身情况,进行重构或其他),如果pdf分页要求,可以吧数据直接赋值。
m = dataPage(groupByDc,13,16,18);
		createPdfTemplate(request,response,m,PDF_DOWN_URL,"pendingStockMovementReport.ftl","test_"+DateUtils.getCurrentSytemTimeForStringByPackagesCode()+".pdf");

ftl样例:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width,initial-scale=1.0"/>
    <title>Billing Report</title>
    <style type="text/css">
        @page {
            size: 297mm 210mm;
            margin: 5mm 5mm 5mm 5mm;
            padding: 0;
            text-align: center;
            font-size: 9pt;
            @top-left {
                content: element(page-header)
            };
            @bottom-left {
                content: element(page-footer)
            };
        }

        .pageBreak {
            page-break-after: always;
        }

        * {
            margin: 0;
            padding: 0;
        }

        body {
            font-family: 'Simsun';
        }

        .b {
            width: 287mm;
        }

        .b-container {
            margin-right: 10mm;
            margin-left: 10mm;
        }

        .table-header {
            text-align: center;
            width: 100%;
        }

        #container-table {
            font-size: 8pt;
            border-collapse: collapse;
            text-align: center;
            font-family: 'SimSun';
            width: 267mm;
            margin-top: 5mm;
            /* table-layout: fixed; */
        }

        .table-header th {
            border: 0.1mm solid #000;
            padding: 0.5mm;
            font-weight: 900;
        }

        #container-table tr td {
            border: 0.1mm solid #000;
            text-align: left;
            padding: 0.5mm;
            height: 9mm;
            /* overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis; */
        }

        .max-height {
            max-height: 7mm;
            overflow: hidden;
            padding: 1mm 0;
            line-height: 4mm;
        }
    </style>

</head>

<body>
<div class="b">
    <div class="b-container">
        <#list dataMap as items>
// 如果数据为空,打印空表头,和必填数据。 start
            <#if items.flag=="N">
 <div class="header"  style="margin-top: 5mm;">
     <div style="float: right; text-align: center; height: 15mm; width: 50mm;">
         <img src="../logo.png" alt="" style="width: 22mm; height: 13mm;" />
         <div style="font-size: 11pt; font-weight: bold; font-family: 'SimSun'">A货有限公司</div>
     </div>
     <!-- 标题 -->
     <div style="font-size: 24pt; font-family: 'Arial'; text-align: center; padding-top: 15mm;">
         pdf名字
     </div>
 </div>
          <div style="margin-top: 5mm;">
			<div style="font-size: 9pt; font-family: 'SimSun';margin-left: 20mm; margin-top: 5mm;">

                <div style="height: 7mm">
                    <div style="float: left; width: 30mm;">测试:</div>
                    <div style="float: left; width: 45mm;">${items.entity.month! }</div>
                </div>
   
            </div>

          <#--遍历数据-->

              <table id="container-table">
                  <tr class="table-header">
                     
                      <th style="width: 17mm;">测试</th>
                  </tr>
              </table>
              <div style="font-weight: bold; font-size: 8pt; float: right; margin-right: 2mm; margin-top: 3mm;text-align: center">
                  <div style="float: left; width: 10mm;">Page</div>
                  <div style="float: left; width: 3mm;font-weight: bold">1</div>
                  <div style="float: left; width: 8mm;">of</div>
                  <div style="float: left; width: 3mm;font-weight: bold">1</div>
              </div>
          </div>
<#else>
// 如果数据为空,打印空表头,和必填数据。 start


 <#if items_index == 0>
    <div class="header"  style="margin-top: 5mm;">
        <div style="float: right; text-align: center; height: 15mm; width: 50mm;">
            <img src="../logo.png" alt="" style="width: 22mm; height: 13mm;" />
            <div style="font-size: 11pt; font-weight: bold; font-family: 'SimSun'">乐信(上海)贸易有限公司</div>
        </div>
        <!-- 标题 -->
        <div style="font-size: 24pt; font-family: 'Arial'; text-align: center; padding-top: 15mm;">
            Billing Report
        </div>
    </div>
 </#if>

        <!-- 表头 -->

        <div style="margin-top: 5mm;">
		<#if items.flag=="F">
			<div style="font-size: 9pt; font-family: 'SimSun';margin-left: 20mm; margin-top: 5mm;">

                <div style="height: 7mm">
                    <div style="float: left; width: 30mm;">测试:</div>
                    <div style="float: left; width: 45mm;">测试数据</div>
                </div>
               
                </div>
            </div>

        </#if>
        <#--遍历数据(列表数据)-->

            <table id="container-table">
                <tr class="table-header">
                    <th style="width: 15mm;">测试</th>
                   
           
                </tr>
		    <#list items.list as itemValue>
          <tr>
             
              <td style="text-align: right;">测试数据</td>
              
          </tr>
            </#list>
            </table>


            <div style="font-weight: bold; font-size: 8pt; float: right; margin-right: 2mm; margin-top: 3mm;text-align: center">
                <div style="float: left; width: 10mm;">Page</div>
                <div style="float: left; width: 3mm;font-weight: bold">${(items_index)+1}</div>
                <div style="float: left; width: 8mm;">of</div>
                <div style="float: left; width: 3mm;font-weight: bold">${totalPage}</div>
            </div>
        </div>
        <#if ((items_index)+1) lt totalPage>
    <div class="pageBreak"></div>
        </#if>
            </#if>
    </#list>
    </div>

</div>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/qq_35193093/article/details/87717863