6.6 在Struts中使用FreeMarker
FreeMarker是一个Java模板语言,它是JSP的绝佳替代方案,也是一个开源项目。FreeMarker允许Java Servlet保持图形设计同应用程序逻辑的分离,这是通过在模板中密封HTML完成的。模板用Servlet提供的数据动态地生成HTML。由FreeMarker编写的文件后缀名为“.ftl”。在Struts中对FreeMarker提供了完美的支持,只需要在选择result type为FreeMarker就可以使用FreeMarker来输出页面了。(请参考第5章中关于FreeMarker Result的介绍)。
本节介绍FreeMarker在Struts2中是如何应用的,FreeMarker的详细使用方法请参考FreeMarker文档或访问它的网站http://freemarker.org/。
6.6.1 最简单的应用
确认配置好项目的CLASSPATH中的所有依赖以后,就可以开始使用FreeMarker了。典型情况下只需要freemarker.jar。下面将通过该模块实现最简单的登录功能,具体步骤如下:
1)在web.xml文件配置关于Struts2和FreeMarker,具体内容如实例6-17所示。
【实例6-17】web.xml配置文件:web.xml
01 <?xml version="1.0" encoding="UTF-8"?> 02 <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 03 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 04 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 05 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 06 <filter> 07 <filter-name>struts2</filter-name> 08 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> 09 </filter> 10 <filter-mapping> 11 <filter-name>struts2</filter-name> 12 <url-pattern>/*</url-pattern> 13 </filter-mapping> 14 <servlet> 15 <servlet-name>JspSupportServlet</servlet-name> 16 <servlet-class>org.apache.struts2.views.JspSupportServlet</servlet-class> 17 <load-on-startup>1</load-on-startup> 18 </servlet> 19 </web-app>
【代码剖析】上述代码的第6行到第13行实现对Struts2核心过滤器的配置,接着再配置类JspSupportServlet,该类支持在FreeMarker中进行一些配置。
2)利用FreeMarker模板创建出关于登录、登录成功和登录失败页面,具体内容如实例6-18、实例6-19和实例6-20所示。
【实例6-18】关于登录页面:login.ftl
01 <html> 02 <head> 03 <title>login</title> 04 </head> 05 <body> 06 <form action="login.action" method="post"> 07 <center> 08 请登录 09 </center> 10 <table align="center"> 11 <tr> 12 <td> 13 用户名: 14 </td> 15 <td> <!--关于用户名输入框--> 16 <input type="text" name="username" /> 17 </td> 18 </tr> 19 <tr> 20 <td> 21 密码: 22 </td> 23 <td> <!--关于密码输入框--> 24 <input type="password" 25 name="password"> 26 </td> 27 </tr> 28 <tr> 29 <td> <!--关于提交按钮--> 30 <input type="submit" name="submit" 31 value="登录" /> 32 </td> 33 </tr> 34 </table> 35 </form> 36 </body> 37 </html>
【运行程序】浏览该页面,结果如图6.16所示。
【代码剖析】上述代码只是普通的HTML代码,不过该文件的后缀名为.ftl。
【实例6-19】关于登录成功页面:success.ftl
01 <html> 02 <head> 03 <title>success</title> 04 </head> 05 <body> 06 <center> ${user},${state}</center> <!--显示登录成功的信息--> 07 </body> 08 </html>
【运行程序】当登录成功,结果如图6.17所示。
图6.16 浏览页面
图6.17 登录成功
【代码剖析】上述代码中第6行代码里${user}表示输出保存在Session中关于user的值,而${state}表示输出保存在ActionContext中的值。
【实例6-20】关于登录失败页面:error.ftl
01 <html> 02 <head> 03 <title>error</title> 04 </head> 05 <body> 06 <center> ${state} </center> <!--显示登录失败的信息--> 07 </body> 08 </html>
【运行程序】登录失败,结果如图6.18所示。
图6.18 登录失败
【代码剖析】上述代码中第6行代码里${state}表示输出保存在ActionContext中的值。
3)建立Action类,该类主要通过获取HTTP请求、参数等,然后实现该项目的逻辑功能,具体内容如实例6-21所示。
【实例6-21】关于Action类:LoginAction.java
01 public class LoginAction extends ActionSupport { 02 private String username; //关于用户名的变量 03 private String password; //关于密码的变量 04 public String getUsername() { //关于用户名的getter和setter方法 05 return username; 06 } 07 public void setUsername(String username) { 08 this.username = username; 09 } 10 public String getPassword() { //关于密码的getter和setter方法 11 return password; 12 } 13 public void setPassword(String password) { 14 this.password = password; 15 } 16 public String execute() throws Exception { //重写执行方法 17 /* 18 * 只有用户名为cjgong, 密码为123456方可成功登录 19 */ 20 ActionContext ctx = ActionContext.getContext(); 21 if (this.getUsername().equals("cjgong") 22 && this.getPassword().equals("123456")) { 23 ctx.getSession().put("user", this.getUsername()); 24 ctx.put("state", "登录成功"); 25 return SUCCESS; 26 } else { 27 ctx.put("state", "登录失败"); //存储出错信息到变量state 28 return ERROR; 29 } 30 } 31 }
【代码剖析】上述代码中首先创建了关于用户名字和密码的属性,然后为这些属性创建方法,最后在execute()方法中实现了该项目的逻辑功能。
如果想让该项目正常运行,还必须在struts.xml文件中配置上述代码,具体内容如实例6-22所示。
【实例6-22】关于struts配置文件:struts.xml
01 <struts> 02 <package name="com" extends="struts-default"> 03 <action name="login" class="com.cjgong.LoginAction"> 04 <!--指定result的type为freemarker--> 05 <result name="success" type="freemarker"> 06 <param name="location">/userLogin/success.ftl</param> 07 <param 08 name="contentType">text/html;charset=GBK</param> 09 </result> 10 <result name="error" type="freemarker"> 11 <param name="location">/userLogin/error.ftl</param> 12 <param 13 name="contentType">text/html;charset=GBK</param> 14 </result> 15 </action> 16 </package> 17 </struts>
【代码剖析】上述代码中将标签<result>的type设为FreeMarker,当登录成功则会转向success.ftl,当登录失败则会转向error.ftl。
6.6.2 模板加载顺序
Struts2在两个位置查找FreeMarker模板:Web应用程序目录(Web application)、classpath。这个顺序对于在完全编译的jar中提供模板很理想,但是也同时支持在Web应用程序目录中定义这些模板来覆盖jar中的模板文件。事实上,这就是为什么可以覆盖Struts中默认的UI tags和Form Tags的原理。
还有可以通过templatePath上下文变量(context variable)指定一个路径(文件系统中的任意一个目录)。如果指定了该变量,那么这个目录中的内容将会被优先寻找。
6.6.3 在FTL文件中使用标签
再次提醒,Struts2提供标签库与表现方式是分离的,所以在JSP、FreeMarker、Velocity中都可以使用这些标签。例如,在JSP中可能这样创建一个form:
<s:form action="updatePerson"> <s:textfield label="First name" name="firstName"/> <s:submit value="Update"/> </s:form>
用FreeMarker编写的FTL文件中创建同样的form是这样的:
<@s.form action="updatePerson"> <@s.textfield label="First name" name="firstName"/> <@s.submit value="Update"/> </@s.form>
FreeMarker允许动态属性,这就意味着可以给这些标签提供其本不支持的属性。这些不能够直接被应用到标签对象的属性将会被放到这个标签的通用parameters map中。
在FTL文件中使用标签比在JSP中更加灵活,不仅可以替代原本要使用param的情况,还可以在扩展form标签的模板或者主题的时候使用这个功能。例如,创建了一个“3分栏”主题来替代标准的两分栏主题(xhtml),可能想要在第3栏中显示一个叫做“description”的扩展参数.form,可以这样写:
<@s.form action="updatePerson"> <@s.textfield label="First name" name="firstName" description="..."/> <@s.submit value="Update"/> </@s.form>
然后在新模板中可以通过${parameters.description}应用这个description。