8. 类型转换器

8.1 默认的类型转换器

  1. <bean type="com.opensymphony.xwork2.conversion.impl.CollectionConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.CollectionConverter" scope="singleton"/>
  2. <bean type="com.opensymphony.xwork2.conversion.impl.ArrayConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.ArrayConverter" scope="singleton"/>
  3. <bean type="com.opensymphony.xwork2.conversion.impl.DateConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.DateConverter" scope="singleton"/>
  4. <bean type="com.opensymphony.xwork2.conversion.impl.NumberConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.NumberConverter" scope="singleton"/>
  5. <bean type="com.opensymphony.xwork2.conversion.impl.StringConverter" name="struts" class="com.opensymphony.xwork2.conversion.impl.StringConverter" scope="singleton"/>
  1. - 常见的类型基本均可由String转换为相应类型

int和Integer
float和Float
long和Long
double和Double
char和Character
boolean和Boolean
Date:可以接收yyyy-MM-dd或yyyy-MM-dd HH:mm:ss格式字符串
数组:可以将多个同名参数,存放到数组
集合:可将数据保存到List、Map

8.2 自定义类型转换器

  1. package typeconverters;
  2. import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
  3. import java.text.ParseException;
  4. import java.text.SimpleDateFormat;
  5. import java.util.Date;
  6. /**
  7. * 自定义类型转化器
  8. * 类型转化是双向的,页面到服务端的转换value是String[]
  9. * @author mycomputer
  10. */
  11. public class MyDateConverter extends DefaultTypeConverter {
  12. /**
  13. * 值类型转换
  14. * @param value 要转换的值
  15. * @param toType 要转换的类型
  16. * @return 对应类型的值
  17. */
  18. @Override
  19. public Object convertValue(Object value, Class toType) {
  20. SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
  21. try {
  22. //由客户端到服务端
  23. if (toType == Date.class) {
  24. return sdf.parse(((String[]) value)[0]);
  25. }
  26. //由服务端到客户端
  27. else if (toType == String.class){
  28. return sdf.format((Date)value);
  29. }
  30. } catch (ParseException e) {
  31. e.printStackTrace();
  32. }
  33. return super.convertValue(value,toType);
  34. }
  35. }

8.3 局部类型转换的注册

  1. - 仅针对于指定Action起作用,注册方式:在Action类所在包下,创建一个ActionClassName-conversion.properties文件(ActionClassName是具体Action类的类型-conversion.properties是固定写法),该文件的内容格式为:属性名称=类型转换器的全类名

自定义类型转换器的配置有两中方式: 在使用局部自定义类型转换器时,在对应Action类所在的包下新建xxxAction-conversion.properties文件,其他配置一切正常,页面提交数据至Action时未经过注册转换器,注册失败,原因如下:

  1. 基于字段的配置:

    在字段所在的Model(可能是Action,可能是一个JavaBean)的包下,新建一个ModelClassName-conversion.properties文件。 在该文件中输入键值对:fieldName=类型转换器的去类名。 在新建xxx-conversion.properties时参照的位置并非是xxxAction类,而是要转换字段所在的类,注册文件名应为ModelClassName-conversion.properties 2.基于类型的配置: 在src下新建xwork-conversion.properties文件; 键入:待转换的类型=类型转换器的全类名。

  1. - 数据格式错误返回错误信息

通过让Action继承ActionSupport
image.png
通过在struts.xml对应action的result里面添加以下内容使其回到原页面

  1. <result name="input">/index.jsp</result>
  1. - 数据回显(通过struts标签实现form表达数据的提交)
  1. <!-- 缺点:错误信息对用户不友好 -->
  2. <s:form action="zhuce" method="POST">
  3. <s:textfield name="birthday" label="生日"/>
  4. <s:submit value="登录"/>
  5. </s:form>
  1. - 类型转换异常信息修改

