`

struts2.0表单form的提交

阅读更多

Struts2.0里面有一个非常牛*的功能就是支持更高级的POJO访问,这句话是什么意思呢?下面来通过例子实际操作一把就能体会到这个功能的强大与好使了。

要实现的功能:如果用户输入用户名xiaozu,密码111111,则显示welcome,xiaozhu!否则提示用户名或密码错误。

下面是我们所需的文件:


登陆页面login.jsp:

Java代码 复制代码
  1. <%@ page language="java" contentType="text/html; charset=utf-8"%>    
  2. <%@ taglib prefix="s" uri="/struts-tags" %>    
  3. <!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
  4. <html>    
  5. <head>    
  6. <title>登陆页面</title>    
  7. </head>    
  8. <body>    
  9. <s:form action="/test/loginAction.action" method="post">    
  10.     <s:textfield name="userName" label="用户名"/>    
  11.     <s:password name="password" label="密码"/>    
  12.     <s:submit/>    
  13. </s:form>    
  14. </body>    
  15. </html>   
<%@ page language="java" contentType="text/html; charset=utf-8"%> 
<%@ taglib prefix="s" uri="/struts-tags" %> 
<!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<title>登陆页面</title> 
</head> 
<body> 
<s:form action="/test/loginAction.action" method="post"> 
    <s:textfield name="userName" label="用户名"/> 
    <s:password name="password" label="密码"/> 
    <s:submit/> 
</s:form> 
</body> 
</html> 




请求处理LoginAction.java:

Java代码 复制代码
  1. package tutorial;    
  2.   
  3. import com.opensymphony.xwork2.ActionSupport;    
  4.   
  5. public class LoginAction extends ActionSupport {    
  6.   
  7.     private String msg="显示默认消息";    
  8.     private String userName;    
  9.     private String password;    
  10.   
  11.     public String getPassword() {    
  12.        return password;    
  13.     }    
  14.   
  15.     public void setPassword(String password) {    
  16.        this.password = password;    
  17.     }    
  18.   
  19.   
  20.     public String getUserName() {    
  21.        return userName;    
  22.     }    
  23.   
  24.   
  25.     public void setUserName(String userName) {    
  26.        this.userName = userName;    
  27.     }    
  28.   
  29.     public String getMsg() {    
  30.        return msg;    
  31.     }    
  32.   
  33.     public String execute(){    
  34.     if ("xiaozhu".equals(userName)&&"111111".equals(password)) {    
  35.         msg="welcome,"+userName;    
  36.        } else {    
  37.             msg="用户名或密码错误";    
  38.        }    
  39.     return this.SUCCESS;    
  40.     }    
  41. }   
package tutorial; 

import com.opensymphony.xwork2.ActionSupport; 

public class LoginAction extends ActionSupport { 

    private String msg="显示默认消息"; 
    private String userName; 
    private String password; 

    public String getPassword() { 
       return password; 
    } 

    public void setPassword(String password) { 
       this.password = password; 
    } 


    public String getUserName() { 
       return userName; 
    } 


    public void setUserName(String userName) { 
       this.userName = userName; 
    } 

    public String getMsg() { 
       return msg; 
    } 

    public String execute(){ 
    if ("xiaozhu".equals(userName)&&"111111".equals(password)) { 
        msg="welcome,"+userName; 
       } else { 
            msg="用户名或密码错误"; 
       } 
    return this.SUCCESS; 
    } 
} 



响应页面HelloWorld.jsp:

Java代码 复制代码
  1. <%@ page language="java" contentType="text/html; charset=utf-8"%>    
  2. <%@ taglib prefix="s" uri="/struts-tags" %>    
  3. <!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
  4. <html>    
  5.     <head>    
  6.         <title>Hello</title>    
  7.     </head>    
  8.     <body>    
  9.         <h3><s:property value="msg"/></h3>    
  10.     </body>    
  11. </html>   
<%@ page language="java" contentType="text/html; charset=utf-8"%> 
<%@ taglib prefix="s" uri="/struts-tags" %> 
<!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
    <head> 
        <title>Hello</title> 
    </head> 
    <body> 
        <h3><s:property value="msg"/></h3> 
    </body> 
</html> 



如上所示,对于login.jsp表单中的每个值域我们都会在相应的action中声明一个对应的属性并产生相应的get和set方法,如果这个表单中的值很多(例如注册用户信息的表单),就会导致action十分庞大和容易混乱,并且也不利于我们的软件分层,违背了OO的原则,下面看一下改进后的方案。


登陆页面login.jsp:

Java代码 复制代码
  1. <%@ page language="java" contentType="text/html; charset=utf-8"%>    
  2. <%@ taglib prefix="s" uri="/struts-tags" %>    
  3. <!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
  4. <html>    
  5. <head>    
  6. <title>Insert title here</title>    
  7. </head>    
  8. <body>    
  9. <s:form action="/test/loginAction.action" method="post">    
  10.     <s:textfield name="user.userName" label="用户名"/>    
  11.     <s:password name="user.password" label="密码"/>    
  12.     <s:submit/>    
  13. </s:form>    
  14. </body>    
  15. </html>   
<%@ page language="java" contentType="text/html; charset=utf-8"%> 
<%@ taglib prefix="s" uri="/struts-tags" %> 
<!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
<head> 
<title>Insert title here</title> 
</head> 
<body> 
<s:form action="/test/loginAction.action" method="post"> 
    <s:textfield name="user.userName" label="用户名"/> 
    <s:password name="user.password" label="密码"/> 
    <s:submit/> 
</s:form> 
</body> 
</html> 



新增实体类User.java:

Java代码 复制代码
  1. package tutorial;    
  2.   
  3. public class User {    
  4.     private String userName;    
  5.     private String password;    
  6.        
  7.     public String getPassword() {    
  8.        return password;    
  9.     }    
  10.   
  11.     public void setPassword(String password) {    
  12.        this.password = password;    
  13.     }    
  14.   
  15.     public String getUserName() {    
  16.        return userName;    
  17.     }    
  18.   
  19.     public void setUserName(String userName) {    
  20.        this.userName = userName;    
  21.     }    
  22. }   
package tutorial; 

public class User { 
    private String userName; 
    private String password; 
    
    public String getPassword() { 
       return password; 
    } 

    public void setPassword(String password) { 
       this.password = password; 
    } 

    public String getUserName() { 
       return userName; 
    } 

    public void setUserName(String userName) { 
       this.userName = userName; 
    } 
} 



请求处理LoginAction.java:

Java代码 复制代码
  1. package tutorial;    
  2.   
  3. import com.opensymphony.xwork2.ActionSupport;    
  4.   
  5. public class LoginAction extends ActionSupport {    
  6.   
  7.     private String msg="显示默认消息";    
  8.     private User user;    
  9.   
  10.     public User getUser() {    
  11.        return user;    
  12.     }    
  13.   
  14.     public void setUser(User user) {    
  15.        this.user = user;    
  16.     }    
  17.   
  18.     public String getMsg() {    
  19.        return msg;    
  20.     }    
  21.   
  22.     public String execute(){    
  23. if("xiaozhu".equals(user.getUserName())&&"111111".equals(user.getPassword()))    
  24.         msg="welcome,"+user.getUserName();    
  25.     else    
  26.         msg="用户名或密码错误";    
  27.     return this.SUCCESS;//    
  28.     }    
  29. }   
package tutorial; 

import com.opensymphony.xwork2.ActionSupport; 

public class LoginAction extends ActionSupport { 

    private String msg="显示默认消息"; 
    private User user; 

    public User getUser() { 
       return user; 
    } 

    public void setUser(User user) { 
       this.user = user; 
    } 

    public String getMsg() { 
       return msg; 
    } 

    public String execute(){ 
if("xiaozhu".equals(user.getUserName())&&"111111".equals(user.getPassword())) 
        msg="welcome,"+user.getUserName(); 
    else 
        msg="用户名或密码错误"; 
    return this.SUCCESS;// 
    } 
} 



响应页面HelloWorld.jsp:

Java代码 复制代码
  1. <%@ page language="java" contentType="text/html; charset=utf-8"%>    
  2. <%@ taglib prefix="s" uri="/struts-tags" %>    
  3. <!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">    
  4. <html>    
  5.     <head>    
  6.         <title>Hello</title>    
  7.     </head>    
  8.     <body>    
  9.         <h3><s:property value="msg"/></h3>    
  10.     </body>    
  11. </html>   
<%@ page language="java" contentType="text/html; charset=utf-8"%> 
<%@ taglib prefix="s" uri="/struts-tags" %> 
<!DOCTYPE html PUBLIC "-//W 3C //DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> 
<html> 
    <head> 
        <title>Hello</title> 
    </head> 
    <body> 
        <h3><s:property value="msg"/></h3> 
    </body> 
</html> 



前后两种处理方式有何不同呢?后者新建了一个User实体类,用于封装从表单中接收的数据,而在action中就不用设置相应的属性和方法了,并且这样做能够让我们的软件层次感更加明显,系统结构也更加清晰。以User为例,描述一下采用这种方式的关键步骤:

1.  在action中定义一个User类型的对象:User user;
2.  表单中各个控件的name属性要采取如下命名规则:对象名.属性名,注意对象名必须与action中定义的一样,属性名也必须和该对象的属性一一对应。如上例中的user.userName和user.password。


注意:

Java代码 复制代码
  1. public User getUser() {    
  2.       return user;    
  3.    }   
 public User getUser() { 
       return user; 
    } 


Action中的这个get方法必须,否则会出现丢值的现象;set方法就更不用说了,必须的。


上述原理解释:

1. 前面讲的自定义类型转换器是基于 OGNL 的 DefaultTypeConverter 类并实现 convertValue() 方法,两个转换方向的逻辑都写在这一个方法中。而 Struts 2 为我们提供了一个 DefaultTypeConverter 的抽象子类 StrutsTypeConverter 来继承,并实现其中两个抽象方法 convertFromString() 和 convertToString(),这要简单易懂。对比 Struts 1 的转换器是要实现 org.apache.commons.beanutils.Converter 接口,以及它的 convert() 方法的。

2. 注意,上面的 convertFromString() 的第二个参数是一个字符串数组,所以可为请求的数组(如请求串为 ?u=1&u=2&u=3)定义转换器,Action 中相应的属性就应为数组或 List,这一方法的返回值也该为相应的类型(数组或List,要通过第三个参数 toClass 来判断是返回数组还是 List 了)。

3. 字符串(如 "user,pass") 转换成 Action 中的复合属性(如 User user) 前面是自定了类型转换器。除此之外,还可以 Struts 2 内置的 OGNL 表达式,更简单的转换,不用写转换器。例如,你的 Action 有属性 User user,只要在 jsp 页面的输入框命名为 user.name  和 user.pass 即可:
        <input type="text" name="user.name"/> 或用标签:<s:textfield name="user.name" label="用户名"/>
        <input type="text" name="user.pass"/>  或用标签:<s:textfield name="user.pass" label="密 码"/>
    提交后,Struts 2 即会帮你构造 User 对象(user = new User()),并赋上属性值(user.setName(),user.setPass()),最后 user 对象赋给 Action (xxxAction.setUser(user))。所以要明白有三个必备的东西:
        1) User 要用一个默认构造方法 2) User 要有对应 name 和 pass 的设置方法 setName() 和 setPass() 3) Action 要有 user 属性的设置方法 setUser(),getUser() 也是要的,至于功用后面能看到。
其实在 Struts 1 中也有这种用法,不过那是在 BeanUtils 中实现的。

4. 如果 Action 中的属性是 Map<String, User> users; 那么与此对应的表单写法就是:(用标签来写)
        <s:textfield name="users['one'].name" label="第一个用户名"/>
        <s:textfield name="users['one'].name" label="第一个密码"/>
        <s:textfield name="users['two'].name" label="第二个用户名"/>
        <s:textfield name="users['two'].name" label="第二个密码"/>
    应该不难想像,这个表单提交后,users  中存储的是什么吧!
    如果是对于 Action 中的  List 属性,List<User> users; 那么与此对应的表单写法就是:
        <s:textfield name="users[0].name" label="第一个用户名"/>
        <s:textfield name="users[0].name" label="第一个密码"/>
        <s:textfield name="users[1].name" label="第二个用户名"/>
        <s:textfield name="users[1].name" label="第二个密码"/>

5. 归纳前面3、4、5 几点,Struts2 的 Action 在设置每一个属性时都会 get 一下相应的元素 getUser() 或 getUsers()。
    对于 3,在设置 user.name 和 user.pass 之前都会 getUser() 来获取 user 属性,如果 user 为 null 就构造 User 对象,然后设置相应的值。假如声明的时候就已构造好 User 对象,如有其他属性如 age=18,并不会被覆盖。
   对于 4 和 5,也是在设置每一个属性前都会调用 getUsers() 判断声明的 Map 或 List 是否为 null,是则构造对应的 HashMap 或  ArrayList() 对象;接着根据 Key 或下标去获取相应位置的元素,如果不存在或为 null 则构造之,然后设置相应属性值。由此可见,若某元素的某个属性未重设值则保留原值,若原来Map或List 已有多个元素,也只会改变到 Key 或索引所对应元素的某个属性。对于 List 有可能出现跳空的情况,如页面只有索引不从 0 开始
         <s:textfield name="users[1].name" label="第二个用户名"/>
        <s:textfield name="users[1].name" label="第二个密码"/>
提交后就会发现,List 属性 users 的第一个元素为 null 了。同时如果尝试一下,你就会发现这里的 List 不能替代为数组 User[] users。
    这种样法,可在 Struts 1 中实现,但要略施些小节,见我的另一篇日志:提交多行数据到Struts的ActionForm的List属性中 ,行为表现完全一致,只是换到 Struts 2 中一切都不用自己操心。

6. 看第四点,Action 之所以知道该构造什么类型的元素完全是由泛型告诉它的。如果不用泛型(比如用的是 JDK1.4),Action 中仅仅声明的是 Map users; 或 List users; Action 该如何处理呢?它也不知道,只能够帮你构造出无类型的 HashMap 和 ArrayList(),填充不了元素。这就必须在局部类型转换的配置文件中来指定集合元素的类型。例如 Action 为 LoginAction,就要在 LoginAction-conversion.properties 中声明了,格式如下:

    #Element_xxx=复合类型,基中 Element 是固定的,xxx 为属性名
    #下面表示为 List 属性 users 的元素为 com.unmi.vo.User 类型
     Element_users=com.unmi.vo.User

    对于 Map,须分别指定 Key 的类型和 Value 的类型
    #Key_xxx=复合类型,基中 Key 是固定的,xxx 为 map 属性名,下面写成 String 都不行的
    Key_users=java.lang.String
    指定 Map 的 Value 的类型与指定 List 元素类型是一样的
    Element_users=com.unmi.vo.User

难怪 Struts 2 要与 1.5 以上 JDK  使用,泛型比配置来得方便。如果硬要用 1.4 JDK,就只有配置类型了,会多很多 conversion 文件的。在 提交多行数据到Struts的ActionForm的List属性中 中类型的确定由 AutoArrayList() 的构造参数完成。

7. Set 是无序集合,所以无法像 List 那样用数字下标来访问,幸好 Struts 2 可为其指定索引属性。例如,LoginAction 声明为 Set users; (这里好像用泛型只能省得了 Element_users 说明,KeyProperty_users 少不了)。则需在 LoginAction-conversion.properties 中写下:
    #指定 Set 的元素类型
    Element_users=com.unmi.vo.User

    #KeyProperty_集合属性名=集合元素的索引属性名,这里为 User 的 name 属性
    KeyProperty_users=name

此时提交页面这么写,最好提交前能根据输入的用户名自动修动输入框的 name。
        用户名: <input name="users('scott').name"/>
        密 码: <input name="users('scott').pass"/>
显示的时候页面可用标签
        用户名: <s:property value="users('scott').name"/>
        密 码: <s:property value="users('scott').pass"/>
注意前面,访问 Set 元素是用的圆括号,而不同于 Map、List、数组是用中括号。我想一般也犯不着非要用 Set 而不用 List,Struts 2 中用 Set 比在 Struts 1 中似乎还麻烦。

8. Struts 2 内建了一批转换器:boolean、char、int、long、float、double 和它们的包装类型;Date,日期格式使用请求所在 Locale 的 SHORT 格式;数组,默认元素为字符串,其他类型则要转换每一个元素?(好像是一次性转换完成的);集合,默认元素为字符串 XWorkList(String.class, Object[]),其他如 List<Integer> ids,类型为 XWorkList(Integer.class, Object[]),XWorkList 继承自 ArrayList。

9. 类型转换出错由 Struts 来帮你处理,在默认拦截器栈中提供了 conversionError 拦截器,不用你写一点代码逻辑。conversionError 在出错时将错误封装成 fieldError,并放在 ActionContext 中。你所要做的就是遵循它的规则,1) 你的 Action 要继承自 ActionSupport,2)在 struts.xml 中声明名为 "input" 的 result,出错时会在 input 逻辑视图显示信息。3)尽量用标签来写输入域(如<s:textfield name="number" label="数量"/>),这样转换出错后,就会像校验失败一样把错误信息显示在每个输入框上面(视模板而定),否则要手工用 <s:fielderror/> 输出在某处。
默认时输出错误信息为(比如是属性 number,输入的是字符串时):Invalid field value for field "number".你可以改变默认显示,在全局国际化资源文件中加上 xwork.default.invalid.fieldvalue={0}字段类型转换失败!。在某些时候,可能还需要对特定字段指定特别的提示信息,那么在名为 ActionName.properties 的局部资源文件中加上 invalid.fieldvalue.属性名=提示信息 (如 invalid.fieldvalue.number=数量格式错误)

10. 最后是集合属性转换错误时的显示,对于页面中的同名输入框,有多个出错误,如果手工用 <s:fieldError/> 只会显示一条错误,但要是输入页是用标签(如<s:textfield name="number" label="数量"/>),仍会在每一个出错的输入框上都提示。至此类型转换的内容也就完结了。


11. struts2

<input type="user.name" value="jack">
<input type="user.name" value="lucy">
action中取得name的值是"jack,lucy".
注意:此处name是字符串类型,不是数组类型

分享到:
评论

相关推荐

    struts2 标签库 帮助文档

    &lt;%@ taglib prefix="s" uri="/struts-tags" %&gt; 就能使用struts2.0的标签库 下面就介绍每个标签的具体应用实例说明:按字母排列 A: 1. 2. &lt;s:a href=""&gt;&lt;/s:a&gt;-----超链接,类似于html里的&lt;a&gt;&lt;/a&gt; 3. ...

    Spring 2.0 开发参考手册

    15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.2. ActionSupport 类 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.6. WebWork 15.7. 更多资源 16. Portlet MVC框架 16.1. 介绍 16.1.1. 控制器 - ...

    Java/JavaEE 学习笔记

    Struts2.0..263 第一章 MVC Model.........................263 第二章 Struts Basic264 第三章 Action,Result & Struts2 Tag Library......................267 第四章 Data Transfer & Type Converter..273 第五...

    J2EE学习笔记(J2ee初学者必备手册)

    Struts2.0..263 第一章 MVC Model.........................263 第二章 Struts Basic264 第三章 Action,Result & Struts2 Tag Library......................267 第四章 Data Transfer & Type Converter..273 第五...

    spring chm文档

    15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.2. ActionSupport 类 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.6. WebWork 15.7. 更多资源 16. Portlet MVC框架 16.1. 介绍 16.1.1. 控制器 - ...

    千方百计笔试题大全

    166、如何用JQuery进行表单验证? 39 167、Prototype如何实现页面局部定时刷新? 40 168、Prototype如何为一个Ajax添加一个参数? 40 169、Ajax请求总共有多少种Callback? 41 170、Javascript如何发送一个Ajax请求?...

    java面试宝典

    166、如何用JQuery进行表单验证? 39 167、Prototype如何实现页面局部定时刷新? 40 168、Prototype如何为一个Ajax添加一个参数? 40 169、Ajax请求总共有多少种Callback? 41 170、Javascript如何发送一个Ajax请求?...

    Spring-Reference_zh_CN(Spring中文参考手册)

    15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.1.1. DelegatingRequestProcessor 15.4.1.2. DelegatingActionProxy 15.4.2. ActionSupport 类 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.5.1.1. 将 ...

    Spring API

    2. Spring 2.0和 2.5的新特性 2.1. 简介 2.2. 控制反转(IoC)容器 2.2.1. 新的bean作用域 2.2.2. 更简单的XML配置 2.2.3. 可扩展的XML编写 2.2.4. Annotation(注解)驱动配置 2.2.5. 在classpath中自动搜索组件...

    Spring中文帮助文档

    15.4. Struts 15.4.1. ContextLoaderPlugin 15.4.2. ActionSupport Classes 15.5. Tapestry 15.5.1. 注入 Spring 托管的 beans 15.6. WebWork 15.7. 更多资源 16. Portlet MVC框架 16.1. 介绍 16.1.1. 控制...

Global site tag (gtag.js) - Google Analytics