pom文件
<!--依赖springboot-start中dependencyManagement的版本-->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>${freemarker.version}</version>
</dependency>
<!--itextpdf-->
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itextpdf</artifactId>
<version>5.3.4</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-asian</artifactId>
<version>5.2.0</version>
</dependency>
<dependency>
<groupId>com.itextpdf</groupId>
<artifactId>itext-pdfa</artifactId>
<version>5.5.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.itextpdf.tool</groupId>
<artifactId>xmlworker</artifactId>
<version>1.2.1</version>
</dependency>
<!--没有该包的话,会有中文显示问题-->
<dependency>
<groupId>com.lowagie</groupId>
<artifactId>itext</artifactId>
<version>2.1.7</version>
</dependency>
<!--xdocreport-->
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>org.apache.poi.xwpf.converter.pdf</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>fr.opensagres.xdocreport</groupId>
<artifactId>org.apache.poi.xwpf.converter.xhtml</artifactId>
<version>1.0.6</version>
</dependency>
java文件
import com.hanxiaozhang.constant.ContractConstant;
import com.hanxiaozhang.watermarkutil.PDFWatermarkPrint;
import com.hanxiaozhang.watermarkutil.WatermarkPrint;
import lombok.extern.slf4j.Slf4j;
import java.io.*;
import java.util.HashMap;
import java.util.Map;
/**
* 功能描述: <br>
* 〈word转pdf, pdf转word工具类测试〉
*
*/
@Slf4j
public class WordUtilTest {
public static void main(String[] args) throws Exception {
String docx = "D:\\test\\test.docx";
WordUtil.getInstance().execute(docx,"test",initData(),"test11");
}
/**
* 初始化docx文件中的变量数据
* @return
*/
public static Map initData() {
Map<String, String> data = new HashMap<>(4);
data.put("test", "tese");
return data;
}
}
@Slf4j
public class WordUtil {
/**
* 代表应用程序和URL之间的通信链接
*/
HttpURLConnection httpURLConnection = null;
/**
* 生成pdf路径名
*/
private String pdfName;
/**
* 添加水印的pdf路径名
*/
private String waterPdfName;
/**
* 文件上传到fast的地址
*/
private String fileUrl;
private File pdfFile;
private File waterPdfFile;
private static class Holder{
private final static WordUtil INSTANCE = new WordUtil();
}
private WordUtil() {
}
public static WordUtil getInstance() {
return Holder.INSTANCE;
}
/**
* 执行生成PDF文件
*/
public String execute(String fastUrl, String waterMark, Map<String, String> initPdfData, String fileName) {
this.fileUrl=null;
this.pdfName = CommonUtil.getDir() + fileName + "-" + DateUtil.format2() + ".pdf";
log.info("WordUtil--execute-pdfName: {}",pdfName);
this.waterPdfName = CommonUtil.getDir() + fileName + "-" + DateUtil.format2() + "-1.pdf";
log.info("WordUtil--execute-waterPdfName: {}",waterPdfName);
this.pdfFile = new File(pdfName);
this.waterPdfFile = new File(waterPdfName);
InputStream is = null;
try {
is = getInputStreamByPath(fastUrl);
// word 转 pdf
WordUtil.wordToPDF(is, initPdfData, pdfFile, ContractConstant.DOCX);
watermark(waterMark);
FileUtil.uploadFile(fileToByte(waterPdfFile), CommonUtil.getDir(), fileName +".pdf");
} catch (Exception e) {
log.error("wordToPDF『"+pdfName+"』", e);
} finally {
try {
if (is != null) {
is.close();
}
} catch (Exception e) {
log.error("关闭流异常", e);
}
}
log.info("返回生成pdf--execute-fileUrl{}",fileUrl);
return fileUrl;
}
/**
* word转pdf
*
* @param srcInput doc输入流
* @param data 需要替换的doc文档变量数据
* @param targetPdf pdf文件
* @param fileType doc或者docx
* @throws Exception
*/
public static void wordToPDF(InputStream srcInput, Map<String, String> data, File targetPdf, String fileType) throws Exception {
if (fileType.endsWith(ContractConstant.DOCX)) {
byte[] pdfData = bindDocxDataAndToPdf(srcInput, data);
FileUtils.writeByteArrayToFile(targetPdf, pdfData);
} else if (fileType.endsWith(ContractConstant.DOC)) {
byte[] pdfData = bindDocDataAndToPdf(srcInput, data);
FileUtils.writeByteArrayToFile(targetPdf, pdfData);
} else {
throw new RuntimeException("文件格式不正确");
}
}
/**
* 替换docx文件内容,并转换成PDF
*
* @param input docx文件流
* @param data 替换内容
* @return pdf文件流
* @throws Exception
*/
private static byte[] bindDocxDataAndToPdf(InputStream input, Map<String, String> data) throws Exception {
byte[] replacedContent = replaceDocxContent(input, data);
byte[] pdfData = docxToPdf(new ByteArrayInputStream(replacedContent));
return pdfData;
}
/**
* 替换doc文件内容,并转换成PDF
*
* @param input docx文件流
* @param data 替换内容
* @return pdf文件流
* @throws Exception
*/
private static byte[] bindDocDataAndToPdf(InputStream input, Map<String, String> data) throws Exception {
byte[] pdfData = new byte[0];
return pdfData;
}
/**
* docx转成pdf
*
* @param docxStream docx文件流
* @return 返回pdf数据
* @throws Exception
*/
private static byte[] docxToPdf(InputStream docxStream) throws Exception {
ByteArrayOutputStream targetStream = null;
XWPFDocument doc = null;
try {
doc = new XWPFDocument(docxStream);
PdfOptions options = PdfOptions.create();
// 中文字体处理
options.fontProvider(new IFontProvider() {
@Override
public Font getFont(String familyName, String encoding, float size, int style, Color color) {
try {
BaseFont bfChinese = createFont();
Font fontChinese = new Font(bfChinese, size, style, color);
if (familyName != null) {
fontChinese.setFamily(familyName);
}
return fontChinese;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
});
targetStream = new ByteArrayOutputStream();
PdfConverter.getInstance().convert(doc, targetStream, options);
return targetStream.toByteArray();
} catch (IOException e) {
throw new Exception(e);
} finally {
IOUtils.closeQuietly(targetStream);
}
}
/**
* doc转成pdf
*
* @param docStream doc文件流
* @return 返回pdf数据
* @throws Exception
*/
private static byte[] docToPdf(InputStream docStream) {
ByteArrayOutputStream targetStream = new ByteArrayOutputStream();
// todo 待完善doc转成pdf
return targetStream.toByteArray();
}
/**
* 替换docx内容
*
* @param in docx输入流
* @param map 替换键值对
* @return 返回替换后的文件流
* @throws Exception
*/
private static byte[] replaceDocxContent(InputStream in, Map<String, String> map) throws Exception {
// 读取word模板
XWPFDocument hdt = null;
ByteArrayOutputStream out = null;
try {
hdt = new XWPFDocument(in);
// 替换段落内容
List<XWPFParagraph> paragraphs = hdt.getParagraphs();
if (map != null && !map.isEmpty()) {
replaceParagraphsContent(paragraphs, map);
}
// 替换表格内容
List<XWPFTable> tables = hdt.getTables();
// 读取表格
for (XWPFTable table : tables) {
int rcount = table.getNumberOfRows();
// 遍历表格中的行
for (int i = 0; i < rcount; i++) {
XWPFTableRow row = table.getRow(i);
// 遍历行中的单元格
List<XWPFTableCell> cells = row.getTableCells();
for (XWPFTableCell cell : cells) {
List<XWPFParagraph> cellParagraphs = cell.getParagraphs();
if (map != null && !map.isEmpty()) {
replaceParagraphsContent(cellParagraphs, map);
}
}
}
}
out = new ByteArrayOutputStream();
hdt.write(out);
return out.toByteArray();
} catch (IOException e) {
throw new Exception(e.getMessage());
} finally {
IOUtils.closeQuietly(out);
}
}
/**
* 替换段落内容
*
* @param paragraphs
* @param map
*/
private static void replaceParagraphsContent(List<XWPFParagraph> paragraphs, Map<String, String> map) {
for (XWPFParagraph paragraph : paragraphs) {
List<XWPFRun> runs = paragraph.getRuns();
for (XWPFRun run : runs) {
String text = run.getText(0);
if (text != null) {
boolean isSetText = false;
for (Map.Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
// 在配置文件中有这个关键字对应的键
if (text.indexOf(key) != -1) {
String value = entry.getValue();
if (value == null) {
throw new RuntimeException(key + "对应的值不能为null");
}
// 文本替换
text = text.replace(key, value);
isSetText = true;
}
}
if (isSetText) {
run.setText(text, 0);
}
}
}
}
}
/**
* 创建字体
*
* @return
*/
private static BaseFont createFont() {
//仿宋体
String font_cn = getChineseFont();
BaseFont chinese = null;
try {
chinese = BaseFont.createFont(font_cn, BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
} catch (DocumentException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return chinese;
}
/**
* 获取中文字体位置
*
* @return
*/
private static String getChineseFont() {
// 仿宋体
String font = "C:/windows/fonts/simfang.ttf";
// 判断系统类型,加载字体文件
java.util.Properties prop = System.getProperties();
String osName = prop.getProperty("os.name").toLowerCase();
if (osName.indexOf("linux") > -1) {
font = "/usr/share/fonts/simsun/simfang.ttf";
}else if(osName.indexOf("mac os x") > -1){
font="/Users/Downloads/simfang.ttf";
}
if (!new File(font).exists()) {
throw new RuntimeException("字体文件不存在,影响导出pdf中文显示!" + font);
}
return font;
}
/**
* 将文件转换成byte数组
*
* @param tradeFile
* @return
*/
public static byte[] fileToByte(File tradeFile) {
byte[] buffer = null;
try {
FileInputStream fis = new FileInputStream(tradeFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int n;
while ((n = fis.read(b)) != -1) {
bos.write(b, 0, n);
}
fis.close();
bos.close();
buffer = bos.toByteArray();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return buffer;
}
/**
* 添加水印
*
* @param waterMark
*/
private void watermark(String waterMark) {
WatermarkPrint watermarkPrint = new PDFWatermarkPrint();
try {
watermarkPrint.print(pdfFile, new BufferedOutputStream(new FileOutputStream(waterPdfFile)),waterMark, DateUtil.format1());
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 上传到fast
*/
private void uploadFast() {
// 上传到文件服务器
String remoteServerPath = "https://www.xxxx.com/";
String remoteFilePath = null;
try {
// remoteFilePath = FastDfsUtil.upload(fileToByte(waterPdfFile), "pdf");
} catch (Exception e) {
e.printStackTrace();
}
if (StringUtil.isBlank(remoteFilePath)) {
throw new RuntimeException("文件上传失败,请重新上传!");
}
String fileUrl = "";
// 保存到数据库
if (remoteServerPath.endsWith("/")) {
fileUrl = remoteServerPath + remoteFilePath;
} else {
fileUrl = remoteServerPath + "/" + remoteFilePath;
}
this.fileUrl = fileUrl;
}
/**
* 获取输入流通过Url
*
* @param fileUrl
* @return
*/
private InputStream getInputStreamByUrl(String fileUrl) {
InputStream is = null;
for (int i = 0; i < 3; i++) {
try {
URL url = new URL(fileUrl);
httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoInput(true);
httpURLConnection.setRequestMethod("GET");
httpURLConnection.setConnectTimeout(30000);
is = httpURLConnection.getInputStream();
break;
} catch(Exception e) {
log.error("打开文件链接异常, 第【{}】次", i+1 , e);
}
}
return is;
}
/**
* 获取输入流通过path
*
* @param path
* @return
*/
private InputStream getInputStreamByPath(String path){
InputStream is = null;
try {
is = new FileInputStream(path);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
return is;
}
}
@Slf4j
public class FreemarkerUtil {
public static Configuration CONFIG;
public static String renderTemplate(String s, Map<String, Object> data) throws IOException, TemplateException {
Template t = new Template(null, new StringReader(s), CONFIG);
// 执行插值,并输出到指定的输出流中
StringWriter w = new StringWriter();
t.getConfiguration();
try {
t.process(data, w);
} catch (Exception e) {
e.printStackTrace();
log.error("填充模板内容出现异常,模板:"+s);
log.debug("noticeTime",data.get("noticeTime"));
}
return w.getBuffer().toString();
}
public static String renderFileTemplate(String file, Map<String, Object> data) throws IOException,
TemplateException {
Configuration cfg = CONFIG;
cfg.setDefaultEncoding("UTF-8");
// 取得模板文件
Template t = cfg.getTemplate(file);
// 执行插值,并输出到指定的输出流中
StringWriter w = new StringWriter();
t.getConfiguration();
t.process(data, w);
return w.getBuffer().toString();
}
}
public class PdfHelper {
private Document document;
private BaseFont bfChinese;
/**
* 字体
*/
@SuppressWarnings("unused")
private Font font;
public PdfHelper(String path) {
document = new Document();
try {
// 建立一个PdfWriter对象
PdfWriter.getInstance(document, new FileOutputStream(path));
document.open();
// 设置中文字体
bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED);
// 设置字体大小
font = new Font(bfChinese, 10, Font.NORMAL);
} catch (DocumentException de) {
} catch (IOException ioe) {
}
}
public static PdfHelper instance(String path) {
return new PdfHelper(path);
}
public void exportPdf() {
document.close();
}
public void addHtmlList(List<Element> list) throws DocumentException {
for (Element e : list) {
document.add(e);
}
}
}
@Slf4j
public class PdfUtil {
/**
* 协议模板
*/
private ContractTemplateDO contractTemplateDO;
private PdfHelper pdf;
private Map<String, Object> data;
/**
* 生成pdf路径名
*/
private String pdfName;
/**
* 添加水印的pdf路径名
*/
private String waterPdfName;
private File pdfFile;
private File waterPdfFile;
/**
* 文件上传到fast的地址
*/
private String fileUrl;
/**
* 水印文字
*/
private String watermark;
private static class Holder{
private static PdfUtil INSTANCE = new PdfUtil();
}
private PdfUtil(){}
public static PdfUtil getInstance() {
return Holder.INSTANCE;
}
/**
* 执行生成PDF文件
*/
public String execute(ContractTemplateDO contractTemplateDO, Map<String, Object> templateData, String watermark, String fileName) {
this.contractTemplateDO = contractTemplateDO;
pdfName = CommonUtil.getDir() + fileName + "-" + DateUtil.format2() + ".pdf";
waterPdfName = CommonUtil.getDir() + fileName + "-" + DateUtil.format2() + "-1.pdf";
this.pdf = PdfHelper.instance(pdfName);
this.waterPdfFile = new File(waterPdfName);
this.data = templateData;
this.watermark = watermark;
prepare();
valid();
initDate();
createPdf();
watermark(watermark);
//uploadFast();
return fileUrl;
}
/**
* 预处理
*/
private void prepare() {
}
/**
* 校验
*/
private void valid() {
}
/**
* 初始化参数
*/
private void initDate() {
}
/**
* 创建PDF
*/
private void createPdf() {
boolean checkFile = false;
File pdfFile = new File(pdfName);
try {
if (!pdfFile.exists()) {
pdfFile.mkdir();
}
String out = FreemarkerUtil.renderTemplate(contractTemplateDO.getTemplateContent(), this.data);
ProtocolHelper.templateHtml(out, pdf);
checkFile = true;
} catch (IOException e) {
log.error("解析模板出错",e);
throw new RuntimeException("解析模板出错");
} catch (Exception e) {
log.error("生成pdf出错",e);
}
if (!checkFile) {
throw new RuntimeException("pdf生成的路径不存在...");
}
pdf.exportPdf();
}
/**
* 上传到fast
*/
private void uploadFast() {
// 上传到文件服务器
String remoteServerPath = "https://www.xxxx.com/";
String remoteFilePath = null;
try {
// remoteFilePath = FastDfsUtil.upload(fileToByte(waterPdfFile), "pdf");
} catch (Exception e) {
e.printStackTrace();
}
if (StringUtil.isBlank(remoteFilePath)) {
throw new RuntimeException("文件上传失败,请重新上传!");
}
String fileUrl = "";
// 保存到数据库
if (remoteServerPath.endsWith("/")) {
fileUrl = remoteServerPath + remoteFilePath;
} else {
fileUrl = remoteServerPath + "/" + remoteFilePath;
}
this.fileUrl = fileUrl;
}
/**
* 打印水印
*
* @param watermark
*/
private void watermark(String watermark) {
WatermarkPrint watermarkPrint = new PDFWatermarkPrint();
File file = new File(pdfName);
try {
watermarkPrint.print(file, new BufferedOutputStream(new FileOutputStream(waterPdfFile)),watermark, DateUtil.format2());
} catch (IOException e) {
e.printStackTrace();
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
@Slf4j
public class ProtocolHelper {
/**
*
* @param str
* @param pdf
* @return
* @throws IOException
* @throws DocumentException
*/
protected static void templateHtml(String str, PdfHelper pdf) throws IOException, DocumentException {
final List<Element> pdfeleList = new ArrayList<Element>();
ElementHandler elemH = new ElementHandler() {
@Override
public void add(final Writable w) {
if (w instanceof WritableElement) {
pdfeleList.addAll(((WritableElement) w).elements());
}
}
};
log.info("Charset.defaultCharset(): {}",Charset.defaultCharset());
InputStreamReader isr = new InputStreamReader(new ByteArrayInputStream(str.getBytes("UTF-8")), "UTF-8");
XMLWorkerHelper.getInstance().parseXHtml(elemH, isr);
List<Element> list = new ArrayList<Element>();
pdfeleList.forEach(x->{
if (x instanceof LineSeparator || x instanceof WritableDirectElement) {
return;
}
list.add(x);
});
pdf.addHtmlList(list);
}
}