<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Word簡(jiǎn)歷文檔自動(dòng)化生成新方案

          共 12204字,需瀏覽 25分鐘

           ·

          2024-05-11 18:13

          來源:juejin.cn/post/7101493026899853325

          推薦:https://t.zsxq.com/Kpajy

          好看的簡(jiǎn)歷并不是千篇一律的,而是各有特色。前幾天我看了雷軍的簡(jiǎn)歷,簡(jiǎn)直亮瞎了我的雙眼。

          又看了某網(wǎng)紅的簡(jiǎn)歷,佩服的五體投地。

          剛好最近公司又要裁員了,老板需要我整理一批簡(jiǎn)歷。老系統(tǒng)中的人員信息都存儲(chǔ)在數(shù)據(jù)庫(kù)中,我該如何給老板拉簡(jiǎn)歷呢?

          百思不得其解呀,如果是畫一個(gè)前端頁(yè)面,那得一個(gè)一個(gè)的另存為。這時(shí)候 RPA 到是可以用上,但是前端頁(yè)面得有人畫。但是,前端最近人數(shù)本來就不夠,還要砍一半。

          不得已,我給團(tuán)隊(duì)的小伙伴說,后端生成 word 簡(jiǎn)歷吧,轉(zhuǎn)成 pdf 壓縮后扔給我。我轉(zhuǎn)給老板。順便給大家支了招,使用 poi + FreeMarker 來搞定。當(dāng)然,如果沒有 FreeMarker 也是可以的,有 FreeMarker 是可以更靈活的。

          下面就是本文要講解的一些核心要點(diǎn),分享給大家!

          前言

          工作中經(jīng)常會(huì)遇到生成word這樣的需求, 以前都是使用FreeMarker來生成的 我們先了解一下FreeMarker是如何生成word的

          • 制作好word模板
          • 轉(zhuǎn)換為xml文檔并格式化, 文件后綴改為ftl(這一步生成的xml格式可能會(huì)錯(cuò)亂...)
          • 在模板代碼(上萬行)中加各種邏輯代碼來實(shí)現(xiàn)需求
          • FreeMarker模板引擎渲染生成word(doc格式的)
          • doc轉(zhuǎn)docx

          ps: word doc格式和docx格式的區(qū)別 doc為二進(jìn)制文件, 非常大, 打開速度非常慢; docx為壓縮文件, 非常小, 打開速度很快

          上萬行的xml代碼簡(jiǎn)直是維護(hù)地獄, 要是這時(shí)候老板覺得這個(gè)word模板不太好看, 改改字體, 換下顏色, 調(diào)整表格樣式等等, 除非你對(duì)word的xml結(jié)構(gòu)特比特別熟悉, 否則你只能重復(fù)上面的步驟再來一次,心態(tài)崩了!!!

          有沒有一種更容易維護(hù)的方式來生成word呢, 答案就是: POI-TL。

          poi-tl簡(jiǎn)介

          poi-tl(poi template language)是基于Apache POI的Word模板引擎,純Java組件,跨平臺(tái),代碼短小精悍,通過插件機(jī)制使其具有高度擴(kuò)展性。

          注意: POI-TL可能會(huì)和項(xiàng)目中使用到xml相關(guān)操作的包產(chǎn)生沖突 建議將POI-TL單獨(dú)寫成一個(gè)服務(wù), 包裝需要使用到的相關(guān)特性以避免沖突

          poi-tl使用

          使用步驟十分簡(jiǎn)單:

          • 準(zhǔn)備好word模板
          • 準(zhǔn)備好數(shù)據(jù) 下面我們來試一下
          ?

          maven

          <!-- poi-tl -->
          <dependency>
              <groupId>com.deepoove</groupId>
              <artifactId>poi-tl</artifactId>
              <version>1.12.0</version>
          </dependency>
          <!-- spire.doc -->
          <dependency>
              <groupId>e-iceblue</groupId>
              <artifactId>spire.doc.free</artifactId>
              <version>3.9.0</version>
          </dependency>
          <!-- spring el -->
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-expression</artifactId>
              <version>5.3.18</version>
          </dependency>
          ?

          先看下我的模板

          ?

          這是生成后的word效果

          我在模板中嘗試了POI-TL的以下特性。

          /**
           * 表格內(nèi)設(shè)置超鏈接
           */

          @Data
          @EqualsAndHashCode(callSuper = true)
          @AllArgsConstructor
          public class LoopRowTableHyperlinkRenderPolicy extends LoopRowTableRenderPolicy {
              /**
               * 列
               */

              private int hyperlinkIndex;
              /**
               * 超鏈接url key
               */

              private String hyperlinkName = "url";
              /**
               * 超鏈接text key
               */

              private String hyperlinkValue;

              public LoopRowTableHyperlinkRenderPolicy(int hyperlinkIndex, String hyperlinkValue) {
                  this.hyperlinkIndex = hyperlinkIndex;
                  this.hyperlinkValue = hyperlinkValue;
              }

              @Override
              protected void afterloop(XWPFTable table, Object data) {
                  try {
                      List<JSONObject> jsonObjectList = JSONArray.parseArray(JSON.toJSONString(data), JSONObject.class);
                      List<XWPFTableRow> rows = table.getRows();
                      // index從1開始, 跳過表頭
                      for (int i = 1; i < rows.size(); i++) {
                          XWPFTableCell cell = rows.get(i).getCell(hyperlinkIndex);
                          List<XWPFParagraph> paragraphs = cell.getParagraphs();
                          for (XWPFParagraph paragraph : paragraphs) {
                              JSONObject js = jsonObjectList.get(i - 1);
                              String url = String.valueOf(js.get(hyperlinkName));
                              String value = String.valueOf(js.get(hyperlinkValue));
                              if (StrUtil.isBlank(url) || "null".equals(url)) {
                                  // 不滿足條件, 正常填充值
                                  cell.setText(value);
                              } else {
                                  // 滿足條件, 設(shè)置超鏈接
                                  setLink(url, value, paragraph);
                              }
                              // 居中
                              paragraph.setAlignment(ParagraphAlignment.CENTER);
                              paragraph.setVerticalAlignment(TextAlignment.CENTER);
                          }
                      }
                  } catch (Exception ex) {
                      ex.printStackTrace();
                  }
              }

              private void setLink(String url, String text, XWPFParagraph e) {
                  String id = e.getDocument().getPackagePart().addExternalRelationship(url,
                          XWPFRelation.HYPERLINK.getRelation()).getId();
                  CTHyperlink ctHyperlink = e.getCTP().addNewHyperlink();
                  ctHyperlink.setId(id);
                  CTText ctText = CTText.Factory.newInstance();
                  // 設(shè)置值
                  ctText.setStringValue(text);
                  CTR ctr = CTR.Factory.newInstance();
                  CTRPr rpr = ctr.addNewRPr();
                  CTColor color = CTColor.Factory.newInstance();
                  // 設(shè)置顏色
                  color.setVal("0000FF");
                  rpr.setColorArray(new CTColor[]{color});
                  // 單下劃線
                  // rpr.addNewU().setVal(STUnderline.SINGLE);
                  // 無下劃線
                  rpr.addNewU().setVal(STUnderline.NONE);
                  ctr.setTArray(new CTText[]{ctText});
                  ctHyperlink.setRArray(new CTR[]{ctr});
              }
          }
          • 柱狀圖/餅圖(柱狀圖可以在模板中調(diào)整柱間距來改變柱的粗細(xì))
          • 嵌套 語(yǔ)法: {{+nested}}

          sub.docx

          這里是{{province}}
              {{city}} - {{district}}
          • 循環(huán)
          {{?sections}}集合第[{{_index}}]個(gè)元素: {{name}}{{/sections}}
          • 區(qū)塊對(duì)
          {{?isEmpty}}
          ******數(shù)據(jù)不為null******
          {{/}}
          {{?isEmpty == null}}
          ******數(shù)據(jù)為null******
          {{/}}
          {{new java.text.SimpleDateFormat('yyyy-MM-dd HH:mm:ss').format(time)}}
          ?

          配置并生成文件

          Configure config = Configure.builder()
                  // isStrict = false , 關(guān)閉嚴(yán)格模式, 嚴(yán)格模式下key不存在會(huì)報(bào)錯(cuò)
                  // 關(guān)閉后key不存在會(huì)被忽略
                  .useSpringEL(false)
                  // 表格綁定policy
                  .bind("books", policy)
                  .build();
          XWPFTemplate template = XWPFTemplate.
                  compile(getFile("""template/template.docx"), config).render(data);
          String path = OUT_PATH + IdUtil.fastSimpleUUID() + ".docx";
          template.writeToFile(path);
          private File getFile(String path, String name) throws IOException {
              InputStream input = this.getClass().getClassLoader().getResourceAsStream(path + name);
              File file = new File(name);
              FileUtils.copyInputStreamToFile(input, file);
              return file;
          }

          POI-TLTOCRenderPolicy插件還不太好使(Beta實(shí)驗(yàn)功能:目錄,打開文檔時(shí)會(huì)提示更新域) 這里我使用的是spire.doc來更新目錄, 為了避免更新目錄造成內(nèi)容位置錯(cuò)亂, 我在模板文件的目錄后加了一個(gè)分頁(yè)符

          /**
           * 更新目錄
           *
           * @param source 源文件
           * @param dir    目錄
           * @return 更新后文件
           */

          public static File updateTOCBySpire(String source, String dir) {
              Document document = new Document(source);
              String path = newPath(dir);
              File file = new File(path);
              try {
                  document.updateTableOfContents();
                  document.saveToFile(path, FileFormat.Docx_2013);
              } finally {
                  document.close();
              }
              return file;
          }

          注意spire.doc免費(fèi)版的最多支持500個(gè)段落, 25個(gè)表格, 超過部分會(huì)被截?cái)?/code>(一般情況下這個(gè)已經(jīng)能夠滿足了)

          也可以使用docx4j來更新目錄(文檔很多頁(yè)會(huì)特別慢, 并且DTM ID可能被耗盡, 導(dǎo)致無法使用)

          如果真的是文檔特別大的話可以使用jacob(不能跨平臺(tái), 只能在windows系統(tǒng)下使用)或者使用付費(fèi)版的spire.doc(可以跨平臺(tái)的)

          瀏覽 58
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  少妇视频成人 | 日韩无码专区电影 | 日本精品一字幕 | 久久性爱视频网 | 国产做受 高潮游戏视频 |