主要来学习一下struts2的数据存储

contextMap

动作类的生命周期

动作类是多例的,每一次动过访问,动过类都会实例化,所以是线程安全的。


struts2中是怎么存储数据的了,其实在每次请求到来时,核心控制器StrutsPrepareAndExecuteFilter都会创建一个ActionContext和ValueStack,并且每次动作访问都会创建,我们可以下StrutsPrepareAndExecuteFilter类中的方法:

[java] view plain copy
  1. public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
  2.   
  3.        HttpServletRequest request = (HttpServletRequest) req;  
  4.        HttpServletResponse response = (HttpServletResponse) res;  
  5.   
  6.        try {  
  7.            prepare.setEncodingAndLocale(request, response);  
  8.            prepare.createActionContext(request, response);  
  9.            prepare.assignDispatcherToThread();  
  10.            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {  
  11.                chain.doFilter(request, response);  
  12.            } else {  
  13.                request = prepare.wrapRequest(request);  
  14.                ActionMapping mapping = prepare.findActionMapping(request, response, true);  
  15.                if (mapping == null) {  
  16.                    boolean handled = execute.executeStaticResourceRequest(request, response);  
  17.                    if (!handled) {  
  18.                        chain.doFilter(request, response);  
  19.                    }  
  20.                } else {  
  21.                    execute.executeAction(request, response, mapping);  
  22.                }  
  23.            }  
  24.        } finally {  
  25.            prepare.cleanupRequest(request);  
  26.        }  
  27.    }  

可以看到它有执行
[java] view plain copy
  1. prepare.createActionContext(request, response);  
再去看这个方法:

[java] view plain copy
  1. public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {  
  2.        ActionContext ctx;  
  3.        Integer counter = 1;  
  4.        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);  
  5.        if (oldCounter != null) {  
  6.            counter = oldCounter + 1;  
  7.        }  
  8.          
  9.        ActionContext oldContext = ActionContext.getContext();  
  10.        if (oldContext != null) {  
  11.            // detected existing context, so we are probably in a forward  
  12.            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));  
  13.        } else {  
  14.            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();  
  15.            stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));  
  16.            ctx = new ActionContext(stack.getContext());  
  17.        }  
  18.        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);  
  19.        ActionContext.setContext(ctx);  
  20.        return ctx;  
  21.    }  

可以看到,它有创建了ValueStack和ActionContext,并且从下面ActionContext类可以看到,其创建是关联到当前线程的,所以是安全的