在Action所在包中添加一个ActionClassName.properties的属性文件,在该文件中写入内容,invalid.fieldvalue.变量名=异常提示信息

  1. - 实现多种时间格式验证
  1. package typeconverters;
  2. import com.opensymphony.xwork2.ActionContext;
  3. import com.opensymphony.xwork2.conversion.TypeConversionException;
  4. import com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter;
  5. import java.text.ParseException;
  6. import java.text.SimpleDateFormat;
  7. import java.util.Date;
  8. import java.util.regex.Pattern;
  9. /**
  10. * 自定义类型转化器
  11. * 类型转化是双向的,页面到服务端的转换value是String[]
  12. * @author mycomputer
  13. */
  14. public class MyDateConverter extends DefaultTypeConverter {
  15. /**
  16. * 值类型转换
  17. * @param value 要转换的值
  18. * @param toType 要转换的类型
  19. * @return 对应类型的值
  20. */
  21. @Override
  22. public Object convertValue(Object value, Class toType) {
  23. SimpleDateFormat sdf = null;
  24. try {
  25. //由客户端到服务端
  26. if (toType == Date.class) {
  27. //实现多种时间格式验证
  28. sdf = getSimpleDateFormat(((String[]) value)[0]);
  29. //存到域空间中
  30. ActionContext.getContext().getSession().put("sdf",sdf);
  31. return sdf.parse(((String[]) value)[0]);
  32. }
  33. //由服务端到客户端
  34. else if (toType == String.class){
  35. sdf = (SimpleDateFormat) ActionContext.getContext().getSession().get("sdf");
  36. return sdf.format((Date)value);
  37. }
  38. } catch (ParseException e) {
  39. e.printStackTrace();
  40. }
  41. return super.convertValue(value,toType);
  42. }
  43. private SimpleDateFormat getSimpleDateFormat(String source) {
  44. SimpleDateFormat sdf = null;
  45. if (Pattern.matches("^\\d{4}-\\d{2}-\\d{2}$",source)){
  46. sdf = new SimpleDateFormat("yyyy-MM-dd");
  47. }else if (Pattern.matches("^\\d{4}/\\d{2}/\\d{2}$",source)){
  48. sdf = new SimpleDateFormat("yyyy/MM/dd");
  49. }else if (Pattern.matches("^\\d{4}\\d{2}\\d{2}$",source)){
  50. sdf = new SimpleDateFormat("yyyyMMdd");
  51. }else {
  52. throw new TypeConversionException();
  53. }
  54. return sdf;
  55. }
  56. }

9. 数据验证

  • 为防止客户端传来的数据引发程序异常,除了需要进行客户端验证,还需要进行服务端验证

9.1 手工编写代码实现对Action所有方法进行验证

  1. package actions;
  2. import com.opensymphony.xwork2.ActionSupport;
  3. import java.util.Date;
  4. import java.util.regex.Pattern;
  5. /**
  6. * 继承ActionSupport类,重写validate方法
  7. * @author mycomputer
  8. */
  9. public class LoginAction extends ActionSupport{
  10. private Date birthday;
  11. private int age;
  12. private String name;
  13. private String mobile;
  14. public String getName() {
  15. return name;
  16. }
  17. public void setName(String name) {
  18. this.name = name;
  19. }
  20. public String getMobile() {
  21. return mobile;
  22. }
  23. public void setMobile(String mobile) {
  24. this.mobile = mobile;
  25. }
  26. public int getAge() {
  27. return age;
  28. }
  29. public void setAge(int age) {
  30. this.age = age;
  31. }
  32. public Date getBirthday() {
  33. return birthday;
  34. }
  35. public void setBirthday(Date birthday) {
  36. this.birthday = birthday;
  37. }
  38. public String zhuce(){
  39. return "success";
  40. }
  41. public String dosome(){
  42. return "success";
  43. }
  44. @Override
  45. public void validate() {
  46. if (name == null || "".equals(name.trim())){
  47. //如果fieldErrors.size() > 0,则自动跳转到input视图
  48. this.addFieldError("name","用户名不能为空");
  49. }
  50. if (mobile == null || "".equals(mobile.trim())){
  51. this.addFieldError("mobile","电话不能为空");
  52. }else if (Pattern.matches("^1[345789]\\d{9}$",mobile)){
  53. this.addFieldError("mobile","电话格式有错");
  54. }
  55. }
  56. }
  1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
  2. <%@ taglib prefix="s" uri="/struts-tags" %>
  3. <html>
  4. <head>
  5. <title>注册页面</title>
  6. </head>
  7. <body>
  8. <s:fielderror/>
  9. <s:form action="zhuce" method="POST">
  10. <s:textfield name="age" label="年龄"/>
  11. <s:textfield name="birthday" label="生日"/>
  12. <s:textfield name="name" label="名字"/>
  13. <s:textfield name="mobile" label="电话"/>
  14. <s:submit value="登录"/>
  15. </s:form>
  16. </body>
  17. </html>

