Struts2的传值方式及原理
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Struts2的传值方式及原理相关的知识,希望对你有一定的参考价值。
1.普通的传值方式
UserActionForCommonParam类
Action类接收三个参数,分别是id,username,content.
- package com.struts.action;
- public class UserActionForCommonParam {
- private int id;
- private String username;
- private String content;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- // 从前台页面接收到参数后会在这个方法里打印
- public String addUser() {
- System.out.println("ID: " + this.getId());
- System.out.println("Username: " + this.getUsername());
- System.out.println("Content: " + this.getContent());
- return "success";
- }
- }
对应的struts.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
- "http://struts.apache.org/dtds/struts-2.3.dtd">
- <struts>
- <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
- <constant name="struts.devMode" value="true"/>
- <package name="default" namespace="/" extends="struts-default">
- <action name="UserActionForCommonParam" class="com.struts.action.UserActionForCommonParam" method="addUser">
- <result name="success">/UserPage.jsp</result>
- </action>
- </package>
- </struts>
前台页面UserPage.jsp
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <title>UserPage</title>
- </head>
- <body>
- <%--下面的Table用于提交参数(id,username,content)--%>
- <form action="UserActionForCommonParam" method="POST">
- <table border="1">
- <tr>
- <td>ID:</td>
- <td><input type="text" name="id"/></td>
- </tr>
- <tr>
- <td>Username:</td>
- <td><input type="text" name="username"/></td>
- </tr>
- <tr>
- <td>Content:</td>
- <td><input type="text" name="content"/></td>
- </tr>
- <tr>
- <td colspan="2" align="center">
- <input type="submit" value="提交"/>
- </td>
- </tr>
- </table>
- </form>
- <br/>
- <%--下面的Table用于显示传递回来id,username,content--%>
- <table border="1">
- <tr>
- <td>ID: </td>
- <td><input type="text" value="${id}"/></td>
- </tr>
- <tr>
- <td>Username: </td>
- <td><input type="text" value="${username}"/></td>
- </tr>
- <tr>
- <td>Content: </td>
- <td><input type="text" value="${content}"/></td>
- </tr>
- </table>
- <%--用于查看ValueStack中的传递的值--%>
- <s:debug/>
- </body>
- </html>
在实践后会发现,如果遇到参数非常多的情况,那么就需要在Action类中写非常多的属性以及对应的get/set方法.所以这种方式不太可取.解决问题的方法必然是封装一个JavaBean.这就用到了Strut2的第二种传值方式--DomainModel
2.DomainModel传值
首先要创建一个存储的JavaBean
User类
把id,username,content封装的到一个User类当中.
- package com.struts.model;
- public class User {
- private int id;
- private String username;
- private String content;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- }
UserActionForDomainModel类
- package com.struts.action;
- import com.opensymphony.xwork2.ActionSupport;
- import com.struts.model.User;
- public class UserActionForDomainModel extends ActionSupport{
- private User user;
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
- public String addUser() {
- System.out.println("ID: " + user.getId());
- System.out.println("Username: " + user.getUsername());
- System.out.println("Content: " + user.getContent());
- return "success";
- }
- }
对应的struts.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <!DOCTYPE struts PUBLIC
- "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
- "http://struts.apache.org/dtds/struts-2.3.dtd">
- <struts>
- <constant name="struts.enable.DynamicMethodInvocation" value="true"/>
- <constant name="struts.devMode" value="true"/>
- <package name="default" namespace="/" extends="struts-default">
- <action name="userForDomainModel" class="com.struts.action.UserActionForDomainModel" method="addUser">
- <result name="success">/UserPage.jsp</result>
- </action>
- </package>
- </struts>
前台页面UserPage.jsp
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <title>UserPage</title>
- </head>
- <body>
- <%--要特别注意的是DomainModel的传值方式必须要使用对象.参数方式进行赋值以及取值--%>
- <form action="userForDomainModel" method="POST">
- <table border="1">
- <tr>
- <td>ID:</td>
- <td><input type="text" name="user.id"/></td>
- </tr>
- <tr>
- <td>Username:</td>
- <td><input type="text" name="user.username"/></td>
- </tr>
- <tr>
- <td>Content:</td>
- <td><input type="text" name="user.content"/></td>
- </tr>
- <tr>
- <td colspan="2" align="center">
- <input type="submit" value="提交"/>
- </td>
- </tr>
- </table>
- </form>
- <br/>
- <%--下面的Table用于显示传递回来id,username,content--%>
- <table border="1">
- <tr>
- <td>ID: </td>
- <td><input type="text" value="${user.id}"/></td>
- </tr>
- <tr>
- <td>Username: </td>
- <td><input type="text" value="${user.username}"/></td>
- </tr>
- <tr>
- <td>Content: </td>
- <td><input type="text" value="${user.content}"/></td>
- </tr>
- </table>
- <%--用于查看ValueStack中的传递的值--%>
- <s:debug/>
- </body>
- </html>
实际上User类不需要显式的实例化,struts会自动帮你实例化,但前提条件是,传值时需要使用对象.参数名的方式进行传递.
除了这种传值方式外,struts2还提供另外一种传值方式.
3.ModelDriven传值
依然要创建User的JavaBean
User类
- package com.struts.model;
- public class User {
- private int id;
- private String username;
- private String content;
- public int getId() {
- return id;
- }
- public void setId(int id) {
- this.id = id;
- }
- public String getUsername() {
- return username;
- }
- public void setUsername(String username) {
- this.username = username;
- }
- public String getContent() {
- return content;
- }
- public void setContent(String content) {
- this.content = content;
- }
- }
UserActionForModelDriven类
- package com.struts.action;
- import com.opensymphony.xwork2.ModelDriven;
- import com.struts.model.User;
- public class UserActionForModelDriven implements ModelDriven<User>{
- private User user;
- public String addUser() {
- System.out.println("ID: " + user.getId());
- System.out.println("Username: " + user.getUsername());
- System.out.println("Content: " + user.getContent());
- return "success";
- }
- @Override
- public User getModel() {
- if (user == null) {
- user = new User();
- }
- return user;
- }
- }
这种方式可以不用在Action类中编写对应的get/set方法,但是需要实例化User类.
前台UserPage.jsp
- <%@ page contentType="text/html;charset=UTF-8" language="java" %>
- <%@ taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <title>UserPage</title>
- </head>
- <body>
- <form action="userForModelDriven" method="POST">
- <table border="1">
- <tr>
- <td>ID:</td>
- <td><input type="text" name="id"/></td>
- </tr>
- <tr>
- <td>Username:</td>
- <td><input type="text" name="username"/></td>
- </tr>
- <tr>
- <td>Content:</td>
- <td><input type="text" name="content"/></td>
- </tr>
- <tr>
- <td colspan="2" align="center">
- <input type="submit" value="提交"/>
- </td>
- </tr>
- </table>
- </form>
- <br/>
- <%--下面的Table用于显示传递回来id,username,content--%>
- <table border="1">
- <tr><span id="transmark"></span>
- <td>ID: </td>
- <td><input type="text" value="${id}"/></td>
- </tr>
- <tr>
- <td>Username: </td>
- <td><input type="text" value="${username}"/></td>
- </tr>
- <tr>
- <td>Content: </td>
- <td><input type="text" value="${content}"/></td>
- </tr>
- </table>
- <%--用于查看ValueStack中的传递的值--%>
- <s:debug/>
- </body>
- </html>
页面还是和普通传值一样.
可以去ValueStack当中观察参数的存储,更透彻的理解Struts2的参数传递. : <s:debug/>
1.什么是ValueStack
对于每一个action的调用,Struts在执行相应的动作方法之前会先创建一个名为ValueStack的对象。Value Stack用来保存该动作对象或者对象。由于最终在执行Action类相应的action方法之前,拦截器需要先访问ValueStack。视图也需要访问ValueStack。Struts框架将其保存在一个名为struts.valueStack的请求属性中。
2.获取valueStack的三种方法:
ValueStack v1 = ActionContext.getContext().getValueStack();
ValueStack v2 = ServletActionContext.getValueStack(ServletActionContext.getRequest());
ValueStack v3 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
打印其HashCode码一模一样。
说明:
1、 值是一样的,说明只有一个对象
2、 因为有一种是从request域中获取的,所以是一次请求
3.ValueStack的内容
valueStack分为对象栈(Object Stack)和Map栈(Context Map).
Struts将把动作和相关对象压入Object Stack,而把各种各样的映射关系压入Context Map。
通常说的ValueStack就是指Object Stack,它是一个真正数据结构意义的栈。Object Stack也常常被称为root(其实是一个ArrayList)。Context Map我们一般称其为context(是一个HashMap)它是整个OGNL其中包括了root
4.OGNL中的两种对象
OGNL中包含两种对象,即_root和_value.
_value即:request, session, application, parameters, attr等命名对象,但这些命名对象都不是根。
_root即:当前请求的Action实例等
“根”对象和普通命令对象的区别在于:
“根”对象(root) 对象栈: 实际上是 CompoundRoot 类型, 是一个使用 ArrayList 定义的栈. 里边保存各种和当前 Action 实例相关的对象(如果这个Action实例包括域对象的话域对象会进root).是一个数据结构意义的栈.
1)访问Context Map里的对象需要在对象名之前添加 #
2)访问Object Stack对象的属性时,可以省略#而直接通过属性名来搜索
说明:
从上图中也可以看出valueStack总共分为两个部分:
对象栈:root (CompoundRoot类)
Map栈:_values和_root (OgnlContext 类)
5.Struts会把当前访问的Action实例压入值栈栈定
压入时间点为:
由于Struts2最后终将调用Action类中的action方法。但在调用此方法之前:
*先创建一个StrutsActionProxy (ActionProxy默认实现的子类)
*在创建StrutsActionProxy之后,对其进行初始化,把Action对象压入值栈
在调用该方法前该Action被压入栈顶,如果在初始化的过程中,在Action的构造函数中又初始化了其他类,这这个类也会被压入值栈。所以最后栈顶的元素会是这个新初始化的类。
6.ValueStack中对象的存取
Object Stack 的存放: push 或者 add:
将一个对象放入Object Stack的栈顶:
- 1
ActionContext.getContext().getValueStack().push(object);
- 2
ActionContext.getContext().getValueStack().getRoot().add(0,object);
Object Stack的提取: peek() 或 pop()
peek()取得的是栈顶元素:
- 1
Object object = ActionContext.getContext().getValueStack().peek();
Object Stack的元素的弹出:pop:
- 1
Object object = ActionContext.getContext().getValueStack().pop();
7.动态修改ValueStack中对象的属性
说明:
可以利用valueStack.setParameter方法改变对象栈中对象的属性的值。至于匹配哪个。则依次从对象栈的栈顶向下搜索,找到匹配的就修改
以上是关于Struts2的传值方式及原理的主要内容,如果未能解决你的问题,请参考以下文章