利用apache-pdfbox库修改pdf文件模板,进行信息替换
public String createSignFile(Long id) throws IOException {
// 1.验证企业信息
CompanyDO company = validateCompanyExists(id);
// 2.验证签约状态
if(company.getSignStatus()!=0){
throw exception(COMPANY_SIGN_STATUS_NOT_ZERO);
}
// 3.获取合同模板(合同模板有独立模板管理板块)
String enterType = company.getEnterCompanyType()==1?"franchisee_enter":"service_provider_enter";
AgreementRespDTO agreementDTO = operateAgreementApi.getAgreementByType(enterType);
if(agreementDTO==null){
throw exception(COMPANY_AGREEMENT_NOT_EXISTS);
}
String templatePath = agreementDTO.getFile();
// 4.设定合同参数
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日");
String currentDate = sdf.format(new Date());
Map<String, String> data = new HashMap<>();
data.put("companyName", company.getName());
data.put("secrecyInfo", "无");
data.put("yearLimit", "一");
data.put("StartDate", currentDate);
// 5.生成合同文件
// 5.1加载 pdf 模板和字体库文件
//适用于本地资源路径(本地用于调试,信息为e:/file.pdf)
// FileInputStream fis = new FileInputStream(templatePath);
// 采用网络资源路径(系统中采用oss对象存储,所以获取的是网络路径)
URL url = new URL(templatePath);
URLConnection connection = url.openConnection();
InputStream fis = connection.getInputStream();
// 字体文件【华文仿宋】,可以自己换字体库
URL fontUrl = new URL("https://你自己的地址.oss-cn-beijing.aliyuncs.com/stfangso.ttf");
URLConnection fontConnection = fontUrl.openConnection();
InputStream fontFile = fontConnection.getInputStream();
// 开始读取
//============ pdf 文件读取处理 ===============
PDDocument pdf = PDDocument.load(fis);
Map<COSName, PDFont> oldfont = new HashMap<COSName, PDFont>();
COSName fontName = null;
PDType0Font targetfont= PDType0Font.load(pdf,fontFile);
for (PDPage page : pdf.getPages()) {
PDFStreamParser pdfsp = new PDFStreamParser(page);
pdfsp.parse();
List<Object> tokens = pdfsp.getTokens();
for (int j = 0; j < tokens.size(); j++) {
//创建一个object对象去接收标记
Object next = tokens.get( j );
//instanceof判断其左边对象是否为其右边类的实例
if(next instanceof COSName) {
fontName= (COSName)next;
if(!oldfont.containsKey(fontName)) {
oldfont.put(fontName, page.getResources().getFont(fontName));
}
}else
if(next instanceof COSString) {
COSString previous = (COSString)next;
try(InputStream in = new ByteArrayInputStream(previous.getBytes())){
StringBuffer sb = new StringBuffer();
while (in.available()>0) {
int rc = oldfont.get(fontName).readCode(in);
sb.append(oldfont.get(fontName).toUnicode(rc));
}
//重置COSString对象
previous.setValue(targetfont.encode(sb.toString()));
}
}else if(next instanceof COSArray) {
//PDF中的字符串
byte[] pstring = {};
int prej = 0;
COSArray previous =(COSArray)next;
// //循环previous
for (int k = 0; k < previous.size(); k++) {
Object arrElement = previous.getObject( k );
if( arrElement instanceof COSString ){
//COSString对象>>创建java字符串的一个新的文本字符串。
COSString cosString =(COSString)arrElement;
//将此字符串的内容作为PDF文本字符串返回。
if (j == prej) {
byte[] thisbyte = cosString.getBytes();
byte[] temp = new byte[pstring.length+thisbyte.length];
System.arraycopy(pstring, 0, temp, 0, pstring.length);
System.arraycopy(thisbyte, 0, temp, pstring.length, thisbyte.length);
pstring=temp;
} else {
prej = j;
pstring = cosString.getBytes();
}
}
}
try(InputStream in = new ByteArrayInputStream(pstring)){
StringBuffer sb = new StringBuffer();
while (in.available()>0) {
int rc = oldfont.get(fontName).readCode(in);
sb.append(oldfont.get(fontName).toUnicode(rc));
}
String str =sb.toString();
for (Map.Entry<String, String> entry : data.entrySet()) {
String key = "${" + entry.getKey() + "}";
if (str.contains(key)) {
str = str.replace(key, entry.getValue() != null ? entry.getValue() : "");
break;
}
}
COSString cosString2 = (COSString) previous.getObject(0);
cosString2.setValue(targetfont.encode(str));
}
int total = previous.size()-1;
for (int k = total; k > 0; k--) {
previous.remove(k);
}
}
}
PDStream updatedStream = new PDStream(pdf);
OutputStream out = updatedStream.createOutputStream();
ContentStreamWriter tokenWriter = new ContentStreamWriter(out);
tokenWriter.writeTokens(tokens);
out.close();
oldfont.forEach((k,v)->{
page.getResources().put(k, targetfont);
});
page.setContents(updatedStream);
}
//保存到本地中(主要用于调试)
//pdf.save("d:/1.pdf");
//pdf.close();
//将文件直接保存上传(由于生成后,前台展示所以要直接上传获取上传地址进行前台回显)
ByteArrayOutputStream out = new ByteArrayOutputStream();
pdf.save(out);
pdf.close();//记得关闭资源哦
// 将输出流的内容转换为Base64编码的字符串
byte[] bytes = out.toByteArray();
String pdfUrl =fileApi.createFile(bytes);
// 将上传后的文件,存到数据库中
companyMapper.updateById(new CompanyDO().setId(id).setSignFileUrl(pdfUrl));
return pdfUrl;
}
该板块主要用于利用模板生成入驻企业的合同信息,便于在线发起合同签署功能。
采用了模板的变量替换方式,需要将变量信息预先插入到模板的指定位置。