9.2 手工编写代码实现对Action指定方法进行验证

  1. //在实现对Action所有方法进行验证基础上,将validate方法名之后加上指定方法的方法名,
  2. //方法名首字母大写
  3. public void validateDosome() {
  4. if (name == null || "".equals(name.trim())){
  5. this.addFieldError("name","用户名不能为空");
  6. }
  7. if (mobile == null || "".equals(mobile.trim())){
  8. this.addFieldError("mobile","电话不能为空");
  9. }else if (Pattern.matches("^1[345789]\\d{9}$",mobile)){
  10. this.addFieldError("mobile","电话格式有错");
  11. }
  12. }

9.3 基于XML配置方式实现输入数据验证

  1. - 使用XML配置方式实现输入数据的验证,Action类仍需要继承自ActionSupport类。验证仍分为两类:对Action中所有方法执行前的验证、对Action 中指定方法执行前的验证
  2. - 该验证方式需要使用XML配置文件,该配置文件的约束,即文件头部,在xwork-core-2.3.24.jar中的根下的xwork-validatior-1.0.3.dtd中可以找到
  3. - Action中所有方法执行前的验证
  4. - Action类所在的包中放入一个XML配置文件,该文件的取名应遵守ActionClassName-validation.xml规则
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <!DOCTYPE validators PUBLIC
  3. "-//Apache Struts//XWork Validator 1.0.3//EN"
  4. "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
  5. <validators>
  6. <field name="name">
  7. <field-validator type="requiredstring">
  8. <!--<param name="trim">true</param>-->
  9. <message>用户名不能为空</message>
  10. </field-validator>
  11. </field>
  12. <field name="mobile">
  13. <field-validator type="requiredstring">
  14. <message>电话不能为空</message>
  15. </field-validator>
  16. <field-validator type="regex">
  17. <param name="regex"><![CDATA[
  18. ^1[345789]\d{9}$
  19. ]]></param>
  20. <message>电话格式不正确</message>
  21. </field-validator>
  22. </field>
  23. </validators>
  1. - Action中指定方法执行前的验证
  2. - 更改XML文件的文件名命名规则为:ActionClassName-ActionName_MethodName-validation.xml

9.4 常用验证器的用法

  1. - required:非空(必填)验证
  1. <field-validator type="required">
  2. <message>性别不能为空</message>
  3. </field-validator>
  1. - requiredstring:非空字符串验证
  1. <field-validator type="requiredstring">
  2. <!--<param name="trim">true</param>-->
  3. <message>用户名不能为空</message>
  4. </field-validator>
  1. - fieldexpression:字段表达式验证
  1. <field-validator type="fieldexpression">
  2. <!-- 表达式只能是== -->
  3. <param name="expression">pwd == repwd</param>
  4. <message>确认密码与密码不一致</message>
  5. </field-validator>
  1. - stringlength:字符串长度验证
  1. <field-validator type="stringlength">
  2. <param name="minLength">2</param>
  3. <param name="maxLength">10</param>
  4. <param name="trim">true</param>
  5. <message>产品名称应在${minLength}-${maxLength}之间</message>
  6. </field-validator>
  1. - int:整数范围校验
  1. <field-validator type="int">
  2. <param name="min">1</param>
  3. <param name="max">150</param>
  4. <message>年龄须在1-150之间</message>
  5. </field-validator>

注意,int、long、short、double 与 date校验器均继承自RangeValidatorSupport类,是范围校验器,即不对数据类型进行校验,只对其有效范围进行校验。它们均有两个参数min与max。

  1. - email:邮件验证
  1. <field-validator type="email">
  2. <message>电子邮件无效</message>
  3. </field-validator>
  1. - regex:正则表达式验证
  1. <!-- <![CDATA[]]>成为cDate区,用于存放特殊表达式 -->
  2. <field-validator type="regex">
  3. <param name="regex"><![CDATA[
  4. ^1[345789]\d{9}$
  5. ]]></param>
  6. <message>电话格式不正确</message>
  7. </field-validator>

9.5 Action方法的执行流程

1、类型转换
类型转换失败是在Action调用相应属性的set方法之前发生,类型转换失败,不影响程序的运行
2、set方法
无论类型转换是否成功,都将执行该属性的set方法。当类型转换失败,会设置该属性值为null
3、数据验证
当验证器对通过set方法设置的属性值进行验证时,若验证失败,则会将验证失败信息写入到一个专门的集含中 fieldErrors集合。当所有数据验证完毕后,若fieldErrors集合中存在异常信息,即集合的size()大于0,则workFlow拦截器会返回一个”input”字符串,使请求转发到input视图。请求将无法到达 Action,即无法执行Action方法;当然,若在类型转换时已经发生异常,不仅会将异常信息写入到fieldErrors集合,还会继承执该属性的set方法,将null值赋予该属性。该属性接收到的为null值,肯定不是用户输入的期望的值,所以在进行数据验证时,也一定会验证失败。此时的验证失败信息也同样会写入到 fieldErrors集合
4、Action方法
经过上面的执行,如果系统中的fieldErrors集合存在异常信息,系统会自动将请求转发至input视图。如果系统中的fieldErrors没有任何异常信息,系统将执行Action方法

10. 拦截器

  • 拦截器是 Struts2的一个重要特性。因为Struts2的大多数核心功能都是通过拦截器实现的。拦截器之所以称之为”拦截器“,是因为它可以在执行Action方法之前拦截住用户请求,执行一些操作;或在 Action方法执行之后拦截住向用户发送的响应,执行一些操作。即在Acton方法执行之前或之后执行,以增强 Action方法的功能。Struts2内置了很多拦截器,每个拦截器完成相对独立的功能,多个拦截器的组合体称为拦截器栈。最为重要的拦截器栈是系统默认的拦截器栈DefaultStack。拦截器定义在struts2-core-2.3.24.jar!struts-default.xml 中

  • 实现拦截器: ```java package interceptors;

import com.opensymphony.xwork2.ActionContext; import com.opensymphony.xwork2.ActionInvocation; import com.opensymphony.xwork2.interceptor.AbstractInterceptor;

/**

  • 也可实现Interceptor接口
  • @author mycomputer */ public class MyInterceptor extends AbstractInterceptor {

    @Override public String intercept(ActionInvocation actionInvocation) throws Exception {

    1. Object user = ActionContext.getContext().getSession().get("user");
    2. if (user != null){
    3. //调用Action方法
    4. return actionInvocation.invoke();
    5. }
    6. return "fail";

    } } xml <?xml version=”1.0” encoding=”UTF-8” ?> <!DOCTYPE struts PUBLIC “-//Apache Software Foundation//DTD Struts Configuration 2.3//EN” “http://struts.apache.org/dtds/struts-2.3.dtd">

  1. <package name="zhuce" namespace="/" extends="struts-default">
  2. <interceptors>
  3. <interceptor name="myinster" class="interceptors.MyInterceptor"/>
  4. </interceptors>
  5. <action name="zhuce" class="actions.LoginAction" method="zhuce">
  6. <result name="success">/success.jsp</result>
  7. <result name="input">/index.jsp</result>
  8. <result name="fail">/index.jsp</result>
  9. <interceptor-ref name="myinster"/>
  10. <interceptor-ref name="defaultStack"/>
  11. </action>
  12. </package>

  1. - 定义、注册拦截器(通过拦截器栈)
  2. ```xml
  3. <?xml version="1.0" encoding="UTF-8" ?>
  4. <!DOCTYPE struts PUBLIC
  5. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  6. "http://struts.apache.org/dtds/struts-2.3.dtd">
  7. <struts>
  8. <package name="zhuce" namespace="/" extends="struts-default">
  9. <interceptors>
  10. <interceptor name="myinster" class="interceptors.MyInterceptor"/>
  11. <interceptor-stack name="mystack">
  12. <interceptor-ref name="myinster"/>
  13. <interceptor-ref name="defaultStack"/>
  14. </interceptor-stack>
  15. </interceptors>
  16. <action name="zhuce" class="actions.LoginAction" method="zhuce">
  17. <result name="success">/success.jsp</result>
  18. <result name="input">/index.jsp</result>
  19. <result name="fail">/index.jsp</result>
  20. <interceptor-ref name="mystack"/>
  21. </action>
  22. </package>
  23. </struts>
  1. <package name="zhuce" namespace="/" extends="struts-default">
  2. <interceptors>
  3. <interceptor name="myinster" class="interceptors.MyInterceptor"/>
  4. <interceptor-stack name="mystack">
  5. <interceptor-ref name="myinster"/>
  6. <interceptor-ref name="defaultStack"/>
  7. </interceptor-stack>
  8. </interceptors>
  9. <!-- 注册到默认拦截器,需注意action里面不要写
  10. <interceptor-ref name="mystack"/>覆盖了默认拦截器 -->
  11. <default-interceptor-ref name="mystack"/>
  12. <action name="zhuce" class="actions.LoginAction" method="zhuce">
  13. <result name="success">/success.jsp</result>
  14. <result name="input">/index.jsp</result>
  15. <result name="fail">/index.jsp</result>
  16. </action>
  17. </package>

  1. <a name="uEiiG"></a>
  2. #### 10.1 方法过滤拦截器
  3. ```xml
  4. <?xml version="1.0" encoding="UTF-8" ?>
  5. <!DOCTYPE struts PUBLIC
  6. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  7. "http://struts.apache.org/dtds/struts-2.3.dtd">
  8. <struts>
  9. <package name="zhuce" namespace="/" extends="struts-default">
  10. <interceptors>
  11. <interceptor name="myinster" class="interceptors.MyInterceptor">
  12. <!-- 拦截doFirst,doSecond方法 -->
  13. <!--<param name="includeMethods">doFirst,doSecond</param>-->
  14. <!-- 除了doThird方法都拦截 -->
  15. <param name="excludeMethods">doThird</param>
  16. </interceptor>
  17. <interceptor-stack name="mystack">
  18. <interceptor-ref name="myinster"/>
  19. <interceptor-ref name="defaultStack"/>
  20. </interceptor-stack>
  21. </interceptors>
  22. <default-interceptor-ref name="mystack"/>
  23. <action name="zhuce" class="actions.LoginAction" method="zhuce">
  24. <result name="success">/success.jsp</result>
  25. <result name="input">/index.jsp</result>
  26. <result name="fail">/index.jsp</result>
  27. </action>
  28. </package>
  29. </struts>

10.2 拦截器的执行顺序

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE struts PUBLIC
  3. "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
  4. "http://struts.apache.org/dtds/struts-2.3.dtd">
  5. <struts>
  6. <package name="zhuce" namespace="/" extends="struts-default">
  7. <interceptors>
  8. <interceptor name="oneInterceptor" class="interceptors.MyInterceptor">
  9. <param name="excludeMethods">doThird</param>
  10. </interceptor>
  11. <interceptor name="twoInterceptor" class="interceptors.MyInterceptorTwo">
  12. <param name="includeMethods">doFirst,doSecond</param>
  13. </interceptor>
  14. <interceptor-stack name="mystack">
  15. <!-- 拦截器的执行顺序与注册的顺序是一致的 -->
  16. <interceptor-ref name="oneInterceptor"/>
  17. <interceptor-ref name="twoInterceptor"/>
  18. <interceptor-ref name="defaultStack"/>
  19. </interceptor-stack>
  20. </interceptors>
  21. <default-interceptor-ref name="mystack"/>
  22. <action name="zhuce" class="actions.LoginAction" method="zhuce">
  23. <result name="success">/success.jsp</result>
  24. <result name="input">/index.jsp</result>
  25. <result name="fail">/index.jsp</result>
  26. </action>
  27. </package>
  28. </struts>

11. 国际化