superword这个项目,全使用JAVA8新特性: https://github.com/ysc/superword ,一开始只是我的一个英语单词分析工具,用于生成HTML片段然后发到博客中,后来功能越来越强于是我就做成一个项目了,再后来有人跟我说自己不是计算机专业的不会用这个软件,于是我就改造成了一个WEB项目,这个项目现在有点需要改进的地方,就是把JAVA代码生成HTML的这个逻辑改成使用FREEMARKER的方式。
我们首先来看在org.apdplat.superword.system.AntiRobotFilter类中的原来的JAVA代码生成HTML的逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
StringBuilder html =
new
StringBuilder();
html.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\">"
)
.append(quizItem.getWord().getWord())
.append(
":</font></h1>"
);
html.append(
"<h2><ul>"
);
for
(String option : quizItem.getMeanings()){
html.append(
"<li>"
);
if
(option.equals(_answer)) {
html.append(
"<font color=\"red\">"
).append(option).append(
"</font>"
);
}
else
if
(option.equals(quizItem.getWord().getMeaning())){
html.append(
"<font color=\"blue\">"
).append(option).append(
"</font>"
);
}
else
{
html.append(option);
}
html.append(
"</li>\n"
);
}
html.append(
"</ul></h2>\n<h1><a href=\""
)
.append(servletContext.getContextPath())
.append(
"\">Continue...</a></h1>\n"
);
|
这样的代码对JAVA开发人员来说,第一次写的时候很爽很方便,用于原型开发快速验证功能是可以的,不过如果隔的时间长了自己再回头来看或者其他人来看这段代码,就会很吃力,因为这里纠缠了JAVA和HTML,纠缠了业务逻辑、数据处理逻辑以及显示逻辑,所以,如果代码需要持续维护的话就需要重构,下面我们就使用FREEMARKER来重构。
第一步,在pom.xml中引入FREEMARKER的依赖:
1
2
3
4
5
6
|
<!-- html模板引擎 -->
<
dependency
>
<
groupId
>org.freemarker</
groupId
>
<
artifactId
>freemarker</
artifactId
>
<
version
>${freemarker.version}</
version
>
</
dependency
>
|
1
|
<
freemarker.version
>2.3.24-incubating</
freemarker.version
>
|
第二步,在类路径下的template/freemarker/identify_quiz.ftlh文件中定义HTML模板:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
<
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"
>${quizItem.word.word}:</
font
>
</
h1
>
<
h2
>
<
ul
>
<#list quizItem.meanings as meaning>
<#if meaning == answer>
<#-- 用户答案 -->
<
li
><
font
color
=
"red"
>${meaning}</
font
></
li
>
<#elseif meaning == quizItem.word.meaning>
<#-- 正确答案 -->
<
li
><
font
color
=
"blue"
>${meaning}</
font
></
li
>
<#else>
<#-- 其他选项 -->
<
li
>${meaning}</
li
>
</#if>
</#list>
</
ul
>
</
h2
>
<
h1
>
<
a
href
=
""
>Continue...</
a
>
</
h1
>
|
第三步,在org.apdplat.superword.system.AntiRobotFilter类中准备模板需要的数据:
1
2
3
|
Map<String, Object> data =
new
HashMap<>();
data.put(
"quizItem"
, quizItem);
data.put(
"answer"
, _answer);
|
第四步,编写一个工具类org.apdplat.superword.freemarker.TemplateUtils,将模板和数据融合生成最终的HTML代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
package
org.apdplat.superword.freemarker;
import
freemarker.template.Configuration;
import
freemarker.template.Template;
import
freemarker.template.TemplateExceptionHandler;
import
org.apdplat.superword.model.QuizItem;
import
org.slf4j.Logger;
import
org.slf4j.LoggerFactory;
import
java.io.StringWriter;
import
java.io.Writer;
import
java.util.HashMap;
import
java.util.Map;
/**
* 模板工具, 用于生成html代码
* Created by ysc on 4/2/16.
*/
public
class
TemplateUtils {
private
TemplateUtils(){}
private
static
final
Logger LOGGER = LoggerFactory.getLogger(TemplateUtils.
class
);
private
static
final
Configuration CFG =
new
Configuration(Configuration.VERSION_2_3_23);
static
{
LOGGER.info(
"开始初始化模板配置"
);
CFG.setClassLoaderForTemplateLoading(TemplateUtils.
class
.getClassLoader(),
"/template/freemarker/"
);
CFG.setDefaultEncoding(
"UTF-8"
);
if
(LOGGER.isDebugEnabled()) {
CFG.setTemplateExceptionHandler(TemplateExceptionHandler.HTML_DEBUG_HANDLER);
}
else
{
CFG.setTemplateExceptionHandler(TemplateExceptionHandler.IGNORE_HANDLER);
}
CFG.setLogTemplateExceptions(
false
);
LOGGER.info(
"模板配置初始化完毕"
);
}
/**
* 在识别用户是否是机器人的测试中, 如果用户测试失败, 则向用户显示这里生成的HTML代码
* @param data 需要两个数据项, 一是测试数据集quizItem, 二是用户的回答answer
* @return 测试结果HTML代码
*/
public
static
String getIdentifyQuiz(Map<String, Object> data){
try
{
Template template = CFG.getTemplate(
"identify_quiz.ftlh"
);
Writer out =
new
StringWriter();
template.process(data, out);
return
out.toString();
}
catch
(Exception e){
LOGGER.error(
"generate authentication template failed"
, e);
}
return
""
;
}
public
static
void
main(String[] args) {
Map<String, Object> data =
new
HashMap<>();
QuizItem quizItem = QuizItem.buildIdentifyHumanQuiz(
12
);
data.put(
"quizItem"
, quizItem);
data.put(
"answer"
,
"random answer"
);
System.out.println(TemplateUtils.getIdentifyQuiz(data));
}
}
|
第五步,在org.apdplat.superword.system.AntiRobotFilter类中删除JAVA代码生成HTML的逻辑,转而使用如下代码:
1
2
3
4
|
Map<String, Object> data =
new
HashMap<>();
data.put(
"quizItem"
, quizItem);
data.put(
"answer"
, _answer);
String html = TemplateUtils.getIdentifyQuiz(data);
|
大功告成!看一下页面输出效果:
最后看一下模板引擎的日志输出,第一次访问:
1
2
3
4
5
6
7
|
开始初始化模板配置
模板配置初始化完毕
0 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.
1 DEBUG [2016-04-02 22:04:25] TemplateLoader.findTemplateSource(
"identify_quiz_en_US.ftlh"
): Not found
2 DEBUG [2016-04-02 22:04:25] TemplateLoader.findTemplateSource(
"identify_quiz_en.ftlh"
): Not found
2 DEBUG [2016-04-02 22:04:25] TemplateLoader.findTemplateSource(
"identify_quiz.ftlh"
): Found
2 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"
|
第二次:
1
2
3
4
|
5324 DEBUG [2016-04-02 22:04:30] TemplateLoader.findTemplateSource(
"identify_quiz_en_US.ftlh"
): Not found
5325 DEBUG [2016-04-02 22:04:30] TemplateLoader.findTemplateSource(
"identify_quiz_en.ftlh"
): Not found
5325 DEBUG [2016-04-02 22:04:30] TemplateLoader.findTemplateSource(
"identify_quiz.ftlh"
): Found
5325 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.
|
第三次:
1
2
3
4
|
81642 DEBUG [2016-04-02 22:05:47] TemplateLoader.findTemplateSource(
"identify_quiz_en_US.ftlh"
): Not found
81643 DEBUG [2016-04-02 22:05:47] TemplateLoader.findTemplateSource(
"identify_quiz_en.ftlh"
): Not found
81643 DEBUG [2016-04-02 22:05:47] TemplateLoader.findTemplateSource(
"identify_quiz.ftlh"
): Found
81643 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.