Java 實(shí)現(xiàn)word模板轉(zhuǎn)為pdf
1. pom相關(guān)依賴
工具poi-tl (操作word文檔模板) + jacob (將操作后的word模板轉(zhuǎn)為pdf)
<!-- poi-tl的pom依賴 --> <dependency> <groupId>com.deepoove</groupId> <artifactId>poi-tl</artifactId> <version>1.9.1</version> </dependency>
<!-- jacob的pom依賴(需自行導(dǎo)入.jar包) --> <dependency> <groupId>com.jacob</groupId> <artifactId>jacob</artifactId> <version>1.17</version> <scope>system</scope> <systemPath>${project.basedir}/src/main/resources/lib/jacob.jar</systemPath> </dependency>
2. 對(duì)word模板進(jìn)行插入數(shù)據(jù)操作
使用poi-tl操作word需要?jiǎng)?chuàng)建一個(gè)用于向word插入數(shù)據(jù)的Map<String, Object>集合, word模板中標(biāo)簽格式為"{{標(biāo)簽}}", 其中標(biāo)簽內(nèi)容為Map<String, Object> 的key.
// 項(xiàng)目根路徑 String abPath = new File("").getAbsolutePath() + "/src/main/resources"; // 創(chuàng)建用于插入數(shù)據(jù)的Map Map<String, Object> map = new HashMap<>(); map.put(<k>, <v>); ... // 填充word文檔 XWPFTemplate template = XWPFTemplate.compile(abPath + "<模板路徑>").render(map); // 輸出文檔 template.writeAndClose(new FileOutPutStream("<輸出路徑>"));
3. 對(duì)word模板的表格執(zhí)行插入數(shù)據(jù)操作(動(dòng)態(tài)表格)
使用poi-tl操作word的表格,動(dòng)態(tài)的插入數(shù)據(jù),需要用到poi-tl的可選插件進(jìn)行自定義渲染策略, 首先在word需要操作的表格中的任意單元格添加標(biāo)簽“{{標(biāo)簽}}”
自定義渲染策略
/** * 自定義渲染策略 * * @author */ public class DetailTablePolicy extends DynamicTableRenderPolicy { // 表格起始行行數(shù) int tableStartRow = 1; /** * 自定義渲染策略 * * @data 傳入的封裝好的數(shù)據(jù) */ @Override public void render(XWPFTable table, Object data) throws Exception { // 如果數(shù)據(jù)為空,直接返回 if (null == data) return; // 封裝數(shù)據(jù)List的數(shù)據(jù)封裝對(duì)象 NdrwhkhzbData detailData = (NdrwhkhzbData) data; // 獲取當(dāng)前列表行高 int height = table.getRow(2).getHeight(); // 從封裝對(duì)象中獲取數(shù)據(jù)集合 List<RowRenderData> datas = detailData.getNdrwhkhzbs(); if (null != datas) { // 循環(huán)移除空白表格中數(shù)據(jù)數(shù)量的空白行 for (int i = 1; i < datas.size() + 2; i++) { table.removeRow(i); } // 循環(huán)插入數(shù)據(jù) for (int i = 0; i < datas.size(); i++) { // 新增一行空白行 XWPFTableRow insertNewTableRow = table.insertNewTableRow(tableStartRow); // 設(shè)置行高 insertNewTableRow.setHeight(height); // 循環(huán)添加單元格(4為每行單元格數(shù)量) for (int j = 0; j < 4; j++) { insertNewTableRow.createCell(); } // 填充表格 TableRenderPolicy.Helper.renderRow(table.getRow(tableStartRow), datas.get(i)); } } } }
把自定義渲染策略當(dāng)做工具類, 在主邏輯中直接配置使用
/** * 操作年度任務(wù)和考核指標(biāo)表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據(jù)uid查詢年度任務(wù)和考核指標(biāo)數(shù)據(jù) List<NdrwhkhzbEntity> list = ndrwhkhzbService.selectNdrwhkhzbByUid(uid); for (NdrwhkhzbEntity ndrwhkhzbEntity : list) { RowRenderData rrd = Rows.of(ndrwhkhzbEntity.getNd(), ndrwhkhzbEntity.getNdrw(), ndrwhkhzbEntity.getNdkhzb() , ndrwhkhzbEntity.getZyrwdsjjd()).center().create(); nds.add(rrd); } detailTable.setNdrwhkhzbs(nds); datas.setNdrwhkhzbData(detailTable); // 配置表格 Configure config = Configure.builder().bind("detail_table", new DetailTablePolicy()).build(); // 調(diào)用渲染策略進(jìn)行填充 XWPFTemplate template = XWPFTemplate.compile(dirPath + "/" + uid + "_Complete.docx", config).render(datas); // 寫入表格中 template.writeToFile(dirPath + "/" + uid + "_Complete.docx"); }
用到的一些實(shí)體類
// PageData public class PageData { @Name("detail_table") private NdrwhkhzbData ndrwhkhzbData; public NdrwhkhzbData getNdrwhkhzbData() { return ndrwhkhzbData; } public void setNdrwhkhzbData(NdrwhkhzbData ndrwhkhzbData) { this.ndrwhkhzbData = ndrwhkhzbData; } } // NdrwhkhzbData public class NdrwhkhzbData { private List<RowRenderData> ndrwhkhzbs; public List<RowRenderData> getNdrwhkhzbs() { return ndrwhkhzbs; } public void setNdrwhkhzbs(List<RowRenderData> ndrwhkhzbs) { this.ndrwhkhzbs = ndrwhkhzbs; } }
4. 將編輯好的Word轉(zhuǎn)為pdf格式(jacob)
這里將word轉(zhuǎn)為pdf時(shí)需要用到j(luò)acob, 這里需要將jacob的dll文件放到j(luò)dk和jre的bin目錄下, 下載的jacob中dll文件一般為兩個(gè)版本, X86為32位, X64為64位, 根據(jù)自己安裝的jdk版本添加所對(duì)應(yīng)的dll文件
/* * 將 .docx 轉(zhuǎn)換為 .pdf */ ActiveXComponent app = null; String wordFile = dirPath + "/" + uid + "_Complete.docx"; String pdfFile = dirPath + "/" + dirName + ".pdf"; System.out.println("開始轉(zhuǎn)換..."); // 開始時(shí)間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent("Word.Application"); // 設(shè)置word不可見,很多博客下面這里都寫了這一句話,其實(shí)是沒有必要的,因?yàn)槟J(rèn)就是不可見的,如果設(shè)置可見就是會(huì)打開一個(gè)word文檔,對(duì)于轉(zhuǎn)化為pdf明顯是沒有必要的 //app.setProperty("Visible", false); // 獲得word中所有打開的文檔 Dispatch documents = app.getProperty("Documents").toDispatch(); System.out.println("打開文件: " + wordFile); // 打開文檔 Dispatch documentP = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch(); // 如果文件存在的話,不會(huì)覆蓋,會(huì)直接報(bào)錯(cuò),所以我們需要判斷文件是否存在 File target = new File(pdfFile); if (target.exists()) { target.delete(); } System.out.println("另存為: " + pdfFile); // 另存為,將文檔報(bào)錯(cuò)為pdf,其中word保存為pdf的格式宏的值是17 Dispatch.call(documentP, "SaveAs", pdfFile, 17); // 關(guān)閉文檔 Dispatch.call(documentP, "Close", false); // 結(jié)束時(shí)間 long end = System.currentTimeMillis(); System.out.println("轉(zhuǎn)換成功,用時(shí):" + (end - start) + "ms"); } catch (Exception e) { e.getMessage(); System.out.println("轉(zhuǎn)換失敗" + e.getMessage()); } finally { // 關(guān)閉office app.invoke("Quit", 0); }
5. 通過lo流將生成好的文件傳到瀏覽器下載
/* * 下載pdf */ String fileName = dirName + ".pdf"; File file = new File(dirPath + "/" + fileName); if (file.exists()) { BufferedInputStream bis = null; FileInputStream fis = null; try { response.setHeader("Content-disposition", "attachment; filename=" + fileName); byte[] buff = new byte[2048]; fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buff); while (i != -1) { os.write(buff, 0, i); i = bis.read(buff); } os.close(); } catch (Exception e) { e.printStackTrace(); } finally { assert fis != null; fis.close(); assert bis != null; bis.close(); } }
6. 最后的Controller整體代碼
package org.example.controller; import com.deepoove.poi.XWPFTemplate; import com.deepoove.poi.config.Configure; import com.deepoove.poi.data.Includes; import com.deepoove.poi.data.RowRenderData; import com.deepoove.poi.data.Rows; import com.jacob.activeX.ActiveXComponent; import com.jacob.com.Dispatch; import org.example.entity.*; import org.example.service.*; import org.example.utils.DetailTablePolicy; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Controller; import org.springframework.util.DigestUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * 創(chuàng)建pdf控制器 * * @author: yoojyn * @data: 2021/1/11 */ @Controller @RequestMapping("/createPdfController") public class CreatePdfController { @Autowired private IKtfmService ktfmService; @Autowired private IKtjbxxService ktjbxxService; @Autowired private IKtbyxfxService ktbyxfxService; @Autowired private IZtmbhkhzbService ztmbhkhzbService; @Autowired private INdrwhkhzbService ndrwhkhzbService; @Autowired private IKtjfysjsmService ktjfysjsmService; @Autowired private IXjxhkxxfxService xjxhkxxfxService; /** * 生成word文件 * * @param session 作用域 */ @Scope("prototype") @ResponseBody @RequestMapping("/createPdf") public void createPdf(HttpSession session, HttpServletResponse response) { // 獲取當(dāng)前用戶id Userinfo loginedUser = (Userinfo) session.getAttribute("loginedUser"); Integer uid = loginedUser.getUid(); String dirName = DigestUtils.md5DigestAsHex((uid + "_國(guó)家重大專項(xiàng)任務(wù)合同申報(bào)").getBytes()); String dirPath = "D:/" + dirName; String abPath = new File("").getAbsolutePath() + "/src/main/resources"; try { // 創(chuàng)建用于存儲(chǔ)中間文件的文件夾 new File(dirPath).mkdirs(); // 創(chuàng)建用于存儲(chǔ)數(shù)據(jù)的map集合 Map<String, Object> map = new HashMap<>(); // 獲取封面數(shù)據(jù) createKtfm(uid, map); // 獲取基本信息數(shù)據(jù) createJbxx(uid, map); // 獲取必要性分析 createByxfx(uid, map); // 獲取總體目標(biāo)和考核指標(biāo) createZtmbhkhzb(uid, map); // 獲取經(jīng)費(fèi)預(yù)算及說明 createJfysjsm(uid, map); // 查詢附件 XjxhkxxfxEntity xjxhkxxfxEntity = xjxhkxxfxService.selectXjxhkxxfxByUid(uid); // 設(shè)置下一步處理表格要用到的標(biāo)簽 map.put("page9", Includes.ofLocal(abPath + "/static/file/upload/" + xjxhkxxfxEntity.getFilename()).create()); map.put("detail_table", "{{detail_table}}"); // 填充文檔 XWPFTemplate template = XWPFTemplate.compile(abPath + "/static/file/moban/moban.docx").render(map); // 輸出文檔 template.writeAndClose(new FileOutputStream(dirPath + "/" + uid + "_Complete.docx")); // 操作年度任務(wù)和考核指標(biāo)表 createNdrwhkhzb(uid, dirPath); } catch (IOException e) { e.printStackTrace(); } try { /* * 將 .docx 轉(zhuǎn)換為 .pdf */ ActiveXComponent app = null; String wordFile = dirPath + "/" + uid + "_Complete.docx"; String pdfFile = dirPath + "/" + dirName + ".pdf"; System.out.println("開始轉(zhuǎn)換..."); // 開始時(shí)間 long start = System.currentTimeMillis(); try { // 打開word app = new ActiveXComponent("Word.Application"); // 設(shè)置word不可見,很多博客下面這里都寫了這一句話,其實(shí)是沒有必要的,因?yàn)槟J(rèn)就是不可見的,如果設(shè)置可見就是會(huì)打開一個(gè)word文檔,對(duì)于轉(zhuǎn)化為pdf明顯是沒有必要的 //app.setProperty("Visible", false); // 獲得word中所有打開的文檔 Dispatch documents = app.getProperty("Documents").toDispatch(); System.out.println("打開文件: " + wordFile); // 打開文檔 Dispatch documentP = Dispatch.call(documents, "Open", wordFile, false, true).toDispatch(); // 如果文件存在的話,不會(huì)覆蓋,會(huì)直接報(bào)錯(cuò),所以我們需要判斷文件是否存在 File target = new File(pdfFile); if (target.exists()) { target.delete(); } System.out.println("另存為: " + pdfFile); // 另存為,將文檔報(bào)錯(cuò)為pdf,其中word保存為pdf的格式宏的值是17 Dispatch.call(documentP, "SaveAs", pdfFile, 17); // 關(guān)閉文檔 Dispatch.call(documentP, "Close", false); // 結(jié)束時(shí)間 long end = System.currentTimeMillis(); System.out.println("轉(zhuǎn)換成功,用時(shí):" + (end - start) + "ms"); } catch (Exception e) { e.getMessage(); System.out.println("轉(zhuǎn)換失敗" + e.getMessage()); } finally { // 關(guān)閉office app.invoke("Quit", 0); } /* * 下載pdf */ String fileName = dirName + ".pdf"; File file = new File(dirPath + "/" + fileName); if (file.exists()) { BufferedInputStream bis = null; FileInputStream fis = null; try { response.setHeader("Content-disposition", "attachment; filename=" + fileName); byte[] buff = new byte[2048]; fis = new FileInputStream(file); bis = new BufferedInputStream(fis); OutputStream os = response.getOutputStream(); int i = bis.read(buff); while (i != -1) { os.write(buff, 0, i); i = bis.read(buff); } os.close(); } catch (Exception e) { e.printStackTrace(); } finally { assert fis != null; fis.close(); assert bis != null; bis.close(); } } } catch (Exception e) { e.printStackTrace(); } finally { delDir(new File(dirPath)); } } /** * 刪除文件夾 * * @param file 文件夾對(duì)象 */ private void delDir(File file) { if (file.isFile()) { file.delete(); } if (file.isDirectory()) { File[] files = file.listFiles(); for (File f : files) { f.delete(); } file.delete(); } } /** * 儲(chǔ)存經(jīng)費(fèi)預(yù)算及說明 * * @param uid 用戶id * @param map 儲(chǔ)存數(shù)據(jù)的map集合 */ private void createJfysjsm(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號(hào)查詢經(jīng)費(fèi)預(yù)算及說明 KtjfysjsmEntity ktjfysjsmEntity = ktjfysjsmService.getDatesByUid(uid); // 添加到map集合 map.put("zjzyczzj", ktjfysjsmEntity.getZjzyczzj()); map.put("zjdfczzj", ktjfysjsmEntity.getZjdfczzj()); map.put("zjdwzczj", ktjfysjsmEntity.getZjdwzczj()); map.put("zjqt", ktjfysjsmEntity.getZjqt()); } /** * 操作年度任務(wù)和考核指標(biāo)表 * * @throws IOException 輸入輸出流異常 */ private void createNdrwhkhzb(Integer uid, String dirPath) throws IOException { PageData datas = new PageData(); NdrwhkhzbData detailTable = new NdrwhkhzbData(); List<RowRenderData> nds = new ArrayList<>(); // 根據(jù)uid查詢年度任務(wù)和考核指標(biāo)數(shù)據(jù) List<NdrwhkhzbEntity> list = ndrwhkhzbService.selectNdrwhkhzbByUid(uid); for (NdrwhkhzbEntity ndrwhkhzbEntity : list) { RowRenderData rrd = Rows.of(ndrwhkhzbEntity.getNd(), ndrwhkhzbEntity.getNdrw(), ndrwhkhzbEntity.getNdkhzb() , ndrwhkhzbEntity.getZyrwdsjjd()).center().create(); nds.add(rrd); } detailTable.setNdrwhkhzbs(nds); datas.setNdrwhkhzbData(detailTable); Configure config = Configure.builder().bind("detail_table", new DetailTablePolicy()).build(); XWPFTemplate template = XWPFTemplate.compile(dirPath + "/" + uid + "_Complete.docx", config).render(datas); template.writeToFile(dirPath + "/" + uid + "_Complete.docx"); } /** * 儲(chǔ)存總體目標(biāo)和考核指標(biāo) * * @param uid 用戶id * @param map 儲(chǔ)存數(shù)據(jù)的map集合 */ private void createZtmbhkhzb(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號(hào)查詢總體目標(biāo)和考核指標(biāo) ZtmbhkhzbEntity ztmbhkhzbEntity = ztmbhkhzbService.selectZtmbhkhzbByUid(uid); // 添加到map集合 map.put("page6", ztmbhkhzbEntity.getZtmbhkhzb()); } /** * 儲(chǔ)存必要性分析數(shù)據(jù) * * @param uid 用戶id * @param map 儲(chǔ)存數(shù)據(jù)的map集合 */ private void createByxfx(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號(hào)查詢必要性分析數(shù)據(jù) KtbyxfxEntityWithBLOBs ktbyxfxEntity = ktbyxfxService.selectKtbyxfxByUid(uid); // 添加到map集合 map.put("page5_ktyzx", ktbyxfxEntity.getKtyzx()); map.put("page5_ktysfgc", ktbyxfxEntity.getKtysf()); map.put("page5_ktyq", ktbyxfxEntity.getKtyq()); } /** * 儲(chǔ)存基本信息數(shù)據(jù) * * @param uid 用戶編號(hào) * @param map 儲(chǔ)存數(shù)據(jù)的map集合 */ private void createJbxx(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號(hào)查詢基本信息數(shù)據(jù) KcjbxxEntity kcjbxxEntity = ktjbxxService.selectKtjbxxByUid(uid); // 添加到map集合 map.put("page3_ktmc", kcjbxxEntity.getKtmc()); map.put("page3_ktmj", kcjbxxEntity.getKtmj()); map.put("page3_yjwcsj", kcjbxxEntity.getYjwcsj()); map.put("page3_kyhdlx", kcjbxxEntity.getKthdlx()); map.put("page3_yqcglx", kcjbxxEntity.getYqcglx()); map.put("page3_dwmc", kcjbxxEntity.getDwmc()); map.put("page3_dwxz", kcjbxxEntity.getDwxz()); map.put("page3_txdz", kcjbxxEntity.getTxdz()); map.put("page3_yzbm", kcjbxxEntity.getYzbm()); map.put("page3_szdq", kcjbxxEntity.getSzdq()); map.put("page3_dwzgbm", kcjbxxEntity.getDwzgbm()); map.put("page3_lxdh", kcjbxxEntity.getLxdh()); map.put("page3_zzjgdm", kcjbxxEntity.getZzjgdm()); map.put("page3_czhm", kcjbxxEntity.getCzhm()); map.put("page3_dwclsj", kcjbxxEntity.getDwclsj()); map.put("page3_dzxx", kcjbxxEntity.getDzxx()); } /** * 儲(chǔ)存課題封面數(shù)據(jù) * * @param uid 用戶編號(hào) * @param map 儲(chǔ)存數(shù)據(jù)的map集合 */ private void createKtfm(Integer uid, Map<String, Object> map) { // 根據(jù)用戶編號(hào)查詢封面數(shù)據(jù) KtfmEntity ktfmEntity = ktfmService.selectKtfmByUid(uid); // 添加到map集合 map.put("page1_zxmc", "5G總體及關(guān)鍵器件"); map.put("page1_xmbh", "2016ZX03001_001"); map.put("page1_xmmc", "新一代寬帶無(wú)線移動(dòng)通信網(wǎng)"); map.put("page1_ktbh", "2016ZX03001_001_002"); map.put("page1_ktmc", "5G高性能基站A/D、D/A轉(zhuǎn)換器試驗(yàn)樣片研發(fā)"); map.put("page1_zrdw", "program_test"); map.put("page1_ktzz", ktfmEntity.getKtfzr()); map.put("page1_ktnx1", "2016-01-01"); map.put("page1_ktnx2", "2017-12-31"); map.put("page1_tbrq", "2020-12-28"); map.put("page1_nian", "二一"); map.put("page1_yue", "一"); } }
以上就是Java 實(shí)現(xiàn)word模板轉(zhuǎn)為pdf的詳細(xì)內(nèi)容,更多關(guān)于Java word模板轉(zhuǎn)為pdf的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
mybatis根據(jù)表逆向自動(dòng)化生成代碼的實(shí)現(xiàn)
若采用mybatis框架,數(shù)據(jù)庫(kù)新建表,手動(dòng)編寫的話,需要編寫大量的實(shí)體類、mapper文件、mapper.xml文件,都是一些重復(fù)且有規(guī)律的工作。我們可以引用插件,然后做配置,自動(dòng)生成這些文件,本文就來(lái)詳細(xì)的介紹一下2021-08-08eclipse/IDEA配置javafx項(xiàng)目步驟(圖文教程)
這篇文章主要介紹了eclipse/IDEA配置javafx項(xiàng)目步驟(圖文教程),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-03-03Java的泛型擦除和運(yùn)行時(shí)泛型信息獲取方式
Java泛型在編譯時(shí)會(huì)發(fā)生類型擦除,即泛型參數(shù)被替換為它們的限定類型(如Object),這使得ArrayList<Integer>和ArrayList<String>在運(yùn)行時(shí)類型相同,盡管如此,我們可以通過定義類或匿名內(nèi)部類的方式在運(yùn)行時(shí)獲取泛型信息2024-09-09Springboot項(xiàng)目Maven依賴沖突的問題解決
使用Spring Boot和Maven進(jìn)行項(xiàng)目開發(fā)時(shí),依賴沖突是一個(gè)常見的問題,本文就來(lái)介紹一下Springboot項(xiàng)目Maven依賴沖突的問題解決,具有一定的參考價(jià)值,感興趣的可以了解一下2024-07-07Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件 FTP軟件主界面(4)
這篇文章主要為大家詳細(xì)介紹了Java語(yǔ)言實(shí)現(xiàn)簡(jiǎn)單FTP軟件,F(xiàn)TP軟件主界面編寫的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-03-03淺析Java如何優(yōu)雅的設(shè)計(jì)接口狀態(tài)碼和異常
HTTP協(xié)議里定義了一系列的狀態(tài)碼用來(lái)表明請(qǐng)求的狀態(tài),如常用的200表示請(qǐng)求正常,404表示請(qǐng)求的資源不存在,所以本文就來(lái)和大家討論一下如何優(yōu)雅的設(shè)計(jì)接口狀態(tài)碼和異常,感興趣的可以了解下2024-03-03Windows中在IDEA上安裝和使用JetBrains Mono字體的教程
這篇文章主要介紹了Windows IDEA上安裝和使用JetBrains Mono字體的教程,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03mybatisPlus自定義批量新增的實(shí)現(xiàn)代碼
這篇文章主要介紹了mybatisPlus自定義批量新增的實(shí)現(xiàn)代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-11-11