您的位置:首页 > 编程语言 > Java开发

Struts 2之HelloWorld(下)

2010-08-19 13:22 281 查看
七.完成程序的国际化
因为一个企业应用经常要面对多区域的用户,因此,程序国际化是一个企业应用必须实现的功能.Struts2提供了非常好的程序国际化的支持.
(1) 定义国际化资源文件
程序国际化设计思想是非常简单的,其主要的思想就是:程序界面中需要输出国际化信息的地方,我们不要再页面中直接输出信息,而是输出一个key值,该key值在不同的语言下对应不同的字符串.当程序需要显示的时候,程序将根据不同的语言环境,加载该key对应语言环境下的字符串,这样就可以完成程序的国际化.
为了给本应用增加程序国际化支持(支持中文和英文),则应该提供两份语言资源文件,下面是本应用程序所使用的中文语言环境下的资源文件的代码:
view plaincopy to clipboardprint?
1. loginPage=登录页面
2. errorPage=错误页面
3. succPage=成功页面
4. failTip=对不起,您不能够登录
5. viewLink=查看图书列表
6. bookPageTitle=所有图书列表
7. bookName=书名
8. user=用户名
9. pass=密码
10. login=登录
loginPage=登录页面 errorPage=错误页面 succPage=成功页面 failTip=对不起,您不能够登录 viewLink=查看图书列表 bookPageTitle=所有图书列表 bookName=书名 user=用户名 pass=密码 login=登录
因为资源文件中包含了非西欧字符,因此必须使用native2ascii命令来处理该文件,将上面的文件保存在WEB-INF/classes路径下,文件名称为”messageResource.properties”保存该文件后,使用native2ascii命令来处理该文件,处理该文件的命令格式为:
view plaincopy to clipboardprint?
1. native2ascii messageResource.properties messageResources_zh_CN.properties
native2ascii messageResource.properties messageResources_zh_CN.properties
上面命令将包含非西欧字符的资源文件处理成ASCII格式,处理完成后生成了一份新的文件:messageResource_zh_CN.properties文件.这个文件的文件名符合资源文件的命名格式,资源文件的文件名的命名格式为:
view plaincopy to clipboardprint?
1. basename_语言代码_国家代码.properties
basename_语言代码_国家代码.properties
当请求来自简体中文的语言环境的时候,系统将自动的使用这种资源文件的内容输出.
除此之外,还应该提供如下英文语言环境下的资源文件:
view plaincopy to clipboardprint?
1. loginPage=Login Page
2. errorPage=Error Page
3. succPage=Welcome Page
4. failTip=Sorry,you can't log in!
5. viewLink=View Books
6. bookPageTitle=All Books List
7. bookName=Book Name
8. user=User Name
9. pass=Password
10. login=Login
loginPage=Login Page errorPage=Error Page succPage=Welcome Page failTip=Sorry,you can't log in! viewLink=View Books bookPageTitle=All Books List bookName=Book Name user=User Name pass=Password login=Login
将上面的资源文件保存在/WEB-INF/classes路径下面,文件名字为”messageResource_cn_US.properties”.当请求来自美国的时候,系统自动使用这份资源文件内容输出.
(2) 加载资源文件
Struts2支持在JSP页面当中临时加载资源文件,也支持通过全局属性来加载资源文件,通过全局属性加载资源文件更加简单,本应用使用全局属性加载Struts2国际化资源文件.
加载资源文件可以通过struts.properties文件来定义,本应用的struts.properties文件仅有一行代码:
view plaincopy to clipboardprint?
1. //定义Struts 2的资源文件的baseName是messageResource
2. struts.custom.i18n.resources=messageResource
//定义Struts 2的资源文件的baseName是messageResource struts.custom.i18n.resources=messageResource
在struts.properties文件中增加上面的代码定义之后,表明该应用使用的资源文件的baseName为”messageResource”这与我们的前面保存的资源文件的baseName是一直的.
Struts2默认加载WEB-INF/classes下面的资源文件,如果将该资源文件放在/WEB-INF/classes中的子路径下面,则需要修改struts.properties中的定义如下:
view plaincopy to clipboardprint?
1. struts.custom.i18n.resources=supermos.messageResource
struts.custom.i18n.resources=supermos.messageResource
(3) 输出国际化信息
为了让程序可以显示国际化信息,则需要在JSP页面中输出key,而不是直接输出字符串常量.
Struts2中提供了如下两种方式来输出国际化信息
①:使用s:text标签来输出国际化信息.
②使用表达式方式输出国际化信息.
因此,我们再次修改表现层的JSP页面,使用国际化标签输出国际化信息.修改后的showBook.jsp页面代码如下:
view plaincopy to clipboardprint?
1. <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>
2.
3. <%@taglib uri="/struts-tags" prefix="s"%>
4.
5.
6.
7. <s:property value="%{getText('bookPageTitle')}"/>
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. <%@ page language="java" import="java.util.*" pageEncoding="utf-8"%>

