superword中的模板抽取实践

superword这个项目,全使用JAVA8新特性: https://github.com/ysc/superword ,一开始只是我的一个英语单词分析工具,用于生成HTML片段然后发到博客中,后来功能越来越强于是我就做成一个项目了,再后来有人跟我说自己不是计算机专业的不会用这个软件,于是我就改造成了一个WEB项目,这个项目现在有点需要改进的地方,就是把JAVA代码生成HTML的这个逻辑改成使用FREEMARKER的方式

我们首先来看在org.apdplat.superword.system.AntiRobotFilter类中的原来的JAVA代码生成HTML的逻辑:

1StringBuilder html = new StringBuilder(); 2html.append("<h1>The meaning of red color font is your answer, but the right answer is the meaning of blue color font for the word <font color=\"red\">") 3        .append(quizItem.getWord().getWord()) 4        .append(":</font></h1>"); 5html.append("<h2><ul>"); 6for(String option : quizItem.getMeanings()){ 7    html.append("<li>"); 8    if(option.equals(_answer)) { 9        html.append("<font color=\"red\">").append(option).append("</font>"); 10    }else if(option.equals(quizItem.getWord().getMeaning())){ 11        html.append("<font color=\"blue\">").append(option).append("</font>"); 12    }else{ 13        html.append(option); 14    } 15    html.append("</li>\n"); 16} 17html.append("</ul></h2>\n<h1><a href=\"") 18        .append(servletContext.getContextPath()) 19        .append("\">Continue...</a></h1>\n");

这样的代码对JAVA开发人员来说,第一次写的时候很爽很方便,用于原型开发快速验证功能是可以的,不过如果隔的时间长了自己再回头来看或者其他人来看这段代码,就会很吃力,因为这里纠缠了JAVA和HTML,纠缠了业务逻辑、数据处理逻辑以及显示逻辑,所以,如果代码需要持续维护的话就需要重构,下面我们就使用FREEMARKER来重构。

第一步,在pom.xml中引入FREEMARKER的依赖:

1<!-- html模板引擎 --> 2<dependency> 3    <groupId>org.freemarker</groupId> 4    <artifactId>freemarker</artifactId> 5    <version>${freemarker.version}</version> 6</dependency> 7 8<freemarker.version>2.3.24-incubating</freemarker.version>

第二步,在类路径下的template/freemarker/identify_quiz.ftlh文件中定义HTML模板:

1<h1> 2    The meaning of red color font is your answer, but the right answer is the meaning of blue color font for the word <font color="red">${quizItem.word.word}:</font> 3</h1> 4<h2> 5    <ul> 6<#list quizItem.meanings as meaning> 7    <#if meaning == answer> 8    <#--  用户答案 --> 9        <li><font color="red">${meaning}</font></li> 10    <#elseif meaning == quizItem.word.meaning> 11    <#--  正确答案 --> 12        <li><font color="blue">${meaning}</font></li> 13    <#else> 14    <#--  其他选项 --> 15        <li>${meaning}</li> 16    </#if> 17</#list> 18    </ul> 19</h2> 20<h1> 21    <a href="">Continue...</a> 22</h1>

第三步,在org.apdplat.superword.system.AntiRobotFilter类中准备模板需要的数据:

1Map<String, Object> data = new HashMap<>(); 2data.put("quizItem", quizItem); 3data.put("answer", _answer);

第四步,编写一个工具类org.apdplat.superword.freemarker.TemplateUtils,将模板和数据融合生成最终的HTML代码:

1package org.apdplat.superword.freemarker; 2 3import freemarker.template.Configuration; 4import freemarker.template.Template; 5import freemarker.template.TemplateExceptionHandler; 6import org.apdplat.superword.model.QuizItem; 7import org.slf4j.Logger; 8import org.slf4j.LoggerFactory; 9 10import java.io.StringWriter; 11import java.io.Writer; 12import java.util.HashMap; 13import java.util.Map; 14 15/** 16 * 模板工具, 用于生成html代码 17 * Created by ysc on 4/2/16. 18 */ 19public class TemplateUtils { 20    private TemplateUtils(){} 21    private static final Logger LOGGER = LoggerFactory.getLogger(TemplateUtils.class); 22    private static final Configuration CFG = new Configuration(Configuration.VERSION_2_3_23); 23 24    static{ 25        LOGGER.info("开始初始化模板配置"); 26        CFG.setClassLoaderForTemplateLoading(TemplateUtils.class.getClassLoader(), "/template/freemarker/"); 27        CFG.setDefaultEncoding("UTF-8"); 28        if(LOGGER.isDebugEnabled()) { 29            CFG.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER); 30        }else{ 31            CFG.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER); 32        } 33        CFG.setLogTemplateExceptions(false); 34        LOGGER.info("模板配置初始化完毕"); 35    } 36 37    /** 38     * 在识别用户是否是机器人的测试中, 如果用户测试失败, 则向用户显示这里生成的HTML代码 39     * @param data 需要两个数据项, 一是测试数据集quizItem, 二是用户的回答answer 40     * @return 测试结果HTML代码 41     */ 42    public static String getIdentifyQuiz(Map<String, Object> data){ 43        try { 44            Template template = CFG.getTemplate("identify_quiz.ftlh"); 45            Writer out = new StringWriter(); 46            template.process(data, out); 47            return out.toString(); 48        }catch (Exception e){ 49            LOGGER.error("generate authentication template failed", e); 50        } 51        return ""; 52    } 53 54    public static void main(String[] args) { 55        Map<String, Object> data = new HashMap<>(); 56        QuizItem quizItem = QuizItem.buildIdentifyHumanQuiz(12); 57        data.put("quizItem", quizItem); 58        data.put("answer", "random answer"); 59        System.out.println(TemplateUtils.getIdentifyQuiz(data)); 60    } 61}

