struts2的contextmap和valueStack

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

contextMap

动作类的生命周期

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


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

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;

        try {
            prepare.setEncodingAndLocale(request, response);
            prepare.createActionContext(request, response);
            prepare.assignDispatcherToThread();
            if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) {
                chain.doFilter(request, response);
            } else {
                request = prepare.wrapRequest(request);
                ActionMapping mapping = prepare.findActionMapping(request, response, true);
                if (mapping == null) {
                    boolean handled = execute.executeStaticResourceRequest(request, response);
                    if (!handled) {
                        chain.doFilter(request, response);
                    }
                } else {
                    execute.executeAction(request, response, mapping);
                }
            }
        } finally {
            prepare.cleanupRequest(request);
        }
    }

可以看到它有执行
prepare.createActionContext(request, response);
再去看这个方法:

 public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }
        
        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
            // detected existing context, so we are probably in a forward
            ctx = new ActionContext(new HashMap<String, Object>(oldContext.getContextMap()));
        } else {
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            stack.getContext().putAll(dispatcher.createContextMap(request, response, null, servletContext));
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        ActionContext.setContext(ctx);
        return ctx;
    }

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

public class ActionContext implements Serializable {

    static ThreadLocal<ActionContext> actionContext = new ThreadLocal<ActionContext>();

ContextMap存储数据

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


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

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

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

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

<html>
  <head>
    <title>用户注册,使用的是struts2的标签</title>
    <s:head></s:head>
  </head>
  <body>
  <%session.setAttribute("name", "张三"); %>
 <s:debug></s:debug>
  </body>
</html>


ActionContext和ValueStack存储数据

1.向ActonContext存数据

public String saveUser(){
		//获取ContextMap
		ActionContext actionContext = ActionContext.getContext();
		actionContext.put("name", "contextMap");
		//向HttpSession存储数据
		//得到Session
		Map<String, Object> session = actionContext.getSession();
		session.put("name", "actionContextSession");
		//原始Session存储对象
		HttpSession httpSession = ServletActionContext.getRequest().getSession();
		httpSession.setAttribute("age", "21");
		return SUCCESS;
	}


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

2.向ValueStack存储数据

a.向ValueStack存普通数据

存普通数据有三种方式:

第一种:直接使用set方法

第二种:使用push方法

第三种:生成get方法

public String saveUser(){
		//获取ContextMap
		ActionContext actionContext = ActionContext.getContext();
		//获取值栈对象
		ValueStack valueStack =actionContext.getValueStack();
		//使用set方法存储数据
        valueStack.set("name", "valueStack");
        //使用push方法存储数据
        valueStack.push("dadadada");
		return SUCCESS;
	}
生成get方法存储数据

public int getNum() {
		return num;
	}

b.向值栈存放对象

实现步骤

第一步定义对象变量

第二步生成变量的get方法

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

	private User user=new User();
       public User getUser() {
        return user;
    }
      public String saveUser(){;
        user.setName("user");
        user.setGender("gender");
        return SUCCESS;
    }

c.存储list集合

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

private List<String> listStr = new ArrayList<String>();
public String saveUser(){
		//获取ContextMap
		ActionContext actionContext = ActionContext.getContext();
		//获取值栈对象
		ValueStack valueStack =actionContext.getValueStack();
		listStr.add("A");
		listStr.add("B");
		listStr.add("C");
		return SUCCESS;
	}
	public List<String> getListStr() {
		return listStr;
	}

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

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

<s:property value="#name"/>
<s:property value="#session.name"/>


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

<!--这是ONGL表达式,不是字符串  -->
<s:property value="name"/>

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

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

<s:property value="[1].name"/>

ValueStack的其它方法

a.setValue

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

//有#,表示存储到contextMap中,否则存储到ValueStack中
		valueStack.setValue("#address", "南山");
		valueStack.setValue("address", "南山");
b.set方法

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

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


Struts2对EL表达式的改变

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

public class HelloAction extends ActionSupport implements ModelDriven<User>{
	
	private User user=new User();
	private String name="ValueStack中的name";
	@Override
	public User getModel() {
		// TODO Auto-generated method stub
		return user;
	}

	public String saveUser(){
		ServletRequest sq=ServletActionContext.getRequest();
		sq.setAttribute("name", "request中的name");
		return SUCCESS;
	}
	public String getName() {
		return name;
	}
}
使用EL表达式查看name的值

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


例2:使用application存数据

public class HelloAction extends ActionSupport{
	
	private String name="ValueStack中的name";
	public String saveUser(){
		ServletContext application=ServletActionContext.getServletContext();
		application.setAttribute("name", "application中的name");
		return SUCCESS;
	}

	public String getName() {
		return name;
	}
}
EL表达式结果值:

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

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中的数据显示在页面

<!-- 
value:ONGL表达式
var:是一个字符串,如果指定了var属性,则会把框架当前的元素,以var为key,存储在contextMap中
              如果没有指定,则会把当前值存储在ValueStack中.
 -->
<table>
<thead>
<tr><td>序号</td><td>姓名</td></tr>
</thead>
<tbody>
</tbody>
<s:iterator value="listUser" var="s" status="vs">
<tr> <td><s:property value="#vs.count"/>
<!--不管是使用ONGL表达式,还是EL表达式都可以取到值,只是注意,有var的时候是存储在ContextMap中 --> 
</td><td><s:property value="#s.name"/></br>${s.name}</td></tr>
</s:iterator>
</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

 <!--s:url   标签是创建一个地址
value:表示一个字符串,不是ONGL表达式,就是输出一个字符串
  -->
<s:url value="name"></s:url>
结果:

<!--s:url   标签是创建一个地址
value:表示一个字符串,不是ONGL表达式,就是输出一个字符串
action:输出的是action的地址,相当于${pageContext.requeat.contextPath}/action1.action
  -->
<s:url action="action1"></s:url>

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

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


<!--s:a标签和s:url一样  -->
<s:a action="action1" var="url">
<s:param name="username" value="'test'"></s:param>
</s:a>

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

<a href="<s:property value='#url' />">请点击</a>



  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值