[java] view plain copy
  1. public class ActionContext implements Serializable {  
  2.   
  3.     static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();  

ContextMap存储数据

 ContextMap中存储了很多的数据,但是我们经常用到的数据就是下面的这些部分

struts2的contextmap和valueStack


我们怎样查看到ValueStack和ContextMap中存储的数据呢,Struts2提供了<s:debug标签,它可以让我们查看到ContextMap和ValueStack中的数据。

struts2的contextmap和valueStack

struts2的contextmap和valueStack

可以看到ValueStack是一个list,ContextMap是一个Map型的数据结构,它是以键值对的形式的存储数据的。

在ContextMap中的键有些比较长,有些短,这些短就是开发者所使用的,长值是框架所使用的,基本要使用的就是上面表格中列出的。

例如:我们在session中存储一条数据

[html] view plain copy
  1. <html>  
  2.   <head>  
  3.     <title>用户注册,使用的是struts2的标签</title>  
  4.     <s:head></s:head>  
  5.   </head>  
  6.   <body>  
  7.   <%session.setAttribute("name", "张三"); %>  
  8.  <s:debug></s:debug>  
  9.   </body>  
  10. </html>  

struts2的contextmap和valueStack


ActionContext和ValueStack存储数据

1.向ActonContext存数据

[java] view plain copy
  1. public String saveUser(){  
  2.         //获取ContextMap  
  3.         ActionContext actionContext = ActionContext.getContext();  
  4.         actionContext.put("name""contextMap");  
  5.         //向HttpSession存储数据  
  6.         //得到Session  
  7.         Map<String, Object> session = actionContext.getSession();  
  8.         session.put("name""actionContextSession");  
  9.         //原始Session存储对象  
  10.         HttpSession httpSession = ServletActionContext.getRequest().getSession();  
  11.         httpSession.setAttribute("age""21");  
  12.         return SUCCESS;  
  13.     }  

struts2的contextmap和valueStack

struts2的contextmap和valueStack

从结果可以看到,不管是ContextMap得到的session还是HttpSession得到的session,其数据都存储在相同的地方.

2.向ValueStack存储数据

a.向ValueStack存普通数据

存普通数据有三种方式:

第一种:直接使用set方法

第二种:使用push方法

第三种:生成get方法

[java] view plain copy
  1. public String saveUser(){  
  2.         //获取ContextMap  
  3.         ActionContext actionContext = ActionContext.getContext();  
  4.         //获取值栈对象  
  5.         ValueStack valueStack =actionContext.getValueStack();  
  6.         //使用set方法存储数据  
  7.         valueStack.set("name""valueStack");  
  8.         //使用push方法存储数据  
  9.         valueStack.push("dadadada");  
  10.         return SUCCESS;  
  11.     }  
生成get方法存储数据

[java] view plain copy
  1. public int getNum() {  
  2.         return num;  
  3.     }  
struts2的contextmap和valueStack

b.向值栈存放对象

实现步骤

第一步定义对象变量

第二步生成变量的get方法

第三步在执行的方法里面向对象中设置值

[java] view plain copy
  1.     private User user=new User();  
  2.        public User getUser() {  
  3.         return user;  
  4.     }  
  5.       public String saveUser(){;  
  6.         user.setName("user");  
  7.         user.setGender("gender");  
  8.         return SUCCESS;  
  9.     }  

struts2的contextmap和valueStack

c.存储list集合

存储集合和存储对象是一样的步骤

[java] view plain copy
  1. private List<String> listStr = new ArrayList<String>();  
[java] view plain copy
  1. public String saveUser(){  
  2.         //获取ContextMap  
  3.         ActionContext actionContext = ActionContext.getContext();  
  4.         //获取值栈对象  
  5.         ValueStack valueStack =actionContext.getValueStack();  
  6.         listStr.add("A");  
  7.         listStr.add("B");  
  8.         listStr.add("C");  
  9.         return SUCCESS;  
  10.     }  
[java] view plain copy
  1. public List<String> getListStr() {  
  2.     return listStr;  
  3. }  

取数据:在jsp中使用struts2的ONGL表达式

在Map中取数据:map中取数据ongl使用#key

[html] view plain copy
  1. <s:property value="#name"/>  
  2. <s:property value="#session.name"/>  
struts2的contextmap和valueStack
struts2的contextmap和valueStack

取ValueStack中的数据,ValueStack是一个List,ONGL取list中的数据时直接写属性名

[html] view plain copy
  1. <!--这是ONGL表达式,不是字符串  -->  
  2. <s:property value="name"/>  

struts2的contextmap和valueStack

因为在ValueStack中从上往下找,第一个属性为name就是存储的valueStack

struts2的contextmap和valueStack

如果想要获取下一个属性名为name的值

[html] view plain copy
  1. <s:property value="[1].name"/>  

ValueStack的其它方法

a.setValue

[java] view plain copy
  1. /** 
  2.     * @see com.opensymphony.xwork2.util.ValueStack#setValue(java.lang.String, java.lang.Object) 
  3.     */  
  4.    public void setValue(String expr, Object value) {  
  5.        setValue(expr, value, devMode);  
  6.    }  
可以看到,setValue的name是一个ONGL的表达式,所以,如果expr不加#是存储到ValueStack,否则存储到MAP中。

[java] view plain copy
  1. //有#,表示存储到contextMap中,否则存储到ValueStack中  
  2.         valueStack.setValue("#address""南山");  
  3.         valueStack.setValue("address""南山");  
b.set方法

[java] view plain copy
  1. //如果栈顶是一个map,那么就直接把数据塞到map中,否则,创建一个MAP,然后再把数据塞到MAP中。  
  2. //使用set方法存储数据  
  3.         valueStack.set("name""valueStack");  
c.findValue

在JSP中调用的是就是findValue方法,该方法先是在ValueStack中查找,然后再ContextMap中查找。


Struts2对EL表达式的改变

例1:向Reques和ValueStack中存储相同属性名的数据

[java] view plain copy
  1. public class HelloAction extends ActionSupport implements ModelDriven<User>{  
  2.       
  3.     private User user=new User();  
  4.     private String name="ValueStack中的name";  
  5.     @Override  
  6.     public User getModel() {  
  7.         // TODO Auto-generated method stub  
  8.         return user;  
  9.     }  
  10.   
  11.     public String saveUser(){  
  12.         ServletRequest sq=ServletActionContext.getRequest();  
  13.         sq.setAttribute("name""request中的name");  
  14.         return SUCCESS;  
  15.     }  
  16.     public String getName() {  
  17.         return name;  
  18.     }  
  19. }  
使用EL表达式查看name的值

struts2的contextmap和valueStack

从结果可以看到,取到了值


例2:使用application存数据

[java] view plain copy
  1. public class HelloAction extends ActionSupport{  
  2.       
  3.     private String name="ValueStack中的name";  
  4.     public String saveUser(){  
  5.         ServletContext application=ServletActionContext.getServletContext();  
  6.         application.setAttribute("name""application中的name");  
  7.         return SUCCESS;  
  8.     }  
  9.   
  10.     public String getName() {  
  11.         return name;  
  12.     }  
  13. }  
EL表达式结果值:

struts2的contextmap和valueStack

EL表达式是取的域中的数据,怎么没有取到了.原因是Struts2有对EL表达式进行了改写

struts2的contextmap和valueStack

Struts2中EL查找顺序改变总结:

   原始的EL表达式查找顺序: page Scope————>request Scope————>sessionScope————>application Scope

   现在的OGNL(改写后的EL表达式)表达式:page Scope————>request Scope————>valueStack(根中)————>contextMap————>sessionScope————>application Scope


Struts2一些通用标签的使用

a.iterator标签

一般就是迭代list中的数据显示在页面

[html] view plain copy
  1. <!--   
  2. value:ONGL表达式  
  3. var:是一个字符串,如果指定了var属性,则会把框架当前的元素,以var为key,存储在contextMap中  
  4.               如果没有指定,则会把当前值存储在ValueStack中.  
  5.  -->  
  6. <table>  
  7. <thead>  
  8. <tr><td>序号</td><td>姓名</td></tr>  
  9. </thead>  
  10. <tbody>  
  11. </tbody>  
  12. <s:iterator value="listUser" var="s" status="vs">  
  13. <tr> <td><s:property value="#vs.count"/>  
  14. <!--不管是使用ONGL表达式,还是EL表达式都可以取到值,只是注意,有var的时候是存储在ContextMap中 -->   
  15. </td><td><s:property value="#s.name"/></br>${s.name}</td></tr>  
  16. </s:iterator>  
  17. </table>  


Struts2中#,$,%符号的使用

a.#     主要有两种用法,第一种是,取ContextMap中的数据,第二个是使用ONGL表达式创建MAP。

b、在xml配置文件中,编写OGNL表达式时使用,例如文件下载时,文件名编码。

struts.xml——>${@Java.NET.URLEncoder.encode(filename)}

c.%

在struts2中,有些标签的value属性取值就是一个OGNL表达式,例如<s:property value="OGNL Expression" />  还有一部分标签,value属性的取值就是普通字 符串,例如<s:textfield value="username"/>,如果想把一个普通的字符串强制看成时OGNL,就需要使用%{}把字符串套起来。

例如<s:textfield value="%{username}"/>。当然在<s:property value="%{OGNL Expression}"/>也可以使用,但不会这么用。


常用的标签  url a

[html] view plain copy
  1. <!--s:url   标签是创建一个地址  
  2. alue:表示一个字符串,不是ONGL表达式,就是输出一个字符串  
  3.  -->  
  4. lt;s:url value="name"></s:url>  
结果:

struts2的contextmap和valueStack

[html] view plain copy
  1. <!--s:url   标签是创建一个地址  
  2. value:表示一个字符串,不是ONGL表达式,就是输出一个字符串  
  3. action:输出的是action的地址,相当于${pageContext.requeat.contextPath}/action1.action  
  4.   -->  
  5. <s:url action="action1"></s:url>  
struts2的contextmap和valueStack

[html] view plain copy
  1. <%-- s:url   标签是创建一个地址  
  2. value:表示一个字符串,不是ONGL表达式,就是输出一个字符串  
  3. action:输出的是action的地址,相当于${pageContext.requeat.contextPath}/action1.action  
  4. var属性:会把action属性的值存储到ContextMap中  
  5. 在s:url中使用s:param标签,则是给url表达式添加参数  
  6.  --%>  
  7. <s:url action="action1" var="url">  
  8. <s:param name="username" value="'test'"></s:param>  
  9. </s:url>  
  10. <s:debug/>  

可以看到在request中有url为key存储的数据

struts2的contextmap和valueStack

[html] view plain copy
  1. <!--s:a标签和s:url一样  -->  
  2. <s:a action="action1" var="url">  
  3. <s:param name="username" value="'test'"></s:param>  
  4. </s:a>  

这样,我们可以把该url的值给a标签

[html] view plain copy
  1. <a href="<s:property value='#url' />">请点击</a>  

相关文章: