版权声明: 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>