這兩天遇到一個財務(wù)系統(tǒng)的需求晃危,其中一個模塊中客戶提供了Word文檔模板
根據(jù)數(shù)據(jù)庫查詢的結(jié)果填充模板,響應(yīng)瀏覽器pdf下載流老客。
具體實(shí)現(xiàn)如下:
引用依賴:freemarker僚饭,aspose-words-15.8.0-jdk16.jar--->需要百度自行下載,maven中央倉庫沒有
<!-- word2pdf -->
? ? ? ? <dependency>
? ? ? ? ? ? <groupId>com.jcraft</groupId>
? ? ? ? ? ? <artifactId>aspose-words</artifactId>
? ? ? ? ? ? <version>15.8.0-jdk16</version>
? ? ? ? </dependency>
????<dependency>
????????<groupId>org.freemarker</groupId>
????????<artifactId>freemarker</artifactId>
????????<version>2.3.18</version>
????</dependency>
freemarker作為替換文檔中變量所需插件胧砰,首先將doc,docx文檔打開鳍鸵,直接另存為xml格式,注意千萬不要直接改文件后綴尉间!
保存完畢后再將文件的后綴名改為.tfl权纤,這樣一來freemarker就可以識別到文件中待替換的變量,請注意在修改完后綴名后一定要用文本編輯器打開檢查文件乌妒,word的格式問題可能導(dǎo)致變量符號被擠開陨簇,發(fā)現(xiàn)有被擠開的變量符號請手動修復(fù)赋除,建議用文本編輯器查找${快速檢查。
接下來在項(xiàng)目resouses目錄下/linux環(huán)境則在classes目錄下新建license.xml文件宜肉。
文件中的內(nèi)容如下:
<License>
<Data>
<Products>
<Product>Aspose.Total for Java</Product>
<Product>Aspose.Words for Java</Product>
</Products>
<EditionType>Enterprise</EditionType>
<SubscriptionExpiry>20991231</SubscriptionExpiry>
<LicenseExpiry>20991231</LicenseExpiry>
<SerialNumber>23dcc79f-44ec-4a23-be3a-03c1632404e9</SerialNumber>
</Data>
<Signature>0nRuwNEddXwLfXB7pw66G71MS93gW8mNzJ7vuh3Sf4VAEOBfpxtHLCotymv1PoeukxYe31K441Ivq0Pkvx1yZZG4O1KCv3Omdbs7uqzUB4xXHlOub4VsTODzDJ5MWHqlRCB1HHcGjlyT2sVGiovLt0Grvqw5+QXBuinoBY0suX0=</Signature>
</License>
接下來將Windows下字體庫上傳到linux损话,Windows下字體庫的位置為C:\Windows\fonts
linux的字體庫是 /usr/share/fonts
將windows下的字體打包上傳到linux上:/usr/share/fonts/chinese? ,然后解壓即可
準(zhǔn)備工作完畢侦啸,接下來上代碼!
所需的工具類:
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()) {// 驗(yàn)證License 若不驗(yàn)證則轉(zhuǎn)化出的pdf文檔會有水印產(chǎn)生
? ? ? ? ? ? System.out.println("非法------------");
return;
}
long old = System.currentTimeMillis();
File file =new File(outpath);
FileOutputStream os =new FileOutputStream(file);
//解決亂碼
? ? ? ? //如果是windows執(zhí)行,不需要加這個
? ? ? ? //TODO 如果是linux執(zhí)行拧烦,需要添加這個*****
? ? ? ? FontSettings.setFontsFolder("/usr/share/fonts/chinese",false);
Document doc =new Document(inpath);//Address是將要被轉(zhuǎn)化的word文檔
? ? ? ? doc.save(os, SaveFormat.PDF);//全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF, EPUB, XPS, SWF 相互轉(zhuǎn)換
? ? ? ? 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()) {// 驗(yàn)證License 若不驗(yàn)證則轉(zhuǎn)化出的pdf文檔會有水印產(chǎn)生
? ? ? ? ? ? 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是將要被轉(zhuǎn)化的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 相互轉(zhuǎn)換
? ? ? ? }catch (Exception e) {
e.printStackTrace();
}
long now = System.currentTimeMillis();
System.out.println("共耗時:" + ((now - old) /1000.0) +"秒");//轉(zhuǎn)化用時
? ? }
}
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");
}
//根據(jù)合作方名稱查詢合作方子業(yè)務(wù)名稱
? ? String businessName =partnerSettleFromDao.findBusinessNameByPartnerName(settlementForm.getUserName());
//boolean flag = partnerSettleFromDao.updatePartnerStatus(settlementForm);
? ? ? ? try {
//合作方確認(rèn)賬單成功恋博,下載word結(jié)算單
? ? ? ? ? ? //導(dǎo)出結(jié)算單模板
? ? ? ? ? ? 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());
? ? ? ? ? ? //編輯替換模板的數(shù)據(jù)齐佳,需要和模板中變量名一一對應(yīng)
? ? ? ? ? ? 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");//根據(jù)路徑獲取要下載的文件輸入流PDF
? ? ? ? ? ? ServletOutputStream os = response.getOutputStream();
byte[] b=new byte[1024];//緩沖區(qū)
? ? ? ? ? ? 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){//把文件流寫到緩沖區(qū)里
? ? ? ? ? ? ? ? os.write(b,0,length);
}
//System.out.println(template.toString());
? ? ? ? ? ? os.flush();
os.close();
return "true";
}catch (Exception e){
log.error("下載結(jié)算單出錯"+e);
e.printStackTrace();
return "false";
}
}