6.7 在Struts中使用Velocity
的模板语言。在WebWork早期版本中是默认的模板编写语言,不过升级Struts2后更加推荐使用FreeMarker,因为它有比Velocity更好的错误报告,支持JSP Tag,还有其他一些细微优点。当然,它们都是JSP很好的替代品。由Velocity编写的文件后缀名为“.vm”。(请参考第5章中关于Velocity Result的介绍)。
本节介绍Velocity在Struts2中是如何应用的,Velocity的详细使用方法请参考Velocity文档。Velocity是apache基金会支持的一个项目,可以访问它的网站http://velocity.apache.org/来学习它。
6.7.1 最简单的应用
开始使用velocity,首先需要保证所有的依赖都已经被加入到工程的CLASSPATH。其次,struts-default.xml中要配置好VelocityResult,它将映射action和模板。这里给出的例子功能与6.6节给出的基本一样,只是把登录功能改成注册功能。具体步骤如下:
1)在web.xml文件配置关于Struts2和velocity,具体内容如实例6-23所示。
【实例6-23】web.xml配置文件:web.xml
01 <filter> 02 <filter-name>struts2</filter-name> 03 <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> 04 </filter> 05 <!--FilterDispatcher用来初始化Struts2并且处理所有的Web请求--> 06 <filter-mapping> 07 <filter-name>struts2</filter-name> 08 <url-pattern>/*</url-pattern> 09 </filter-mapping> 10 <servlet> 11 <servlet-name>velocity</servlet-name> 12 <servlet-class>org.apache.velocity.tools.view.VelocityViewServlet</servlet- 13 class> 14 </servlet> 15 <servlet-mapping> 16 <servlet-name>velocity</servlet-name> 17 <url-pattern>*.vm</url-pattern> 18 </servlet-mapping> 19 <welcome-file-list> 20 <welcome-file>index.jsp</welcome-file> 21 </welcome-file-list> 22 </web-app>
【代码剖析】上述代码的第6行到第9行实现对Struts2核心过滤器的配置,接着配置类velocity,该类支持在velocity中进行一些配置。
2)利用velocity模板创建出关于注册、注册成功和注册失败页面,具体内容如实例6-24、实例6-25和实例6-26所示。
【实例6-24】关于注册页面:register.vm
01 <html> 02 <head> 03 <title>register</title> 04 </head> 05 <body> 06 <form action="userRegister.action" method="post"> 07 <table align="center"> 08 <tr> 09 <td> 10 注册页面 11 </td> 12 <td> 13 </td> 14 </tr> 15 <tr> 16 <td> <!--关于用户名输入框--> 17 用户名: 18 <input type="text" name="username"> 19 </td> 20 </tr> 21 <tr> 22 <td> <!--关于密码输入框--> 23 密码: 24 <input type="password" 25 name="password"> 26 27 </td> 28 </tr> 29 <tr> 30 <td> <!--关于年龄输入框--> 31 年龄: 32 <input type="text" name="age"> 33 34 </td> 35 </tr> 36 <tr> 37 <td> <!--关于提交按钮--> 38 <input type="submit" name="submit" 39 value="提交" /> 40 </td> 41 </tr> 42 </table> 43 </form> 44 </body> 45 </html>
【运行程序】浏览该页面,结果如图6.19所示。
【代码剖析】上述代码只是普通的HTML代码,不过该文件的后缀名.vm。
【实例6-25】关于注册成功页面:success.vm
01 <html> 02 <head> 03 <title>success</title> 04 </head> 05 <body> 06 以下是您注册的信息: 07 <br> 08 用户名:$username <!--显示用户名--> 09 <br> 10 密码:$password <!--显示密码--> 11 <br> 12 年龄:$age <!--显示年龄--> 13 <br> 14 </body> 15 </html>
【运行程序】注册成功,结果如图6.20所示。
图6.19 注册页面
图6.20 注册成功
【代码剖析】上述代码中通过$属性名,来输出保存在Session中user对象相应属性的值。
【实例6-26】关于登录失败页面:error.vm
01 <html> 02 <head> 03 <title>error</title> 04 </head> 05 <body> 06 $state <!--显示相应的信息--> 07 </body> 08 </html>
【运行程序】注册失败,结果如图6.21所示。
图6.21 注册失败
【代码剖析】上述代码中第6行$state表示输出保存在ActionContext中的值。
3)建立Action类,该类主要通过获取HTTP请求、参数等,然后实现该项目的逻辑功能,具体内容如实例6-27所示。
【实例6-27】关于Action类:RegiserAction.java
01 public class RegiserAction implements Action { 02 private String username; //关于用户名变量 03 private String password; //关于密码变量 04 private int age; //关于年龄变量 05 public String getUsername() { //设置用户名的getter和setter方法 06 return username; 07 } 08 public void setUsername(String username) { 09 this.username = username; 10 } 11 public String getPassword() { //设置密码的getter和setter方法 12 return password; 13 } 14 public void setPassword(String password) { 15 this.password = password; 16 } 17 public int getAge() { //设置年龄的getter和setter方法 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 public String execute() throws Exception { //重写执行方法 24 // 判断注册的用户名是否存在 25 ActionContext ctx = ActionContext.getContext(); 26 if (this.getUsername().equals("cjgong")) { 27 ctx.put("state", "该用户名已经存在, 请重新注册"); 28 return "error"; //返回出错字符串 29 } else { 30 ctx.put("username", this.getUsername()); 31 ctx.put("password", this.getPassword()); 32 ctx.put("age", this.getUsername()); 33 return "success"; //返回成功字符串 34 } 35 } 36 }
【代码剖析】上述代码首先创建了关于用户名字和密码的属性,然后为这些属性创建方法,最后在execute()方法中实现了该项目的逻辑功能。
如果想让该项目正常运行,还必须在struts.xml文件中配置上述代码,具体内容如实例6-28所示。
【实例6-28】关于struts配置文件:struts.xml
01 <struts> 02 <package name="com" extends="struts-default"> 03 <action name="*"> 04 <result type="velocity">/userRegister/{1}.vm</result> 05 </action> 06 <action name="userRegister" class="com.cjg.RegiserAction"> 07 <!--指定result的type为velocity--> 08 <result name="success" type="velocity"> 09 /userRegister/success.vm 10 </result> 11 <result name="error" type="velocity"> 12 /userRegister/error.vm 13 </result> 14 </action> 15 </package> 16 </struts>
【代码剖析】上述代码中将标签<result>的type设为velocity,当注册成功则会转向success.vm,当注册失败则会转向error.vm。
6.7.2 变量解析
在Velocity中,将从几个不同的位置查找变量。顺序如下:
1)值栈(value stack)。
2)action上下文(context)。
3)内置对象。
Velocity中内置对象如表6.27所示。
表6.27 Velocity内置对象表
6.7.3 配置Velocity
有时可能希望扩展Struts2提供的Velocity支持。最常见的原因是希望加入自己的标签,就像从Struts2内建的标签中扩展一样。
想要这样做,写一个新的扩展自com.opensymphony.webwork. views.velocity.VelocityManager的类或者也可以覆盖它,然后增加如下内容到webwork.properties:
webwork.velocity.manager.classname = com.yourcompany.YourVelocityManager
可以通过替换velocity.properties中的配置项来配置Velocity。
6.7.4 在VM文件中使用标签
Velocity标签是WebWork提供的一般Tag的扩展,只要简单地了解这些标签的访问方式: #sxxx (...) ... #end (),就可以马上开始使用了。
注意
“#s”后面是没有空格的,它与标签名称直接连在一起(虽然不会发生什么混乱,但在阅读上实在很不舒服,而且Velocity没有采用主流的XML格式)。
还是那个例子,在JSP中可能这样创建一个form:
<s:form action="updatePerson"> <s:textfield label="First name" name="firstName"/> <s:submit value="Update"/> </s:form>
在Velocity中同样的form这样创建:
#sform ("action=updatePerson") #stextfield ("label=First name" "name=firstName") #ssubmit ("value=Update") #end
在上面的例子中注意到,一些标签需要“#end”声明,而其他的却不需要。这是由于Velocity中的限制,如果有块(block)或者内联(inline)标签在前面,标签必须声明#end。而默认情况下所有的标签都是内联(inline)的,除了很少的几个,例如form标签。