Struts 2.x权威指南
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.4.7 数组属性的类型转换器

对于前面的示例应用中的转换器,我们一直只处理字符串数组的第一个数组元素——假设请求参数是单个值,而不是一个字符串数组。实际上,我们必须考虑请求参数是字符串数组的情形,考虑如图4.11所示的输入页面。

图4.11 输入多个同名请求参数的页面

此页面中包含两个用户信息的请求参数,名称都是 users,这两个请求参数必须通过getParameterValues方法来获取参数。此时,users请求参数必须是数组类型,或者List类型(实际上,List和数组是完全相通的)。

下面是处理该请求的Action类代码。

程序清单:codes\04\4.4\ArrayConverter\WEB-INF\src\org\crazyit\struts2\action\LoginAction.java

public class LoginAction implements Action
{
    private User[] users;
    private Date birth;
    private String tip;
    // users属性的setter和getter方法
    public void setUsers(User[] users)
    {
          this.users = users;
    }
    public User[] getUsers()
    {
          return this.users;
    }
    // 省略其他属性的setter和getter方法
    ...
    // 处理请求的execute方法
    public String execute() throws Exception
    {
          // 调用users数组的第一个元素的name属性和pass属性进行判断
          if (getUsers()[0].getName().equals("crazyit")
                && getUsers()[0].getPass().equals("leegang") )
          {
                setTip("转换成功");
                return SUCCESS;
          }
          else
          {
                setTip("转换失败");
                return ERROR;
          }
    }
}

上面的Action使用了User数组类型属性来封装user请求参数。下面是本应用的类型转换器代码。

程序清单:codes\04\4.4\ArrayConverter\WEB-INF\src\org\crazyit\struts2\action\UserConverter.java

public class UserConverter extends StrutsTypeConverter
{
    // 处理将字符串类型转换成复合类型的方法
    public Object convertFromString(Map context,
          String[] values, Class toClass)
    {
          // 如果请求参数数组的长度大于1
          if (values.length > 1)
          {
                // 创建一个User数组
                User[] result = new User[values.length];
                // 遍历请求参数数组
                for (int i = 0; i < values.length ; i++ )
                {
                    // 将每个数组元素转换成一个User实例
                    User user = new User();
                    String[] userValues = values[i]
                          .split(",");
                    user.setName(userValues[0]);
                    user.setPass(userValues[1]);
                    // 将转换的User实例装入数组
                    result[i] = user;
                }
                return result;
          }
          // 如果请求参数数组的长度为1
          else
          {
                // 创建一个User实例
                User user = new User();
                // 将请求参数转换成一个User实例
                String[] userValues = values[0].split(",");
                user.setName(userValues[0]);
                user.setPass(userValues[1]);
                return user;
          }
    }
    // 处理把复合类型转换成字符串类型的方法
    public String convertToString(Map context, Object o)
    {
          // 如果需要转换的值是单个的User实例
          if (o instanceof User)
          {
                User user = (User)o;
                return "<" + user.getName() + ","
                      + user.getPass() + ">";
          }
          // 如果需要转换的值是User数组
          else if (o instanceof User[])
          {
                User[] users = (User[])o;
                String result = "[";
                for (User user : users )
                {
                      result += "<" + user.getName()
                          + "," + user.getPass() + ">";
                }
                return result + "]";
          }
          else
          {
                return "";
          }
    }
}

上面的类型转换器更加完善,它不仅处理了单一请求参数的情形,即values数组长度为1时;也处理了多个请求参数的情形,即 values 数组长度大于 1 的情形。因此,本应用中的类型转换器完全可以代替前面应用里的类型转换器。

在图4.11所示页面的三个输入框内分别输入crazyit,leegang、abc,xyz和2003-02-12,然后提交请求,将看到如图4.12所示的页面。

图4.12 数组属性的类型转换器

对于本示例而言,此处使用局部类型转换器和全局类型转换器的效果是相同的。但底层的转换细节是不同的。

如果使用局部类型转换器,那么类型转换器将会对 users 属性本身起作用,此时名为users的请求参数是一个长度为2的数组。因此,convertFromString方法中的value参数是一个长度为2的数组。局部类型转换器对Action的指定属性起作用。因此,Action每包含一个需要类型转换的属性(不管该属性是单个属性,还是以数组形式存在),类型转换器的convertFromString方法只执行一次。

如果使用全局类型转换器,那么类型转换器将会对所有的User类起作用,上面的users请求参数是一个长度为2的字符串数组,它对应于Action的users属性,将转换成一个长度为2的User数组,因此此处类型转换器的convertFromString方法执行两次。