第五步,在org.apdplat.superword.system.AntiRobotFilter类中删除JAVA代码生成HTML的逻辑,转而使用如下代码:

1Map<String, Object> data = new HashMap<>(); 2data.put("quizItem", quizItem); 3data.put("answer", _answer); 4String html = TemplateUtils.getIdentifyQuiz(data);

大功告成!看一下页面输出效果:

最后看一下模板引擎的日志输出,第一次访问:

1开始初始化模板配置 2模板配置初始化完毕 30    DEBUG [2016-04-02 22:04:25]  Couldn't find template in cache for "identify_quiz.ftlh"("en_US", UTF-8, parsed); will try to load it. 41    DEBUG [2016-04-02 22:04:25]  TemplateLoader.findTemplateSource("identify_quiz_en_US.ftlh"): Not found 52    DEBUG [2016-04-02 22:04:25]  TemplateLoader.findTemplateSource("identify_quiz_en.ftlh"): Not found 62    DEBUG [2016-04-02 22:04:25]  TemplateLoader.findTemplateSource("identify_quiz.ftlh"): Found 72    DEBUG [2016-04-02 22:04:25]  Loading template for "identify_quiz.ftlh"("en_US", UTF-8, parsed) from "file:/Users/ysc/workspace/superword/target/superword-1.0/WEB-INF/classes/template/freemarker/identify_quiz.ftlh"

第二次:

15324 DEBUG [2016-04-02 22:04:30]  TemplateLoader.findTemplateSource("identify_quiz_en_US.ftlh"): Not found 25325 DEBUG [2016-04-02 22:04:30]  TemplateLoader.findTemplateSource("identify_quiz_en.ftlh"): Not found 35325 DEBUG [2016-04-02 22:04:30]  TemplateLoader.findTemplateSource("identify_quiz.ftlh"): Found 45325 DEBUG [2016-04-02 22:04:30]  "identify_quiz.ftlh"("en_US", UTF-8, parsed): using cached since file:/Users/ysc/workspace/superword/target/superword-1.0/WEB-INF/classes/template/freemarker/identify_quiz.ftlh hasn't changed.

第三次:

181642 DEBUG [2016-04-02 22:05:47]  TemplateLoader.findTemplateSource("identify_quiz_en_US.ftlh"): Not found 281643 DEBUG [2016-04-02 22:05:47]  TemplateLoader.findTemplateSource("identify_quiz_en.ftlh"): Not found 381643 DEBUG [2016-04-02 22:05:47]  TemplateLoader.findTemplateSource("identify_quiz.ftlh"): Found 481643 DEBUG [2016-04-02 22:05:47]  "identify_quiz.ftlh"("en_US", UTF-8, parsed): using cached since file:/Users/ysc/workspace/superword/target/superword-1.0/WEB-INF/classes/template/freemarker/identify_quiz.ftlh hasn't changed.

这次重构的完整代码见:https://github.com/ysc/superword/commit/a46b48a352106143ce3a10964b1a98f45a961944,superword中还有一些地方需要做类似的重构,有兴趣的同学可以尝试一下,测试成功后欢迎在github上面给我发pull request.

点赞
收藏

评论区

加载中...

相关推荐

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

java8 函数接口

【前言】 java8新特性java8Optional使用总结(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Fkingsonfu%2Fp%2F11009574.html)java8lambda表达式(https://ww

superword开源项目中的定义相似规则

两个词之间的关系有同义、反义、近义(有多近?)、相关(有多相关?)等等。我们如何来判断两个词之间的关系呢?利用计算机能自动找出这种关系吗?当然可以,不仅能找出来,而且还能量化出有多近和有多相关。本文描述了superword(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub

HtmlExtractor 1.1 发布,网页信息抽取组件

HtmlExtractor(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fysc%2FHtmlExtractor)是一个Java实现的基于模板的网页结构化信息精准抽取组件,本身并不包含爬虫功能,但可被爬虫或其他程序调用以便更精准地对网页结构化信息进行抽取。

JDK源代码以及200多部软件著作中出现的以连字符构造的1011个合成词

JDK源代码以及200多部软件著作中出现的以连字符构造的1011个合成词,单词后面跟的是词频。superword是一个Java实现的英文单词分析软件,主要研究英语单词音近形似转化规律、前缀后缀规律、词之间的相似性规律等等。(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgi

JVM内幕:Java虚拟机详解

用于学习的JVMDIY项目,https://github.com/huangwei2013/jjvm(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fgithub.com%2Fhuangwei2013%2Fjjvm)\这篇文章解释