<%@taglib uri="/struts-tags" prefix="s"%>

<s:property value="%{getText('bookPageTitle')}"/>

我们发现,上面的JSP页面不再包含任何直接字符串,而是全部通过来输出国际化信息.
我们可以通过调整系统语言环境来观看本系统的运行状况.
八.增加数据校验
在上面的应用中,即使浏览器输入任何的用户名,密码系统也会处理用户的请求,在我们的整个Helloworld应用中,这种空用户名,空密码的问题不会引起太大的问题,但是如果数据需要保存到数据库,或者需要根据用户输入的用户名,密码查询数据,这些数据就可能会引发异常.
为了避免用户的输入引起底层的异常,通常,我们会在进行业务逻辑的操作之前,先执行基本的数据校验.
(1) 继承ActionSupport
ActionSupport类是一个工具类,它已经实现了Action接口,除此之外,它还实现了Validateable接口,提供了数据的校验功能.通过继承该ActionSupport类,可以简化Struts2的Action开发.
在Validatable接口中定义了一个validate()方法,重写该方法,如果校验表单输入域出现错误,则将错误添加到ActionSupport类中的fieldErrors域中,然后通过OGNL表达式负责输出.
为了让Struts2增加输入数据校验功能,改写程序中的LoginAction,增加重写validate方法,修改后的LoginAction类代码如下:
view plaincopy to clipboardprint?
1. package com.supermos.app;
2.
3. import com.opensymphony.xwork2.Action;
4. import com.opensymphony.xwork2.ActionContext;
5. import com.opensymphony.xwork2.ActionSupport;
6.
7. public class LoginAction extends ActionSupport implements Action {
8. private String username;
9. private String password;
10.
11. public String getUsername() {
12. return username;
13. }
14.
15. public void setUsername(String username) {
16. this.username = username;
17. }
18.
19. public String getPassword() {
20. return password;
21. }
22.
23. public void setPassword(String password) {
24. this.password = password;
25. }
26.
27. public String execute() throws Exception {
28.
29. if ("supermos".equalsIgnoreCase(username)
30. && "ziwen".equalsIgnoreCase(password)) {
31. // 通过ActionContext对象访问Web应用的Session
32. ActionContext.getContext().getSession().put("user", getUsername());
33. return SUCCESS;
34. } else {
35. return ERROR;
36. }
37. }
38.
39. // 完成输入校验需要重写的validate方法
40. public void validate() {
41. // 如果用户名为空,或者用户名为空字符串
42. if (getUsername() == null || getUsername().trim().equals("")) {
43. // 添加表单校验错误
44. addFieldError("username", "user.required");
45. }
46. // 如果密码为空,或者用户名为空字符串,添加表单校验错误
47. if (getPassword() == null || getPassword().trim().equals("")) {
48. // 添加表单校验错误
49. addFieldError("password", "password.required");
50. }
51. }
52. }
package com.supermos.app; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport implements Action { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { if ("supermos".equalsIgnoreCase(username) && "ziwen".equalsIgnoreCase(password)) { // 通过ActionContext对象访问Web应用的Session ActionContext.getContext().getSession().put("user", getUsername()); return SUCCESS; } else { return ERROR; } } // 完成输入校验需要重写的validate方法 public void validate() { // 如果用户名为空,或者用户名为空字符串 if (getUsername() == null || getUsername().trim().equals("")) { // 添加表单校验错误 addFieldError("username", "user.required"); } // 如果密码为空,或者用户名为空字符串,添加表单校验错误 if (getPassword() == null || getPassword().trim().equals("")) { // 添加表单校验错误 addFieldError("password", "password.required"); } } }
上面的Action重写了validate方法,该方法会在执行系统的execute方法之前执行,如果执行该方法之后,Action类的fieldErrors中已经包含了数据校验的错误,请求将被转发到input逻辑视图处.
为了在校验失败之后,系统能够将试图转入input处,必须在配置Action时候配置input属性,下面是修改之后的loginAction的配置片段:
view plaincopy to clipboardprint?
1.
2.
5.
6.
7.
8. /login.jsp
9. /success.jsp
10. /fail.jsp
11.
12.
13. /login.jsp
14. /showBook.jsp
15.
16.
17.
/login.jsp /success.jsp /fail.jsp /login.jsp /showBook.jsp
运行测试一下,我们发现我们并未在输入页面输出这些校验错误信息,但是页面上却自己输出了..这是因为struts2的标签,上面的JSP页面中表单使用的不是HTML表单,而是使用了标签,这种标签已经具备了输出校验错误的能力.(Struts 2的默认已经提供了输出校验错误的能力)
但是上面的程序还有一个问题:校验信息的国际化,查看上面的Action代码发现,重写validate方法的时候,如果发生校验失败的问题,校验错误的提示信息时以硬编码的形式写死了..这样就是去了国际化的能力.
实际上,ActionSupport类已经提供了国际化信息的能力,它提供了一个getText(String key)的方法,该方法用于从资源文件中获取国际化信息,为了让校验信息支持国际化,再次改写Action里的validate方法,修改之后的validate方法代码如下:
view plaincopy to clipboardprint?
1. package com.supermos.app;
2.
3. import com.opensymphony.xwork2.Action;
4. import com.opensymphony.xwork2.ActionContext;
5. import com.opensymphony.xwork2.ActionSupport;
6.
7. public class LoginAction extends ActionSupport implements Action {
8. private String username;
9. private String password;
10.
11. public String getUsername() {
12. return username;
13. }
14.
15. public void setUsername(String username) {
16. this.username = username;
17. }
18.
19. public String getPassword() {
20. return password;
21. }
22.
23. public void setPassword(String password) {
24. this.password = password;
25. }
26.
27. public String execute() throws Exception {
28.
29. if ("supermos".equalsIgnoreCase(username)
30. && "ziwen".equalsIgnoreCase(password)) {
31. // 通过ActionContext对象访问Web应用的Session
32. ActionContext.getContext().getSession().put("user", getUsername());
33. return SUCCESS;
34. } else {
35. return ERROR;
36. }
37. }
38.
39. // 完成输入校验需要重写的validate方法
40. public void validate() {
41. // 如果用户名为空,或者用户名为空字符串
42. if (getUsername() == null || getUsername().trim().equals("")) {
43. // 添加表单校验错误
44. addFieldError("username", getText("user.required"));
45. }
46. // 如果密码为空,或者用户名为空字符串,添加表单校验错误
47. if (getPassword() == null || getPassword().trim().equals("")) {
48. // 添加表单校验错误
49. addFieldError("password", getText("password.required"));
50. }
51. }
52. }
package com.supermos.app; import com.opensymphony.xwork2.Action; import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionSupport; public class LoginAction extends ActionSupport implements Action { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String execute() throws Exception { if ("supermos".equalsIgnoreCase(username) && "ziwen".equalsIgnoreCase(password)) { // 通过ActionContext对象访问Web应用的Session ActionContext.getContext().getSession().put("user", getUsername()); return SUCCESS; } else { return ERROR; } } // 完成输入校验需要重写的validate方法 public void validate() { // 如果用户名为空,或者用户名为空字符串 if (getUsername() == null || getUsername().trim().equals("")) { // 添加表单校验错误 addFieldError("username", getText("user.required")); } // 如果密码为空,或者用户名为空字符串,添加表单校验错误 if (getPassword() == null || getPassword().trim().equals("")) { // 添加表单校验错误 addFieldError("password", getText("password.required")); } } }
在上面的validate方法中,添加校验错误提示的时候,并不是直接给出了错误的字符串,而是调用了getText方法来获取错误提示.在国际化资源文件中添加这两条提示信息.(ActionSupport增加了让提示信息国际化的能力,ActionSupport提供的getText方法可以根据资源文件加载获得国际化提示信息.)
(2) 使用Struts2的校验框架
上面的方法是通过重写ActionSupport类的validate方法来实现的,这种方法虽然不错,但是需要大量重写validate方法,毕竟重复书写相同的代码不是一件吸引人的事情.
就像Struts1一样,Struts2也允许通过定义配置文件来完成数据的校验,Struts2的校验框架实际上是基于Xwork的validator框架:
下面还是使用原来的Action类(即不重写validate方法),却增加了一个校验配置文件,校验配置文件通过使用Struts2已有的校验器,完成对表单域的校验.Struts2提供了大量的数据校验器,包括表单域校验器和非表单域校验器两种.
本应用主要使用了requiredstring校验器,该校验器是一个必填校验器---指定某个表单域必须输入.
下面是校验规则的定义文件:
view plaincopy to clipboardprint?
1.
2.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.

定义完该校验规则文件之后,该文件的命名应该遵守如下规则:
ActionName-validate.xml:其中ActionName就是需要校验的Action的类名
因此上面的校验规则文件就应该命名为”LoginAction-validate.xml”且,该文件应该与Action类的class文件位于同一个路径下.
当然,在struts.xml文件的Action定义中,一样需要定义input的逻辑视图名,并将input逻辑视图映射到login.jsp表单.
如果不输入用户名,密码而提交表单,将再次看到如图2.14所示的界面.在这种校验方式下,无需书写校验代码,只要通过配置文件配置指定的校验规则就可以了.因此提供了更好的可维护性.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: