温故知新:struts2_03参数的传递

struts2的参数传递和OGNL息息相关,先从几个OGNL的案例来感受一下

OGNL的概念和作用,不赘述,直接百科传送门:http://baike.baidu.com/view/1347280.htm。使用OGNL可以极为灵活的在页面上对目标对象进行存取操作,而不仅仅是只是数据的展示。下面使用OGNL给出几个常用的例子。
测试用实体类User和Department
 1 package demo.ognlDemo;
 2 
 3 public class User {
 4 
 5     private String name;
 6     private int age;
 7     private Department department;
 8 
 9     public void hello(String name) {
10         System.out.println("hello " + name);
11     }
12 
13     public static void sayHi() {
14         System.out.println("HI");
15     }
16 
17     public User() {
18         super();
19     }
20 
21     public User(String name, int age, Department department) {
22         super();
23         this.name = name;
24         this.age = age;
25         this.department = department;
26     }
27    //get/set方法略
28}

 1 package demo.ognlDemo;
 2 
 3 public class Department {
 4 
 5     private String name;
 6     private int no;
 7    
 8     //get/set方法略
 9
} 

下面给出测试类
 1 package demo.ognlDemo;
 2 
 3 import java.util.ArrayList;
 4 import java.util.HashMap;
 5 import java.util.List;
 6 import java.util.Map;
 7 
 8 import ognl.Ognl;
 9 import ognl.OgnlException;
10 
11 import org.junit.Test;
12 
13 
14 public class OgnlDemo {
15 
16     @Test
17     public void test01() {
18         
19         //定义两个演示用的对象
20         User u = new User();
21         u.setAge(20);
22         u.setName("Tom");
23         
24         Department dep = new Department();
25         dep.setName("Security");
26         dep.setNo(10);
27         
28         u.setDepartment(dep);
29         
30         //一个根map
31         Map<String , Object> ctx = new HashMap<String, Object>();
32         ctx.put("user", u);
33         ctx.put("department", dep);
34         
35         try {
36             //下列表达式都是在以指定对象为根进行属性查找
37             //以u为根
38             System.out.println(Ognl.getValue("name", u));
39             System.out.println(Ognl.getValue("age", u));
40             System.out.println(Ognl.getValue("department.name", u));
41             System.out.println("====================================");
42             //以dep为根
43             System.out.println(Ognl.getValue("name", dep));
44             System.out.println(Ognl.getValue("no", dep));
45             System.out.println("====================================");
46             
47             //以集合为根
48             System.out.println(Ognl.getValue("department.name", ctx,ctx));
49             //从根的集合中取值需要添加#来区分
50             System.out.println(Ognl.getValue("#department.name", ctx,u));
51             //访问对象的方法
52             System.out.println(Ognl.getValue("hello('Jerry')",ctx,u));
53             //访问静态的方法,格式为@XXX.XXX.XXX(包名...类名)@XXX(静态方法名)
54             System.out.println(Ognl.getValue("@demo.ognlDemo.User@sayHi()",u));
55             //root是根元素的键值,通过#root可以直接取得根元素
56             System.out.println(Ognl.getValue("#root.name", ctx,u));
57             System.out.println("====================================");
58             
59             //以一个集合为根,取得其中的某个元素
60             List<User> users = new ArrayList<User>();
61             User u1 = new User();
62             u1.setName("zhangsan");
63             User u2 = new User();
64             u2.setName("lisi");
65             users.add(u1);
66             users.add(u2);
67             System.out.println(Ognl.getValue("#root[0].name",users));
68             
69             //或者
70             System.out.println(Ognl.getValue("get(0).name",users));
71             
72         } catch (OgnlException e) {
73             e.printStackTrace();
74         }
75     }
76 }

下面回到struts2,struts2中的所有参数都保存在ValueStack中,而ValueStack就是一个OGNL结构。ValueStack由两部分组成,一个是ActionContext,类似于OGNL的Map集合,另一个是compoundRoot,类似于OGNL的根对象,使用ArrayList维护了一个栈结构。而参数则可以通过三种方式进行传递。
方法一:
在action中添加属性,并为属性添加get/set方法
这个方法实际上就是在ValueStack的根中创建一个action对象,取值的时候如果没有特别指定,则默认取得栈顶的对象。在取值的时候从栈顶开始依次向下获取,根据Key值返回第一个取得的值,同时,我们也可以对ValueStack进行操作,使用ActionContext.getContext().getValueStack()获得ValueStack,进行push,peek或者remove等操作
方法二:
使用ActionContext存放值
方法三:
使用ServletActionContext存放值

Action:
 1 package demo.ognlDemo;
 2 
 3 import org.apache.struts2.ServletActionContext;
 4 
 5 import com.opensymphony.xwork2.ActionContext;
 6 
 7 public class DemoAction {
 8     //1:通过action属性传值
 9     private String name;
10     private String age;
11     
12     public String execute(){
13         
14         name = "Tom";
15         age = "99";
16         
17         //2:通过actioncontext传值
18         ActionContext.getContext().put("demokey"99999999);
19         
20         //3:通过servletActionContext进行传值
21         ServletActionContext.getRequest().setAttribute("servletkey"00000000);
22         
23         return "success";
24     }
25     //get/set方法略
26
27 }
JSP:
 1 <%@ page language="java" contentType="text/html; charset=UTF-8" isELIgnored="false"
 2     pageEncoding="UTF-8"%>
 3 <%@taglib prefix="s" uri="/struts-tags" %>
 4 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 5 <html>
 6 <head>
 7 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 8 <title>struts2 Demo</title>
 9 </head>
10 <body>
11 
12 对于EL表达式而言,不论值存放在什么地方,都可以取得,但是使用struts2的标签,需要注意key值的写法
13 
14 <hr>
15 通过属性进行传值:<br>
16 EL表达式 -->${name}:${age}<br>
17 s:property标签 --<s:property value="name"/> : <s:property value="age"/>
18 <hr>
19 
20 通过actionContext进行传值<br>
21 EL表达式--> ${demokey}<br>
22 s:property标签(访问actionContext中的数据,需要在键值之前添加“#”) --<s:property value="#demokey"/>
23 <hr>
24 
25 通过servletActionContext进行传值<br>
26 EL表达式 -->${servletkey}<br>
27 s:property标签 (访问servletActionContext中的数据,需要在键值之前添加“#”,并且需要注明范围:request/session/application)--<s:property value="#request.servletkey"/>
28 <hr>
29 </body>
30 </html>
为了能查看更详细的信息,开发过程中可以在页面中加入调试标签
1 <s:debug/>
标签展开之后Value Stack Contents就是根的内容,Stack Context就是集合的内容

上述内容是从action到jsp的参数传递,下面是从jsp到action的参数传递
方法一:
通过地址栏参数进行参数传递,/XXX?param=YYY,在Action里可以直接通过对应的属性来获取,或者直接通过servletActionContext取得request,获取参数值。
这种方法对于少量的参数传递来说没有问题,但是碰到大量的参数或者中文,其他特殊参数的传递就显得力不从心,可能需要经过转码进行传递,不方便。
方法二:
表单传递参数,较直接使用地址栏传参安全一些,但是参数一多,仍然很头疼。可以使用以下方法将需要获取的值注入到指定的对象中。
1:比如,在通常情况下,为了传递多个值到一个user对象中,我们可以将表单域的名字写为
1 <input name="user.id" id="uid"/>
这样一来,user的id属性就会接收到相应的值,以此类推,user的其他属性值都可以参照此写法。表单提交之后,在action中就可以使用user进行操作。
2:或者我们可以使action实现ModelDriven<T>接口,这样一来在传递表单的时候,表单域的name属性就无需指定要传递到的对象,直接写作
1 <input name="id" id="uid"/>
ModelDriven实际上就是在ValueStack中,root里的action之上又添加了一个指定的对象,该对象就是实现接口时指定的T,提交表单的时候,参数的值会根据root中的对象,从上到下依次填充,表单域中的属性首先填充到ModelDrive的对象。

上面提到的这两种值填充,在某些情况下可能会有问题,要填充的属性若是非String类型,比如Date类型,这样就无法直接转换,但是一般来说前端会使用控件来限制日期格式的输入,然后通过String来接收日期字符串,自行转换。struts2提供了这种问题的解决方案,虽然用的不多,但是见仁见智,转换器有时也有它的用武之地。
要使用struts2的转换器,需要新建类,然后继承StrutsTypeConverter
 1 package demo.ognlDemo;
 2 
 3 import java.text.ParseException;
 4 import java.text.SimpleDateFormat;
 5 import java.util.Date;
 6 import java.util.Map;
 7 
 8 import org.apache.struts2.util.StrutsTypeConverter;
 9 /**
10  * 自定义的局部转换器,将时间和字符串进行转换
11  * @author Administrator
12  *
13  */
14 public class DateConverter extends StrutsTypeConverter{
15 
16     SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
17     
18     /**
19      * 字符串到对象
20      */
21     @SuppressWarnings("rawtypes")
22     @Override
23     public Object convertFromString(Map context, String[] values, Class toClass) {
24         
25         try {
26             if (values.length > 0 && values.length <= 1) {
27                 String str = values[0];
28                 return sdf.parse(str);
29             }
30             return null;
31         } catch (ParseException e) {
32             e.printStackTrace();
33             return null;
34         }
35         
36         
37     }
38 
39     /**
40      * 对象到字符串
41      */
42     @SuppressWarnings("rawtypes")
43     @Override
44     public String convertToString(Map context, Object o) {
45         Date d = (Date)o;
46         return d.toString();
47     }
48 
49 }
50 
给出一个字符串和日期相互转换的例子,重写父类的convertFromStringconvertToString方法,convertFromString意味着吧页面上传递过来的String参数经过加工变成自己想要的参数类型,values是参数数组,一般只有一个。convertToString意味着将参数从action传出到页面的时候需要进行的转换。写好转换器之后,就需要配置自定义转换器的使用,转换器有局部和全局之分,两种都需要定义对应的properties文件。

局部转换器,也就是针对某个action用的转换器,需要定义名为“action名称-conversion.properties”的配置文件,并且该文件需要和对应的action置于同一目录,里面配置哪些属性需要用哪个转换器转换。这段配置就意味着对应action中的creDate(Date类型)的属性,使用DateConverter转换
1 creDate = demo.ognlDemo.DateConverter

全局转换器不限于哪个action使用,对整个项目都生效,需要配置名为“xwork-conversion.properties”的配置文件,置于src目录下,里面需要配置具体action的具体哪个属性用哪个转换器转换
1 demo.ognlDemo.XXXAction.creDate = demo.ognlDemo.DateConverter

posted on 2014-10-30 16:38 都较瘦 阅读(163) 评论(0)  编辑  收藏 所属分类: MVCFramework


只有注册用户登录后才能发表评论。


网站导航:
 
<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

导航

统计

公告

博客定位:囿于目前的水平,博客定位在记录自己的学习心得和随手的练习

常用链接

留言簿

随笔分类

随笔档案

文章分类

文章档案

搜索

最新评论

阅读排行榜

评论排行榜