<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>

          用JAVA寫(xiě)的word模板自動(dòng)生成引擎

          共 9176字,需瀏覽 19分鐘

           ·

          2021-11-09 16:36

          大家好,我是TJ

          一個(gè)勵(lì)志推薦10000款開(kāi)源項(xiàng)目與工具的程序員


          TJ君做項(xiàng)目的時(shí)候最頭疼什么?當(dāng)然是寫(xiě)各種文檔啦,尤其是在大公司做項(xiàng)目,各種規(guī)范文檔不可少,雖然說(shuō)一個(gè)成熟的項(xiàng)目管理過(guò)程中的確是要依靠各種文檔來(lái)明確項(xiàng)目里程碑及具體的設(shè)計(jì)確認(rèn)和需求分工,但是TJ君還是更喜歡把時(shí)間花在開(kāi)發(fā)代碼上。

          尤其是有些文檔的格式都差不多,那是不是我們程序猿可以發(fā)揮特長(zhǎng),用程序來(lái)生成輸出指定的word文檔,減少自己的手寫(xiě)時(shí)間呢?

          當(dāng)然是可以的!

          今天TJ君就要給大家分享一款Word專(zhuān)用的模板引擎,Poi-tl(Poi-template-language)。這款引擎基于A(yíng)pache Poi,可以根據(jù)用戶(hù)輸入的內(nèi)容直接生成相應(yīng)的word文檔,很是方便。

          Apache Poi是用Java編寫(xiě)的一款免費(fèi)開(kāi)源的跨平臺(tái)的JavaAPI,該API可以通過(guò)Java程序?qū)ffice格式文檔進(jìn)行讀寫(xiě)操作,可以說(shuō)是現(xiàn)階段Java庫(kù)當(dāng)中最好用的office處理庫(kù)了,可能都不用加之一兩個(gè)字。所以基于A(yíng)pache Poi的Poi-tl可以讓你在word文檔的任何地方做任何你想做的事情。

          舉個(gè)例子,如果想生成一個(gè)名叫TJ君真棒.docx的文檔,并且在文檔里包含文本{{title}},只需要一句代碼,這句代碼也是整個(gè)引擎的核心所在:

          //核心API采用了極簡(jiǎn)設(shè)計(jì),只需要一行代碼
          XWPFTemplate.compile("TJ君真棒.docx").render(new?HashMap(){{
          ????????put("title",?"Poi-tl?模板引擎");
          }}).writeToFile("out_TJ君真棒.docx");

          Poi-tl整體設(shè)計(jì)采用了Template + data-model = output模式.

          Configure提供了模板配置功能,比如語(yǔ)法配置和插件配置:


          /**
          ?*?插件化配置
          ?*?
          ?*?@author?Sayi
          ?*?@version?1.0.0
          ?*/

          public?class?Configure?{

          ????//?defalut?expression
          ????private?static?final?String?DEFAULT_GRAMER_REGEX?=?"[\\w\\u4e00-\\u9fa5]+(\\.[\\w\\u4e00-\\u9fa5]+)*";

          ????//?Highest?priority
          ????private?Map?customPolicys?=?new?HashMap();
          ????//?Low?priority
          ????private?Map?defaultPolicys?=?new?HashMap();

          ????/**
          ?????*?引用渲染策略
          ?????*/

          ????private?List>?referencePolicies?=?new?ArrayList<>();

          ????/**
          ?????*?語(yǔ)法前綴
          ?????*/

          ????private?String?gramerPrefix?=?"{{";
          ????/**
          ?????*?語(yǔ)法后綴
          ?????*/

          ????private?String?gramerSuffix?=?"}}";

          ????/**
          ?????*?默認(rèn)支持中文、字母、數(shù)字、下劃線(xiàn)的正則
          ?????*/

          ????private?String?grammerRegex?=?DEFAULT_GRAMER_REGEX;

          ????/**
          ?????*?模板表達(dá)式模式,默認(rèn)為POI_TL_MODE
          ?????*/

          ????private?ELMode?elMode?=?ELMode.POI_TL_STANDARD_MODE;

          ????/**
          ?????*?渲染數(shù)據(jù)校驗(yàn)不通過(guò)時(shí)的處理策略
          ?????*?

            ?????*?
          • DiscardHandler:?什么都不做

          • ?????*?
          • ClearHandler:?清空標(biāo)簽

          • ?????*?
          • AbortHandler:?拋出異常

          • ?????*?

          ?????*/

          ????private?ValidErrorHandler?handler?=?new?ClearHandler();

          ????private?Configure()?{
          ????????plugin(GramerSymbol.TEXT,?new?TextRenderPolicy());
          ????????plugin(GramerSymbol.IMAGE,?new?PictureRenderPolicy());
          ????????plugin(GramerSymbol.TABLE,?new?MiniTableRenderPolicy());
          ????????plugin(GramerSymbol.NUMBERIC,?new?NumbericRenderPolicy());
          ????????plugin(GramerSymbol.DOCX_TEMPLATE,?new?DocxRenderPolicy());
          ????}

          ????/**
          ?????*?創(chuàng)建默認(rèn)配置
          ?????*?
          ?????*?@return
          ?????*/

          ????public?static?Configure?createDefault()?{
          ????????return?newBuilder().build();
          ????}

          ????/**
          ?????*?構(gòu)建器
          ?????*?
          ?????*?@return
          ?????*/

          ????public?static?ConfigureBuilder?newBuilder()?{
          ????????return?new?ConfigureBuilder();
          ????}

          ????/**
          ?????*?新增或變更語(yǔ)法插件
          ?????*?
          ?????*?@param?c
          ?????*????????????語(yǔ)法
          ?????*?@param?policy
          ?????*????????????策略
          ?????*/

          ????public?Configure?plugin(char?c,?RenderPolicy?policy)?{
          ????????defaultPolicys.put(Character.valueOf(c),?policy);
          ????????return?this;
          ????}

          ????/**
          ?????*?新增或變更語(yǔ)法插件
          ?????*?
          ?????*?@param?symbol
          ?????*????????????語(yǔ)法
          ?????*?@param?policy
          ?????*????????????策略
          ?????*?@return
          ?????*/

          ????Configure?plugin(GramerSymbol?symbol,?RenderPolicy?policy)?{
          ????????defaultPolicys.put(symbol.getSymbol(),?policy);
          ????????return?this;
          ????}

          ????/**
          ?????*?自定義模板和策略
          ?????*?
          ?????*?@param?tagName
          ?????*????????????模板名稱(chēng)
          ?????*?@param?policy
          ?????*????????????策略
          ?????*/

          ????public?void?customPolicy(String?tagName,?RenderPolicy?policy)?{
          ????????customPolicys.put(tagName,?policy);
          ????}

          ????/**
          ?????*?新增引用渲染策略
          ?????*?
          ?????*?@param?policy
          ?????*/

          ????public?void?referencePolicy(ReferenceRenderPolicy?policy)?{
          ????????referencePolicies.add(policy);
          ????}

          ????/**
          ?????*?獲取標(biāo)簽策略
          ?????*?
          ?????*?@param?tagName
          ?????*????????????模板名稱(chēng)
          ?????*?@param?sign
          ?????*????????????語(yǔ)法
          ?????*/

          ????//?Query?Operations

          ????public?RenderPolicy?getPolicy(String?tagName,?Character?sign)?{
          ????????RenderPolicy?policy?=?getCustomPolicy(tagName);
          ????????return?null?==?policy???getDefaultPolicy(sign)?:?policy;
          ????}

          ????public?List>?getReferencePolicies()?{
          ????????return?referencePolicies;
          ????}
          ????
          ????private?RenderPolicy?getCustomPolicy(String?tagName)?{
          ????????return?customPolicys.get(tagName);
          ????}

          ????private?RenderPolicy?getDefaultPolicy(Character?sign)?{
          ????????return?defaultPolicys.get(sign);
          ????}

          ????public?Map?getDefaultPolicys()?{
          ????????return?defaultPolicys;
          ????}

          ????public?Map?getCustomPolicys()?{
          ????????return?customPolicys;
          ????}

          ????public?Set?getGramerChars()?{
          ????????return?defaultPolicys.keySet();
          ????}

          ????public?String?getGramerPrefix()?{
          ????????return?gramerPrefix;
          ????}

          ????public?String?getGramerSuffix()?{
          ????????return?gramerSuffix;
          ????}

          ????public?String?getGrammerRegex()?{
          ????????return?grammerRegex;
          ????}

          ????public?ELMode?getElMode()?{
          ????????return?elMode;
          ????}

          ????public?ValidErrorHandler?getValidErrorHandler()?{
          ????????return?handler;
          ????}

          ????public?static?class?ConfigureBuilder?{
          ????????private?boolean?regexForAll;
          ????????private?Configure?config;

          ????????public?ConfigureBuilder()?{
          ????????????config?=?new?Configure();
          ????????}

          ????????public?ConfigureBuilder?buildGramer(String?prefix,?String?suffix)?{
          ????????????config.gramerPrefix?=?prefix;
          ????????????config.gramerSuffix?=?suffix;
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?buildGrammerRegex(String?reg)?{
          ????????????config.grammerRegex?=?reg;
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?supportGrammerRegexForAll()?{
          ????????????this.regexForAll?=?true;
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?setElMode(ELMode?mode)?{
          ????????????config.elMode?=?mode;
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?setValidErrorHandler(ValidErrorHandler?handler)?{
          ????????????config.handler?=?handler;
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?addPlugin(char?c,?RenderPolicy?policy)?{
          ????????????config.plugin(c,?policy);
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?customPolicy(String?tagName,?RenderPolicy?policy)?{
          ????????????config.customPolicy(tagName,?policy);
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?referencePolicy(ReferenceRenderPolicy?policy)?{
          ????????????config.referencePolicy(policy);
          ????????????return?this;
          ????????}

          ????????public?ConfigureBuilder?bind(String?tagName,?RenderPolicy?policy)?{
          ????????????config.customPolicy(tagName,?policy);
          ????????????return?this;
          ????????}

          ????????public?Configure?build()?{
          ????????????if?(config.elMode?==?ELMode.SPEL_MODE)?{
          ????????????????regexForAll?=?true;
          ????????????}
          ????????????if?(regexForAll)?{
          ????????????????config.grammerRegex?=?RegexUtils.createGeneral(config.gramerPrefix,
          ????????????????????????config.gramerSuffix);
          ????????????}
          ????????????return?config;
          ????????}
          ????}
          }

          Visitor提供了模板解析功能:

          /**
          ?*?模板解析器
          ?*?
          ?*?@author?Sayi
          ?*?@version?1.4.0
          ?*/

          public?class?TemplateVisitor?implements?Visitor?{
          ????private?static?Logger?logger?=?LoggerFactory.getLogger(TemplateVisitor.class);

          ????private?Configure?config;
          ????private?List?eleTemplates;

          ????private?Pattern?templatePattern;
          ????private?Pattern?gramerPattern;

          ????static?final?String?FORMAT_TEMPLATE?=?"{0}{1}{2}{3}";
          ????static?final?String?FORMAT_GRAMER?=?"({0})|({1})";

          ????public?TemplateVisitor(Configure?config)?{
          ????????this.config?=?config;
          ????????initPattern();
          ????}

          ????@Override
          ????public?List?visitDocument(XWPFDocument?doc)?{
          ????????if?(null?==?doc)?return?null;
          ????????this.eleTemplates?=?new?ArrayList();
          ????????logger.info("Visit?the?document?start...");
          ????????visitParagraphs(doc.getParagraphs());
          ????????visitTables(doc.getTables());
          ????????visitHeaders(doc.getHeaderList());
          ????????visitFooters(doc.getFooterList());
          ????????logger.info("Visit?the?document?end,?resolve?and?create?{}?ElementTemplates.",
          ????????????????this.eleTemplates.size());
          ????????return?eleTemplates;
          ????}

          ????void?visitHeaders(List?headers)?{
          ????????if?(null?==?headers)?return;
          ????????for?(XWPFHeader?header?:?headers)?{
          ????????????visitParagraphs(header.getParagraphs());
          ????????????visitTables(header.getTables());
          ????????}
          ????}

          ????void?visitFooters(List?footers)?{
          ????????if?(null?==?footers)?return;
          ????????for?(XWPFFooter?footer?:?footers)?{
          ????????????visitParagraphs(footer.getParagraphs());
          ????????????visitTables(footer.getTables());
          ????????}
          ????}

          ????void?visitParagraphs(List?paragraphs)?{
          ????????if?(null?==?paragraphs)?return;
          ????????for?(XWPFParagraph?paragraph?:?paragraphs)?{
          ????????????visitParagraph(paragraph);
          ????????}
          ????}

          ????void?visitTables(List?tables)?{
          ????????if?(null?==?tables)?return;
          ????????for?(XWPFTable?tb?:?tables)?{
          ????????????visitTable(tb);
          ????????}
          ????}

          ????void?visitTable(XWPFTable?table)?{
          ????????if?(null?==?table)?return;
          ????????List?rows?=?table.getRows();
          ????????if?(null?==?rows)?return;
          ????????for?(XWPFTableRow?row?:?rows)?{
          ????????????List?cells?=?row.getTableCells();
          ????????????if?(null?==?cells)?continue;
          ????????????for?(XWPFTableCell?cell?:?cells)?{
          ????????????????visitParagraphs(cell.getParagraphs());
          ????????????????visitTables(cell.getTables());
          ????????????}
          ????????}
          ????}

          ????void?visitParagraph(XWPFParagraph?paragraph)?{
          ????????if?(null?==?paragraph)?return;
          ????????RunningRunParagraph?runningRun?=?new?RunningRunParagraph(paragraph,?templatePattern);
          ????????List?refactorRun?=?runningRun.refactorRun();
          ????????if?(null?==?refactorRun)?return;
          ????????for?(XWPFRun?run?:?refactorRun)?{
          ????????????visitRun(run);
          ????????}
          ????}

          ????void?visitRun(XWPFRun?run)?{
          ????????String?text?=?null;
          ????????if?(null?==?run?||?StringUtils.isBlank(text?=?run.getText(0)))?return;
          ????????ElementTemplate?elementTemplate?=?parseTemplateFactory(text,?run);
          ????????if?(null?!=?elementTemplate)?eleTemplates.add(elementTemplate);
          ????}

          ????private??ElementTemplate?parseTemplateFactory(String?text,?T?obj)?{
          ????????logger.debug("Resolve?where?text:?{},?and?create?ElementTemplate",?text);
          ????????//?temp?,future?need?to?word?analyze
          ????????if?(templatePattern.matcher(text).matches())?{
          ????????????String?tag?=?gramerPattern.matcher(text).replaceAll("").trim();
          ????????????if?(obj.getClass()?==?XWPFRun.class)?{
          ????????????????return?TemplateFactory.createRunTemplate(tag,?config,?(XWPFRun)?obj);
          ????????????}?else?if?(obj.getClass()?==?XWPFTableCell.class)
          ????????????????//?return?CellTemplate.create(symbol,?tagName,?(XWPFTableCell)
          ????????????????//?obj)
          ;
          ????????????????return?null;
          ????????}
          ????????return?null;
          ????}

          ????private?void?initPattern()?{
          ????????String?signRegex?=?getGramarRegex(config);
          ????????String?prefixRegex?=?RegexUtils.escapeExprSpecialWord(config.getGramerPrefix());
          ????????String?suffixRegex?=?RegexUtils.escapeExprSpecialWord(config.getGramerSuffix());

          ????????templatePattern?=?Pattern.compile(MessageFormat.format(FORMAT_TEMPLATE,?prefixRegex,
          ????????????????signRegex,?config.getGrammerRegex(),?suffixRegex));
          ????????gramerPattern?=?Pattern
          ????????????????.compile(MessageFormat.format(FORMAT_GRAMER,?prefixRegex,?suffixRegex));
          ????}

          ????private?String?getGramarRegex(Configure?config)?{
          ????????List?gramerChar?=?new?ArrayList(config.getGramerChars());
          ????????StringBuilder?reg?=?new?StringBuilder("(");
          ????????for?(int?i?=?0;;?i++)?{
          ????????????Character?chara?=?gramerChar.get(i);
          ????????????String?escapeExprSpecialWord?=?RegexUtils.escapeExprSpecialWord(chara.toString());
          ????????????if?(i?==?gramerChar.size()?-?1)?{
          ????????????????reg.append(escapeExprSpecialWord).append(")?");
          ????????????????break;
          ????????????}?else?reg.append(escapeExprSpecialWord).append("|");
          ????????}
          ????????return?reg.toString();
          ????}

          }

          最后,RenderPolicy是渲染策略擴(kuò)展點(diǎn),Render模塊提供了RenderDataCompute表達(dá)式計(jì)算擴(kuò)展點(diǎn),通過(guò)RenderPolicy對(duì)每個(gè)標(biāo)簽進(jìn)行渲染。

          當(dāng)然,如果想將Poi-tl用的好的話(huà),還是要花一點(diǎn)時(shí)間來(lái)研究其中具體模塊的語(yǔ)法,好在Poi-tl提供詳細(xì)的示例代碼講解,小伙伴們只要用心學(xué)一下,很快就能掌握的

          到底能不能讓小伙伴們減輕寫(xiě)文檔的壓力呢?記得用過(guò)之后來(lái)給TJ君反饋哦!想用的小伙伴,完整項(xiàng)目地址在這里:

          點(diǎn)擊下方卡片,關(guān)注公眾號(hào)“TJ君

          回復(fù)“生成word”,獲取倉(cāng)庫(kù)地址

          關(guān)注我,每天了解一個(gè)牛x、好用、有趣的東東

          往期推薦

          GitHub高贊,一款足以取代迅雷的開(kāi)源下載工具

          Copilot 爆裂更新,通過(guò)注釋自動(dòng)生成代碼現(xiàn)已支持 IntelliJ IDEA、PyCharm

          可能是你用過(guò)最好用的Redis客戶(hù)端!

          IDEA中文字符自動(dòng)轉(zhuǎn)換插件,再也不用擔(dān)心程序因?yàn)橹形淖址麍?bào)錯(cuò)了!

          IDEA編碼自動(dòng)注釋工具,讓你的開(kāi)發(fā)更有效率

          十萬(wàn)伏特!讓你的操作終端變成寶可夢(mèng)!


          瀏覽 82
          點(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>
                  久久久免费视频一卡区 | 奇米7777狠狠狠狠视频 | 爱骚逼自拍偷拍精品视频 | 成人无码高清在线 | 中文字幕性爱电影 |