是根据pdf模板生成的 ,pdf模板需配置文本域 ,这个可以去看下其他博客
这个是根据 itext 5.4
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.4.3</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>5.4.1</version>
</dependency>
目前提供了两个生成的方式,一个是直接导出,一个是生成到固定路径
util可直接使用,util包含字体大小自适应
package com.cfam.utils;
import com.cfam.config.BaseException;
import com.cfam.enums.RunExceptionEnum;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.pdf.*;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Map;
/**
* @Description: PDF生成
* @author:yjt
* @date:2021/10/12 10:34
*/
@Slf4j
public class PDFUtil {
/**
* 字体大小
*/
private static final float TEXT_SIZE = 6.3f;
/**
* 自适应字体大小
*/
private static final float TEXT_SIZE_ADAPT = 0f;
/**
* @param fontPath 字体路径
* @param templatePath 模板路径
* @param name 文件名称
* @param sourceMap 数据MAP
* @param response HttpServletResponse
* @Description: 导出PDF
* @Return: void
* @Author: yjt
* @Date: 2021/10/26
*/
public static void exportPdf(String fontPath, String templatePath, String name, Map<String, Object> sourceMap, HttpServletResponse response) {
OutputStream toClient = null;
try {
byte[] pdf = createPdf(fontPath, templatePath, sourceMap);
if (pdf == null) {
log.info("生成PDF字节数据为空");
throw new BaseException(RunExceptionEnum.PDF_CREATE_NULL);
}
//下载文件
response.reset();
// 设置response的Header
String fileName = URLEncoder.encode((name + "." + "pdf"), "UTF-8");
response.addHeader("Content-Disposition", "attachment;filename=" + fileName);
response.addHeader("Content-Length", "" + pdf.length);
toClient = new BufferedOutputStream(response.getOutputStream());
response.setContentType("application/octet-stream");
toClient.write(pdf);
toClient.flush();
toClient.close();
} catch (Exception e) {
log.error("exportPdf 异常 ==> ", e);
} finally {
try {
if (null != toClient) {
toClient.close();
}
} catch (Exception e) {
log.error("finally时 exportPdf 异常 ==> ", e);
}
}
}
/**
* @param fontPath 字体路径
* @param templatePath 模板路径
* @param filePath 生成文件路径
* @param fileName 生成文件名称
* @param sourceMap 数据MAP
* @Description: 根据路径生成PDF
* @Return: void
* @Author: yjt
* @Date: 2021/10/26
*/
public static void pathPdf(String fontPath, String templatePath, String filePath, String fileName, Map<String, Object> sourceMap) {
FileOutputStream fos = null;
try {
byte[] pdf = createPdf(fontPath, templatePath, sourceMap);
if (pdf == null) {
log.info("生成PDF字节数据为空");
throw new CustomException("生成PDF字节数据为空");
}
File path = new File(filePath);
if (!path.isDirectory()) {
path.mkdirs();
}
//最终生成的文件,
fos = new FileOutputStream(filePath + "\\" + fileName + "." + "pdf");
fos.write(pdf);
} catch (Exception e) {
log.error(" pathPdf 异常 ==> ", e);
} finally {
try {
if (null != fos) {
fos.close();
}
} catch (Exception e) {
log.error("finally时 pathPdf 异常 ==> ", e);
}
}
}
/**
* @param fontPath 字体路径
* @param templatePath 模板路径
* @param sourceMap 数据Map
* @Description: 创建pdf
* @Return: 返回一个数据字节数组
* @Author: yjt
* @Date: 2021/10/26
*/
public static byte[] createPdf(String fontPath, String templatePath, Map<String, Object> sourceMap) {
PdfStamper ps = null;
PdfReader reader = null;
ByteArrayOutputStream bos = null;
try {
// pdf模板所在路径
try {
reader = new PdfReader(templatePath);
} catch (IOException e) {
log.error("pdf 模板路径异常 ==> ", e);
throw new BaseException(RunExceptionEnum.PDF_TEMPLATES_PATH_NULL);
}
bos = new ByteArrayOutputStream();
ps = new PdfStamper(reader, bos);
//这是设置字体
BaseFont bf = BaseFont.createFont(fontPath, BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);
ArrayList<BaseFont> fontList = new ArrayList<>();
fontList.add(bf);
AcroFields fields = ps.getAcroFields();
fields.setSubstitutionFonts(fontList);
fillData(bf,fields, sourceMap);
//必须要调用这个,否则文档不会生成的
ps.setFormFlattening(true);
ps.close();
return bos.toByteArray();
} catch (Exception e) {
log.error("创建pdf 异常 ==> ", e);
} finally {
try {
if (null != ps) {
ps.close();
}
if (null != reader) {
reader.close();
}
if(null != bos){
bos.close();
}
} catch (Exception e) {
log.error("finally时 创建pdf 异常 ==> ", e);
}
}
return null;
}
/**
* 填充模板中的数据
*/
public static void fillData(BaseFont bf,AcroFields fields, Map<String, Object> dataMap) {
try {
for (String key : dataMap.keySet()) {
// 为字段赋值,注意字段名称是区分大小写的
String value = String.valueOf(dataMap.get(key));
fields.setFieldProperty(key, "textsize", getFontSize( bf, fields,key,value,TEXT_SIZE), null);
fields.setField(key, (null != value && !"".equals(value) ? value : "------"));
}
} catch (Exception e) {
log.error("pdf 数据放入异常 ==> ", e);
throw new BaseException(RunExceptionEnum.PDF_DATA_ERROR);
}
}
/**
* 获取字体大小
* @param bf 字体
* @param fields 通过方法调用或 FDF 合并查询和更改现有文档中的字段
* @param key 数据 key
* @param value 数据 value
* @param fontSize 字体要求大小
* @return 字体计算大小
*/
public static float getFontSize(BaseFont bf,AcroFields fields,String key,String value,float fontSize){
Rectangle position = null;
try {
position = fields.getFieldPositions(key).get(0).position;
} catch (Exception e) {
}
if(position != null){
// 文本框宽度
float textBoxWidth = position.getWidth();
// 文本框高度
float textBoxHeight = position.getHeight();
// 文本单行行高
float ascent = bf.getFontDescriptor(BaseFont.ASCENT,fontSize);
// baseFont渲染后的文字宽度
float textWidth = bf.getWidthPoint(value, fontSize);
if((textBoxWidth * textBoxHeight)/value.length() < (ascent*(textWidth/value.length())*1.7f)){
//TEXT_SIZE_ADAPT == 0f;
return TEXT_SIZE_ADAPT;
}
}
return fontSize;
}
}