这两天遇到一个财务系统的需求,其中一个模块中客户提供了Word文档模板
根据数据库查询的结果填充模板,响应浏览器pdf下载流。
具体实现如下:
引用依赖:freemarker,aspose-words-15.8.0-jdk16.jar--->需要百度自行下载,maven中央仓库没有
freemarker作为替换文档中变量所需插件,首先将doc,docx文档打开,直接另存为xml格式,注意千万不要直接改文件后缀!
保存完毕后再将文件的后缀名改为.tfl,这样一来freemarker就可以识别到文件中待替换的变量,请注意在修改完后缀名后一定要用文本编辑器打开检查文件,word的格式问题可能导致变量符号被挤开,发现有被挤开的变量符号请手动修复,建议用文本编辑器查找${快速检查。
接下来在项目resouses目录下/linux环境则在classes目录下新建license.xml文件。
文件中的内容如下:
接下来将Windows下字体库上传到linux,Windows下字体库的位置为C:\Windows\fonts
linux的字体库是 /usr/share/fonts
将windows下的字体打包上传到linux上:/usr/share/fonts/chinese ,然后解压即可
准备工作完毕,接下来上代码!
所需的工具类:
import com.aspose.words.Document;
import com.aspose.words.FontSettings;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
public class WordToPdfUtil {
public boolean getLicense() {
boolean result =false;
try {
System.out.println(this.getClass().getClassLoader().getResource("license.xml").toString());
//InputStream is =this.getClass().getClassLoader().getResourceAsStream("license.xml");
InputStream is =this.getClass().getClassLoader().getResourceAsStream("license.xml");
License aposeLic =new License();
aposeLic.setLicense(is);
result =true;
}catch (Exception e) {
e.printStackTrace();
}
return result;
}
/*public static void main(String[] args) throws Exception {
WordToPdfUtil bean = new WordToPdfUtil();
bean.word2Pdf2("D:\\TEST.doc","D:\\TEST.pdf");
}*/
/**
* inpath: 输入word的路径,例如: C:\\TEST.doc
* outpath: 输出pdf的路径,例如: C:\\TEST.pdf
*/
public void word2Pdf2(String inpath,String outpath)throws Exception {
if (!getLicense()) {// 验证License 若不验证则转化出的pdf文档会有水印产生
System.out.println("非法------------");
return;
}
long old = System.currentTimeMillis();
File file =new File(outpath);
FileOutputStream os =new FileOutputStream(file);
//解决乱码
//如果是windows执行,不需要加这个
//TODO 如果是linux执行,需要添加这个*****
FontSettings.setFontsFolder("/usr/share/fonts/chinese",false);
Document doc =new Document(inpath);//Address是将要被转化的word文档
doc.save(os, SaveFormat.PDF);//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
long now = System.currentTimeMillis();
System.out.println("共耗时:" + ((now - old) /1000.0) +"秒");
}
/**
* @param path pdf输出路径
* @param wordInput word输入流
* @param wordName word文档的名称
*/
public void word2pdf(String path, InputStream wordInput, String wordName)throws FileNotFoundException {
if (!getLicense()) {// 验证License 若不验证则转化出的pdf文档会有水印产生
System.out.println("非法");
return;
}
long old = System.currentTimeMillis();
File file =new File(path + wordName +".pdf");//新建一个空白pdf文档
FileOutputStream os =new FileOutputStream(file);
Document doc =null;//Address是将要被转化的word文档
try {
doc =new Document(wordInput);
}catch (Exception e) {
e.printStackTrace();
}
try {
doc.save(os, SaveFormat.PDF);//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互转换
}catch (Exception e) {
e.printStackTrace();
}
long now = System.currentTimeMillis();
System.out.println("共耗时:" + ((now - old) /1000.0) +"秒");//转化用时
}
}
contorller层代码,笔者所用的框架比较老,可以参考一下:
public String preview(HttpServletRequest request, HttpServletResponse response,SettlementForm settlementForm)throws IOException {
String type = settlementForm.getType();
if(settlementForm.getType().equals("元")){
settlementForm.setType("0");
}
if(settlementForm.getType().equals("小")){
settlementForm.setType("1");
}if(settlementForm.getType().equals("P")){
settlementForm.setType("2");
}
//根据合作方名称查询合作方子业务名称
String businessName =partnerSettleFromDao.findBusinessNameByPartnerName(settlementForm.getUserName());
//boolean flag = partnerSettleFromDao.updatePartnerStatus(settlementForm);
try {
//合作方确认账单成功,下载word结算单
//导出结算单模板
String tmpFile =this.getClass().getClassLoader().getResource("/").getPath()+"template/";
Configuration configuration =new Configuration();
configuration.setDefaultEncoding("utf-8");
configuration.setDirectoryForTemplateLoading(new File(tmpFile));
Template template = configuration.getTemplate("template.ftl","utf-8");
//System.out.println(template.toString());
//编辑替换模板的数据,需要和模板中变量名一一对应
Map map =new HashMap<>();
map.put("type",type);
map.put("businessName",businessName);
map.put("username",settlementForm.getUserName());
map.put("accountPeriod",settlementForm.getAccountPeriod());
map.put("month",settlementForm.getAccountPeriod());
map.put("settleToCPAccount",settlementForm.getSettleToCPAccount());
//获取输出流
//ServletOutputStream os = response.getOutputStream();
File outFile =new File(tmpFile+"/test.docx");
Writer ot =new BufferedWriter(new OutputStreamWriter(new FileOutputStream(outFile),
"utf-8"),10240);
template.process(map, ot);
File outputFile =new File("test.pdf");
WordToPdfUtil bean =new WordToPdfUtil();
bean.word2Pdf2(tmpFile+"/test.docx",tmpFile+"/test.pdf");
InputStream inputStream=new FileInputStream(tmpFile+"/test.pdf");//根据路径获取要下载的文件输入流PDF
ServletOutputStream os = response.getOutputStream();
byte[] b=new byte[1024];//缓冲区
int length;
// 重置输出流
response.reset();
response.setHeader("Content-disposition",
"attachment; filename=" +new String(settlementForm.getAccountPeriod().getBytes(),"8859_1")
+new String(settlementForm.getUserName().getBytes(),"8859_1") +".pdf");
response.setContentType("application/msword");
//response.setCharacterEncoding("UTF-8");
while((length=inputStream.read(b))>0){//把文件流写到缓冲区里
os.write(b,0,length);
}
//System.out.println(template.toString());
os.flush();
os.close();
return "true";
}catch (Exception e){
log.error("下载结算单出错"+e);
e.printStackTrace();
return "false";
}
}