前言
最近做一个导出pdf功能记录下,尝试了以下两种方式,个人感觉第一种适合特定规格的数据内容,样式又比较多,严格的再加个水印,当然用第二种也能实现,就是每个样式包括水印都要自己代码实现可能会没那么快。做的时候两种方式都遇到了多行文本换行的问题,好在都解决了。第一种就是文本栏(ColumnText)循环写入,注意赋值后每次都要调用columnText.go(),将行数据输出到文档中,就可以实现换行,第二种每个单元格(PdfPCell)利用它的addElement方式,添加元素Chunk对象,循环添加换行文本就可以了。我要实现的功能模板比较简单,但是内容需要自适应高度,内容长度不确定采取第一种方式会丢失部分内容,所以用的第二种方式。
1、模板方式导出
- 首先制定word模板如图:
- 做好之后另存为pdf格式
- 使用Adobe Acrobat XI Pro工具编辑pdf添加表单,可以设置默认属性,字体大小等
- 代码实现装填参数并导出
之前需要在pom文件种引入以下jar包
<!--pdf模板导出-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.5.6</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
模板导出的方法代码,字体一定要设定不然不会显示中文
public static void fillTemplate(Map<String, Object> o, Map<String, Object> outLine, Map<String, Object> images, String templatePath, String filename, HttpServletResponse response) throws Exception {
OutputStream out = null;
PdfReader reader=null;
ByteArrayOutputStream bos=null;
PdfStamper stamper=null;
try {
//输出到浏览器
// 设置响应头
filename = URLEncoder.encode(filename, "UTF-8");
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment;fileName=" + filename);
out = response.getOutputStream();
// 读取pdf模板
reader = new PdfReader(templatePath);
bos = new ByteArrayOutputStream();
stamper = new PdfStamper(reader, bos);
AcroFields form = stamper.getAcroFields();
// 文字类的内容处理
java.util.Iterator<String> it = form.getFields().keySet().iterator();
//文本处理
while (it.hasNext()) {
String name = it.next().toString();
String oname = name.replace("${", "").replace("}", "");
String value = o.get(oname) != null ? o.get(oname).toString() : "";
System.out.println(oname + "=" + value);
//使用自定义基础字体
// form.setFieldProperty(name, "textfont", bfChinese, null);
//文本域自定义换行处理
if(!oname.contains("term")&&!oname.contains("week")&&!EmptyUtil.isEmpty(outLine) && (!EmptyUtil.isEmpty(outLine.get(oname)) || !EmptyUtil.isEmpty(outLine.get("*")) )){
// 设置字体样式
List<AcroFields.FieldPosition> multiLinePosition = form.getFieldPositions(name);
int page = multiLinePosition.get(0).page;
Rectangle rectangle = multiLinePosition.get(0).position;
PdfContentByte pdfContentByte = stamper.getOverContent(page);
ColumnText columnText = new ColumnText(pdfContentByte);
columnText.setSimpleColumn(rectangle);
Font f= getFont("5");
///t是标识多行文本的需要换行的标识符号
if(!EmptyUtil.isEmpty(value)&&value.contains("/t")){
//循环写入-这种可以实现文本换行
for(String s:value.split("/t")){
Paragraph paragraph = new Paragraph();
paragraph.setFont(f);
paragraph.add(new Phrase(s));
columnText.addText(paragraph);
columnText.addElement(paragraph);
columnText.go();
}
}else{
Paragraph paragraph = new Paragraph();
paragraph.setFont(f);
paragraph.add(new Phrase(value));
columnText.addElement(paragraph);
columnText.addText(paragraph);
columnText.go();
}
}else{
form.setField(name, value);
}
}
// 图片类的内容处理 根据表单域 左下角点定位
if(!EmptyUtil.isEmpty(images)){
for (String key : images.keySet()) {
String value = images.get(key).toString();
String imgpath = value;
if (!EmptyUtil.isEmpty(form.getFieldPositions(key))) {
int pageNo = form.getFieldPositions(key).get(0).page;
Rectangle signRect = form.getFieldPositions(key).get(0).position;
float x = signRect.getLeft();
float y = signRect.getBottom();
// 根据路径读取图片
Image image = Image.getInstance(imgpath);
// 获取图片页面
PdfContentByte under = stamper.getOverContent(pageNo);
//图片按照表单框大小
image.scaleAbsolute(signRect.getWidth(), signRect.getHeight());
// 图片大小自适应
//image.scaleToFit(signRect.getWidth(), signRect.getHeight());
// 添加图片
image.setAbsolutePosition(x, y);
under.addImage(image);
}
}
}
// 如果为false,生成的PDF文件可以编辑,如果为true,生成的PDF文件不可以编辑
stamper.setFormFlattening(true);
stamper.close();
Document doc = new Document();
PdfCopy copy = new PdfCopy(doc, out);
doc.open();
int pageNum = reader.getNumberOfPages();
for (int i = 1; i <= pageNum; i++) {
PdfImportedPage importPage = copy.getImportedPage(new PdfReader(bos.toByteArray()), i);
copy.addPage(importPage);
}
doc.close();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
if (out != null) {
out.flush();
out.close();
}
if (reader != null) {
reader.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 根据编号 i 获取字体样式 以后可以按照需求增加
* @param i
* @return
*/
public static Font getFont(String i) throws IOException, DocumentException {
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
Font FontChinese1 ;
switch (i){
case "1" :FontChinese1= new Font(bfChinese, 18, Font.BOLD);
break;
case "2" :FontChinese1= new Font(bfChinese, 12, Font.BOLD);
break;
case "3" :FontChinese1= new Font(bfChinese, 8, Font.BOLD);
break;
case "4" :FontChinese1= new Font(bfChinese, 24, Font.NORMAL);
break;
case "5" :FontChinese1= new Font(bfChinese, 9, Font.NORMAL);
break;
case "10" :FontChinese1= new Font(bfChinese, 10, Font.NORMAL);
break;
case "6" :FontChinese1= new Font(bfChinese, 8, Font.NORMAL);
break;
default:FontChinese1=null;
}
return FontChinese1;
}
业务数据封装省略了,mapData为业务数据,参数和pdf模板字段对应
//需要填充参数的 字体样式
Map<String,Object> outLinemap=new HashMap<>();
outLinemap.put("*","4");
//生成PDF文件的文件名
String fileName="工作安排"+ UUID.randomUUID()+".pdf";
//导出pdf文件
String filePath = getRequest().getRealPath("/WEB-INF/classes/static/pdf/job.pdf");
PDFUtil.fillTemplate(mapData,outLinemap,null,filePath,fileName,getResponse());
以下是效果图:
文本内容太多会显示不全,超出的会丢失
2、纯代码方式导出
这个就没啥繁琐步骤了直接写代码就好了
public static void download(List<Map<String,String>> list, Map<String, String> mapData, HttpServletResponse response) throws IOException {
Document document = new Document();
document.setMargins(70, 70, 20, 20);
try {
Font content = content = getFont("10");
PdfWriter.getInstance(document,response.getOutputStream());
//打开生成的pdf文件
document.open();
//设置内容
Paragraph paragraph = new Paragraph("一周工作安排", getFont("4"));
paragraph.setAlignment(1);
//引用字体
document.add(paragraph);
document.add(new Paragraph("\n", getFont("4")));
Paragraph paragraph0 = new Paragraph(mapData.get("term"), content);
paragraph0.setAlignment(Element.ALIGN_RIGHT);
document.add(paragraph0);
//设置每页大小
document.setPageSize(new RectangleReadOnly(595.0F, 600.0F));
PdfPCell cell = null;
// 设置表格的列宽和列数
float[] widths2 = {15f,15f,45f,30f,30f};
PdfPTable table = new PdfPTable(widths2);
table.setSpacingBefore(10f);
// 设置表格宽度为100%
table.setWidthPercentage(100.0F);
table.setHeaderRows(1);
table.getDefaultCell().setHorizontalAlignment(1);
//表头
cell = new PdfPCell(new Paragraph("星期",content));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
cell.setFixedHeight(50);
table.addCell(cell);
cell = new PdfPCell(new Paragraph("日期",content));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell(new Paragraph("工作内容",content));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell(new Paragraph("地点",content));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
cell = new PdfPCell(new Paragraph("负责部门",content));
cell.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(cell);
//遍历一周安排数据
for (Map<String,String> data : list) {
PdfPCell cell1 = new PdfPCell(new Paragraph(data.get("week"), content));
PdfPCell cell2 = new PdfPCell(new Paragraph(data.get("date"), content));
PdfPCell cell3 = new PdfPCell();
///n为自定义换行符号-没有特殊含义 if(!EmptyUtil.isEmpty(data.get("content"))&&data.get("content").contains("/n")){
for(String s:data.get("content").split("/n")){
cell3.addElement(new Chunk(s,content));
}
}
PdfPCell cell4 =new PdfPCell();
if(!EmptyUtil.isEmpty(data.get("address"))&&data.get("address").contains("/n")){
for(String s:data.get("address").split("/n")){
cell4.addElement(new Chunk(s,content));
}
}
PdfPCell cell5 =new PdfPCell();
if(!EmptyUtil.isEmpty(data.get("dept"))&&data.get("dept").contains("/n")){
for(String s:data.get("dept").split("/n")){
cell5.addElement(new Chunk(s,content));
}
}
//单元格对齐方式
cell1.setHorizontalAlignment(Element.ALIGN_CENTER);
cell1.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell1.setFixedHeight(40);
//单元格垂直对齐方式
cell2.setHorizontalAlignment(Element.ALIGN_CENTER);
cell2.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell3.setHorizontalAlignment(Element.ALIGN_CENTER);
cell3.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell4.setHorizontalAlignment(Element.ALIGN_CENTER);
cell4.setVerticalAlignment(Element.ALIGN_MIDDLE);
cell5.setHorizontalAlignment(Element.ALIGN_CENTER);
cell5.setVerticalAlignment(Element.ALIGN_MIDDLE);
table.addCell(cell1);
table.addCell(cell2);
table.addCell(cell3);
table.addCell(cell4);
table.addCell(cell5);
}
PdfPCell cellLeft = new PdfPCell(new Paragraph("备注", content));
cellLeft.setFixedHeight(40);
cellLeft.setVerticalAlignment(Element.ALIGN_MIDDLE);
cellLeft.setHorizontalAlignment(Element.ALIGN_CENTER);
PdfPCell cellRight = new PdfPCell(new Paragraph(mapData.get("remark"), content));
cellRight.setVerticalAlignment(Element.ALIGN_MIDDLE);
cellRight.setHorizontalAlignment(Element.ALIGN_CENTER);
cellRight.setColspan(4);
table.addCell(cellLeft);
table.addCell(cellRight);
// document.add(new Paragraph("\n"));
// document.add(new Paragraph("▋ 信息",content));
// document.add(new Paragraph("\n"));
//
document.add(table);
//关闭文档
document.close();
} catch (DocumentException e) {
e.printStackTrace();
}
}
List<Map<String,String>>outData=new ArrayList<>(); Map<String,
String> otherData = new HashMap<>(); outData和otherData 是业务数据集合
// 设置编码格式
response.setContentType("application/pdf;charset=UTF-8");
response.setCharacterEncoding("utf-8");
String fileName = URLEncoder.encode(mapData.get("term"), "UTF-8");
response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".pdf");
PDFUtil.download(outData,otherData, response);
效果图