在这里插入代码片
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.9</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.5.9</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>org.xhtmlrenderer</groupId>
<artifactId>flying-saucer-pdf-itext5</artifactId>
<version>9.0.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/freemarker/freemarker -->
<dependency>
<groupId>freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.9</version>
</dependency>
import lombok.Data;
import java.util.List;
/**
* @description:
* @author: sy0025
* @create: 2019-09-06
*/
@Data
public class PdfParam {
private String yearNumber;
private String symbol;
private String subject;
/**
*发文对象
*/
private String callName;
/**
*发文落款年
*/
private String year;
/**
*发文落款月
*/
private String month;
/**
*发文落款日
*/
private String day;
private List<TableVo> trs;
private String internarSending;
@Data
public static class TableVo{
private String employeeId;
private String name;
private String squence;
private String squenceLevel;
}
}
import com.china.ccd.oa.hrtransfer.model.bo.PdfParam;
import com.itextpdf.text.BaseColor;
import com.itextpdf.text.Document;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfWriter;
import com.itextpdf.tool.xml.XMLWorkerFontProvider;
import com.itextpdf.tool.xml.XMLWorkerHelper;
import freemarker.template.Configuration;
import freemarker.template.DefaultObjectWrapper;
import freemarker.template.Template;
import java.io.BufferedWriter;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class PDFUtil {
public static void main(String[] args) {
PdfParam pdfParam = new PdfParam();
pdfParam.setYearNumber("2019");
pdfParam.setSymbol("38");
pdfParam.setSubject("XXXXX");
pdfParam.setCallName("XXXXX");
pdfParam.setYear("2019");
pdfParam.setMonth("09");
pdfParam.setDay("06");
List<PdfParam.TableVo> tabs = new ArrayList<>();
PdfParam.TableVo table = new PdfParam.TableVo();
table.setEmployeeId("660579");
table.setName("test");
table.setSquence("通用序列-xxxxx");
table.setSquenceLevel("高级四级");
tabs.add(table);
PdfParam.TableVo table2 = new PdfParam.TableVo();
table2.setEmployeeId("660579");
table2.setName("test");
table2.setSquence("通用序列-xxxx");
table2.setSquenceLevel("高级四级");
tabs.add(table2);
pdfParam.setTrs(tabs);
pdfParam.setInternarSending("xxx会,xxx总经理室,xxx办公室,xxx人力资源部,xxx计划财务部,xxx监察保卫部,xxxx法律合规部。");
PDFUtil pdfUtil = new PDFUtil();
System.out.println(pdfUtil.createPdf(pdfParam));
/*
String name = buildHtml();
PDFUtil pdfUtil = new PDFUtil("C:\\\\Users\\\\itw00100\\\\Desktop", name);
PdfParam pdfParam = new PdfParam();
pdfParam.setYearNumber("2019");
pdfParam.setSymbol("38");
pdfParam.setSubject("XXXXX");
pdfParam.setCallName("XXXXX");
pdfParam.setYear("2019");
pdfParam.setMonth("09");
pdfParam.setDay("06");
List tabs = new ArrayList<>();
PdfParam.TableVo table = new PdfParam.TableVo();
table.setEmployeeId("660579");
table.setName("test");
table.setSquence("通用序列-xxx");
table.setSquenceLevel("高级四级");
tabs.add(table);
PdfParam.TableVo table2 = new PdfParam.TableVo();
table2.setEmployeeId("660579");
table2.setName("test");
table2.setSquence("通用序列-xxxx");
table2.setSquenceLevel("高级四级");
tabs.add(table2);
pdfParam.setTabs(tabs);
System.out.println(pdfParam);
Map paraMap = new HashMap();
paraMap.put("yearNumber", pdfParam.getYearNumber());
paraMap.put("symbol", pdfParam.getSymbol());
paraMap.put("subject", pdfParam.getSubject());
paraMap.put("callName", pdfParam.getCallName());
paraMap.put("year", pdfParam.getYear());
paraMap.put("month", pdfParam.getMonth());
paraMap.put("day", pdfParam.getDay());
List tableVoList = pdfParam.getTabs();
StringBuffer sb = new StringBuffer();
for(PdfParam.TableVo tableVo :tableVoList){
sb.append("\n" +
" \n" +
" "+tableVo.getEmployeeId()+"
\n" +
" \n" +
" \n" +
" "+tableVo.getName()+"
\n" +
" \n" +
" \n" +
" "+tableVo.getSquence()+"
\n" +
" \n" +
" \n" +
" "+tableVo.getSquenceLevel()+"
\n" +
" \n" +
" ");
}
paraMap.put("tabs", sb.toString());
try {
String uploadfile = pdfUtil.fillTemplate(paraMap);
System.out.println(uploadfile);
} catch (Exception e) {
e.printStackTrace();
}
*/
}
/**
* 生成pdf
* @param pdfParam
* @return
*/
public String createPdf(PdfParam pdfParam){
String tmpPath = "C:\\Users\\itw00100\\Desktop" + "\\temp";
File tmepFilePath = new File(tmpPath);
if (!tmepFilePath.exists()) {
tmepFilePath.mkdirs();
}
String tmpFileName = System.currentTimeMillis() + ".pdf";
String outputFile = tmpPath + File.separatorChar + tmpFileName;
FileOutputStream outFile = null;
try {
outFile = new FileOutputStream(outputFile);
String itneralSendHtml = "
" +
"
" +
"
" +
"
" +
"
\n" +
"内部发送:"
+pdfParam.getInternarSending()+"\n" +
"
";
createPDFFile(buildHtml(pdfParam),itneralSendHtml, outFile);
} catch (FileNotFoundException e) {
e.printStackTrace();
}catch (Exception e){
e.printStackTrace();
}
return outputFile;
}
/**
* 直接构建html模板
* @param pdfParam
* @return
*/
public String buildHtml(PdfParam pdfParam){
List<PdfParam.TableVo> tableVoList = pdfParam.getTrs();
StringBuffer trs = new StringBuffer();
for(PdfParam.TableVo tableVo :tableVoList){
trs.append("\n" +
" \n" +
" "
+tableVo.getEmployeeId()+"\n" +
" \n" +
" \n" +
" "
+tableVo.getName()+"\n" +
" \n" +
" \n" +
" "
+tableVo.getSquence()+"\n" +
" \n" +
" \n" +
" "
+tableVo.getSquenceLevel()+"\n" +
" \n" +
" ");
}
StringBuffer htmlTemplete = new StringBuffer();
htmlTemplete.append("\n" +
"\n" +
"\n" +
" \n" +
" \n" +
"\n" +
"\n" +
"XXX
\n" +
"xxxxx中心 (XXX部)\n"
+
"\n" +
"
\n" +
"xxxx人部字〔"
+pdfParam.getYearNumber()+"〕"+pdfParam.getSymbol()+"号\n" +
"
\n" +
"\n" +
"\n" +
"\n" +
"xxxx中心人力资源部
\n" +
"关于"
+pdfParam.getSubject()+"人员序列聘任的通知\n" +
"\n" +
"\n" +
"\n" +
""
+pdfParam.getCallName()+":\n" +
"经研究决定:
\n" +
""
+pdfParam.getSubject()+"人员序列聘任结果如下:\n" +
"\n" +
" \n" +
" \n" +
" \n" +
" 员编
\n" +
" \n" +
" \n" +
" 姓名
\n" +
" \n" +
" \n" +
" 通道/序列
\n" +
" \n" +
" \n" +
" 序列等级
\n" +
" \n" +
" \n" +
""+trs.toString()+""+
"\n" +
"
\n" +
"XXX部
\n" +
""
+pdfParam.getYear()+"年"+pdfParam.getMonth()+"月"+pdfParam.getDay()+"日\n" +
"\n" +
"");
return htmlTemplete.toString();
}
/**
* 构建framker模板
* @return
*/
public static String buildHtml() {
StringBuffer htmlTemplete = new StringBuffer();
htmlTemplete.append("\n" +
"\n" +
"\n" +
" \n" +
" \n" +
"\n" +
"\n" +
"xxx
\n" +
"<h1 style=\"text-align:center;font-weight: bold;font-family:方正小标宋简体\">
<span style=\"display:inline;font-size:21.3px;font-family:仿宋_GB2312\">(人力资源部)\n" +
"\n" +
"
\n" +
"XXX人部字〔${yearNumber}〕${symbol}号
\n" +
"
\n" +
"\n" +
"\n" +
"\n" +
"xxxx人力资源部
\n" +
"关于${subject}人员序列聘任的通知
\n" +
"\n" +
"\n" +
"\n" +
"${callName}:
\n" +
"经研究决定:
\n" +
"${subject}人员序列聘任结果如下:
\n" +
"\n" +
" \n" +
" \n" +
" \n" +
" 员编
\n" +
" \n" +
" \n" +
" 姓名
\n" +
" \n" +
" \n" +
" 通道/序列
\n" +
" \n" +
" \n" +
" 序列等级
\n" +
" \n" +
" \n" +
"${tabs}"+
"\n" +
"
\n" +
"xxx人力资源部
\n" +
"${year}年${month}月${day}日
\n" +
"\n" +
"");
String pdfTempleteName = "pdfTemplete.html";
PDFUtil pdfUtil = new PDFUtil("C:\\Users\\itw00100\\Desktop", "pdfTemplete.html");
pdfUtil.createdHtmlTemplate(htmlTemplete.toString());
return pdfTempleteName;
}
/*
* 填充模板
* @param paramMap
* @throws Exception
*/
public String fillTemplate(Map<String, Object> paramMap) throws Exception {
File modelFile = new File(tempFilePath);
if (!modelFile.exists()) {
modelFile.mkdirs();
}
Configuration configuration = new Configuration();
configuration.setDirectoryForTemplateLoading(modelFile);
configuration.setObjectWrapper(new DefaultObjectWrapper());
configuration.setDefaultEncoding("UTF-8");
//获取或创建一个模版。
Template template = configuration.getTemplate(tempFileName);
StringWriter stringWriter = new StringWriter();
BufferedWriter writer = new BufferedWriter(stringWriter);
template.process(paramMap, writer); //把值写进模板
String htmlStr = stringWriter.toString();
writer.flush();
writer.close();
String tmpPath = tempFilePath + "/temp";
File tmepFilePath = new File(tmpPath);
if (!tmepFilePath.exists()) {
tmepFilePath.mkdirs();
}
String tmpFileName = System.currentTimeMillis() + ".pdf";
String outputFile = tmpPath + File.separatorChar + tmpFileName;
FileOutputStream outFile = new FileOutputStream(outputFile);
createPDFFile(htmlStr,"", outFile);
return outputFile;
}
/**
* 根据HTML字符串创建PDF文件
*
* @param htmlStr
* @param os
* @throws Exception
*/
private void createPDFFile(String htmlStr,String appendHtml, OutputStream os) throws Exception {
ByteArrayInputStream bais = new ByteArrayInputStream(htmlStr.getBytes("UTF-8"));
Document document = new Document(PageSize.A4);
try {
PdfWriter writer = PdfWriter.getInstance(document, os);
PDFBuilder builder = new PDFBuilder();
writer.setPageEvent(builder);
document.open();
FontProvider provider = new FontProvider();
XMLWorkerHelper.getInstance().parseXHtml(writer, document, bais, Charset.forName("UTF-8"), provider);
//新起一页追加内容
document.newPage();
//document.add(new Paragraph("New page"));
ByteArrayInputStream bais2 = new ByteArrayInputStream(appendHtml.getBytes("UTF-8"));
XMLWorkerHelper.getInstance().parseXHtml(writer, document, bais2, Charset.forName("UTF-8"), provider);
} catch (Exception e) {
e.printStackTrace();
throw e;
} finally {
try {
document.close();
} catch (Exception e) {
e.printStackTrace();
}
try {
bais.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 字体
*/
private class FontProvider extends XMLWorkerFontProvider {
@Override
public Font getFont(final String fontname, final String encoding,
final boolean embedded, final float size, final int style,
final BaseColor color) {
BaseFont bf = null;
try {
if(fontname == null){
bf = BaseFont.createFont("/public/assets/fonts/" + "simhei" + ".ttf", BaseFont.IDENTITY_H , BaseFont.EMBEDDED);
}else{
bf = BaseFont.createFont("/public/assets/fonts/" + fontname + ".ttf", BaseFont.IDENTITY_H , BaseFont.EMBEDDED);
}
} catch (Exception e) {
e.printStackTrace();
}
Font font = new Font(bf, size, style, color);
font.setColor(color);
return font;
}
}
/**
* 生成html模板
*
* @param content
* @return
*/
public String createdHtmlTemplate(String content) {
String fileName = tempFilePath + "/" + tempFileName;
try {
File file = new File(tempFilePath);
if (!file.isDirectory()) {
file.mkdir();
}
file = new File(fileName);
if (!file.isFile()) {
file.createNewFile();
}
//打开文件
PrintStream printStream = new PrintStream(new FileOutputStream(fileName), true, "UTF-8");
//将HTML文件内容写入文件中
printStream.println(content);
printStream.flush();
printStream.close();
System.out.println("生成html模板成功!");
} catch (Exception e) {
e.printStackTrace();
}
return fileName;
}
private String tempFilePath;
private String tempFileName;
public PDFUtil() {
}
public PDFUtil(String tempFilePath, String tempFileName) {
this.tempFilePath = tempFilePath;
this.tempFileName = tempFileName;
}
public String getTempFilePath() {
return tempFilePath;
}
public void setTempFilePath(String tempFilePath) {
this.tempFilePath = tempFilePath;
}
public String getTempFileName() {
return tempFileName;
}
public void setTempFileName(String tempFileName) {
this.tempFileName = tempFileName;
}
}
import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.PageSize;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.ColumnText;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfPageEventHelper;
import com.itextpdf.text.pdf.PdfTemplate;
import com.itextpdf.text.pdf.PdfWriter;
import java.io.IOException;
/**
* 设置页面附加属性
*
*/
public class PDFBuilder extends PdfPageEventHelper {
/**
* 页眉
*/
public String header = "";
/**
* 文档字体大小,页脚页眉最好和文本大小一致
*/
public int presentFontSize = 12;
/**
* 文档页面大小,最好前面传入,否则默认为A4纸张
*/
public Rectangle pageSize = PageSize.A4;
// 模板
public PdfTemplate total;
// 基础字体对象
public BaseFont bf = null;
// 利用基础字体生成的字体对象,一般用于生成中文文字
public Font fontDetail = null;
/**
*
* Creates a new instance of PdfReportM1HeaderFooter 无参构造方法.
*
*/
public PDFBuilder() {
}
/**
*
* Creates a new instance of PdfReportM1HeaderFooter 构造方法.
*
* @param yeMei
* 页眉字符串
* @param presentFontSize
* 数据体字体大小
* @param pageSize
* 页面文档大小,A4,A5,A6横转翻转等Rectangle对象
*/
public PDFBuilder(String yeMei, int presentFontSize, Rectangle pageSize) {
this.header = yeMei;
this.presentFontSize = presentFontSize;
this.pageSize = pageSize;
}
public void setHeader(String header) {
this.header = header;
}
public void setPresentFontSize(int presentFontSize) {
this.presentFontSize = presentFontSize;
}
/**
*
* TODO 文档打开时创建模板
*
* @see PdfPageEventHelper#onOpenDocument(PdfWriter,
* Document)
*/
@Override
public void onOpenDocument(PdfWriter writer, Document document) {
total = writer.getDirectContent().createTemplate(50, 50);// 共 页 的矩形的长宽高
}
/**
*
* TODO 关闭每页的时候,写入页眉,写入'第几页共'这几个字。
*
* @see PdfPageEventHelper#onEndPage(PdfWriter,
* Document)
*/
@Override
public void onEndPage(PdfWriter writer, Document document) {
this.addPage(writer, document);
}
//加分页
public void addPage(PdfWriter writer, Document document){
try {
if (bf == null) {
bf = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", false);
}
if (fontDetail == null) {
fontDetail = new Font(bf, presentFontSize, Font.NORMAL);// 数据体字体
}
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// 1.写入页眉
ColumnText.showTextAligned(writer.getDirectContent(),
Element.ALIGN_LEFT, new Phrase(header, fontDetail),
document.left(), document.top() + 20, 0);
// 2.写入前半部分的 第 X页/共
int pageS = writer.getPageNumber();
String foot1 = "第 " + pageS + " 页/共";
Phrase footer = new Phrase(foot1, fontDetail);
// 3.计算前半部分的foot1的长度,后面好定位最后一部分的'Y页'这俩字的x轴坐标,字体长度也要计算进去 = len
float len = bf.getWidthPoint(foot1, presentFontSize);
// 4.拿到当前的PdfContentByte
PdfContentByte cb = writer.getDirectContent();
// 5.写入页脚1,x轴就是(右margin+左margin + right() -left()- len)/2.0F
// 再给偏移20F适合人类视觉感受,否则肉眼看上去就太偏左了
// ,y轴就是底边界-20,否则就贴边重叠到数据体里了就不是页脚了;注意Y轴是从下往上累加的,最上方的Top值是大于Bottom好几百开外的。
// ColumnText
// .showTextAligned(
// cb,
// Element.ALIGN_CENTER,
// footer,
// (document.rightMargin() + document.right()
// + document.leftMargin() - document.left() - len) / 2.0F + 20F,
// document.bottom() - 20, 0);
// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
// len , y 轴和之前的保持一致,底边界-20
// cb.addTemplate(total, (document.rightMargin() + document.right()
// + document.leftMargin() - document.left()) / 2.0F + 20F,
// document.bottom() - 20); // 调节模版显示的位置
// i % 2 == 0 ? "偶数" : "奇数";
if(pageS % 2 == 0){
ColumnText
.showTextAligned(
cb,
Element.ALIGN_CENTER,
footer,
document.left()+25F ,
document.bottom() - 20, 0);
// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
// len , y 轴和之前的保持一致,底边界-20
cb.addTemplate(total,
document.left()+25F ,
document.bottom() - 20); // 调节模版显示的位置
}else{
ColumnText
.showTextAligned(
cb,
Element.ALIGN_CENTER,
footer,
(document.rightMargin() + document.right()
+ document.leftMargin() - document.left() - len)-75F ,
document.bottom() - 20, 0);
// 6.写入页脚2的模板(就是页脚的Y页这俩字)添加到文档中,计算模板的和Y轴,X=(右边界-左边界 - 前半部分的len值)/2.0F +
// len , y 轴和之前的保持一致,底边界-20
cb.addTemplate(total, (document.rightMargin() + document.right()
+ document.leftMargin() - document.left())-75F,
document.bottom() - 20); // 调节模版显示的位置
}
}
/**
*
* TODO 关闭文档时,替换模板,完成整个页眉页脚组件
*
* @see PdfPageEventHelper#onCloseDocument(PdfWriter,
* Document)
*/
public void onCloseDocument(PdfWriter writer, Document document) {
// 7.最后一步了,就是关闭文档的时候,将模板替换成实际的 Y 值,至此,page x of y 制作完毕,完美兼容各种文档size。
total.beginText();
total.setFontAndSize(bf, presentFontSize);// 生成的模版的字体、颜色
String foot2 = " " + (writer.getPageNumber()) + " 页";
total.showText(foot2);// 模版显示的内容
total.endText();
total.closePath();
}
}
注:可以定义多种字体,需下载.ttf文件