Struts2概述
Struts2虽然是Struts1的基础上发展起来的,但是实质上是以WebWork框架为核心,为传统的Struts1注入了WebWork的设计理念,统一了Struts1和WebWork两个框架,可以说是一个不同于Struts1的一个全新的框架。
Struts2和WebWork一样,使用拦截器作为处理,以用户的业务逻辑控制器为目标,创建一个控制器代理。
Struts2的入门
Struts2框架的大致处理流程如下:
1.浏览器发送请求
2.浏览器请求被Struts2提供的过滤器StrutsPrepareAndExecuteFilter拦截
3.核心控制器FilterDispatcher根据请求决定调用合适的Action
4.Struts2的拦截器链自动对请求应用通用功能,也包含用户自定义的一些拦截器
5.回调Action的execute方法或自定义的action方法,首先这些方法会获得用户请求的参数,然后执行某种数据库的操作
6.返回result视图,处理的结果会被输出到浏览器中
对于框架来说,一些常用的框架有Struts2 spring hibernate springmvc mybatis sprintboot等。
如何在eclipse等IDE中使用Struts2框架呢?主要包含四个步骤:首先就是导入Struts的jar包。Struts2的核心的jar包主要有以下几个(可以通过Struts压缩文件中官方提供的示例中获得,如果直接导入Struts2压缩包的lib文件夹中的所有jar包就太多了):
第二步导入jar包后就是要在web.xml中配置Struts2为我们提供的过滤器了,也就是我们前面提到过的StrutsPrepareAndExecuteFilter这个过滤器。配置过程如下:
配置过滤器后,就可以保证我们的所有浏览器发出的request请求就会被我们的Struts2过滤器所处理了。
第三步,就是要使用Struts.xml 配置文件了。首先我们先简单介绍一下struts.xml文件。Struts2的配置文件是有两份的:
*配置action的struts.xml文件*配置struts2全局属性的struts.properties文件(我们的struts.xml文件中是继承struts.properties中的内容的,其中配置了struts2的拦截器栈)
其中struts.xml文件内定义了Struts2的一系列的action,当我们在定义action时,指定action的实现类并定义了该action处理结果与视图资源之间的映射关系。下面是=简单看一下struts.xml配置文件:
Struts2的action是必须要配置在package中的,在struts.xml中package标签是可以有多个的,它们是以不同的包的名称来进行区分的。
先看package标签:
name:包的名称 namespace:名称空间,一般配置为 ‘/’ extends:继承,一般为固定值struts-default 表示要引入的struts2的相关信息比如拦截器栈等Struts配置信息
再看action标签:
name : 访问该action的请求路径的一部分和package标签中的namespace属性值一起构成了浏览器中访问该action的请求路径
class:表示该路径请求的真正的类
method:表示要执行的action中的具体的方法,如果不配置默认是执行execute方法的
最后看result标签:
result标签是表示的action处理后的返回视图,比如将处理结果返回到某个页面或者action,name是要返回的具体的页面的一个映射而type指定了返回的方式是转发、重定向或是其他。可以说result指定了execute方法(或method指定的方法)返回值和视图资源之间的映射关系。
除此之外,就是配置struts2全局属性的struts.properties,它是以键值对的形式表示的。
第四步,就是正式编写相关的action类了。对于struts2开发者来说,Action才是应用的核心,因为开发者需要提供大量的Action类,并在struts.xml中配置Action。Action类包含了对用户请求的处理逻辑,也被称为业务控制器。
接下来简单说一下,在struts2中创建action类的三种方式:创建pojo类、实现action接口、继承ActionSupport类。下面具体来说一下:
方式一:直接创建一个普通的java类
//创建action的第一种方式 public class ActionDemo1 { public String execute(){ System.out.println("actiondemo1"); return "hello"; } }
方式二:实现Action接口
import com.opensymphony.xwork2.Action; //创建action的第二种方法,实现action接口 public class ActionDemo2 implements Action{ @Override public String execute() throws Exception { // 创建action的第二种方法 System.out.println("actiondemo2"); return "hello"; } }
方式三:继承ActionSupport类,一般建议采用此种方式创建Action
import com.opensymphony.xwork2.ActionSupport; //创建action的第三种方式继承actionsupport类,最常用的一种方式 public class ActionDemo3 extends ActionSupport{ @Override public String execute(){ System.out.println("actiondemo3"); return "hello"; } }
以上就是创建Action的三种方式。综上四个步骤便是在eclipse使用struts2进行开发的一个简单的入门流程。接下来简单了解一下ActionSupport类(实际上它实现了Action函数式接口):ActionSupport为许多Action类提供了一个默认的实现类,用户在创建自己的Action时可以直接继承该类,而无需自己去实现一个Action接口,ActionSupport类为我们提供了许多的方法,比较常用的有两个,一个是用于向action对象中存入表单验证返回的错误信息(addActionError()),一个是用于进行验证操作(validate()子类需要覆写这个方法来进行验证操作)。下面具体针对validate举-个例子:
描述:当用户点击提交按钮的时候,如果用户名为null就显示错误信息,这里将错误信息以属性形式存入action对象中。
action:
import com.opensymphony.xwork2.ActionSupport; public class ActionValidate extends ActionSupport{ private String username ; public String getUsername(){ return username ; } private String error ; //提供get方法 public String getError(){ return error ; } @Override //重写validate进行非空判断 public void validate(){//特别注意当action的execute执行时默认先执行validate方法,而无需显式调用 if(username == null){//用户提交后验证username文本框是否为空 //如果为空,向变量error添加错误信息 error = "用户名不能为空"; } } @Override public String execute(){ if(error != null){ return "validatejsp"; }else{ return NONE; } } }
jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib uri="/struts-tags" prefix="s"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <form action="validate" method="post"> username <input type="text" name="username"/><s:property value="error"></s:property> <br> <input type="submit" value="提交"> </form> </body> </html>
Action访问servlet的API
struts2可以说是对servlet的进行的封装,并解决了servlet产生的一些问题。总体上来说,Struts2的Action并没有和任何的servletAPI进行耦合,这是struts2的一个改良之处,除此之外struts2也提供了一种更加轻松的方式来访问servletAPI,因为web应用中通常需要访问的servletAPI就是HttpServletRequest、HttpSession和ServletContext分别代表着JSP内置对象中的request、session和application。struts2中提供了一个ServletActionContext类,该类是ActionContext类的一个子类(超类、子类分别在不同的包中),提供了直接取得request、response等的对象的方法,具体演示如下:
public class ActionTemp extends ActionSupport{ public String execute(){ HttpServletRequest request = ServletActionContext.getRequest(); HttpServletResponse response = ServletActionContext.getResponse(); HttpSession session = request.getSession(); ServletContext servletContext = ServletActionContext.getServletContext(); return NONE; } }
Action对数据的封装
主要解决的问题是:在action中如何获得请求参数。主要有两种方式属性驱动和模型驱动。
属性驱动:
第一种方式:直接在action类中提供与请求参数匹配的属性,并提供set和get方法。
1 public class ActionData extends ActionSupport { 2 //第一种:直接在action类中提供与请求参数匹配的属性,并提供set和get方法 3 private String username ; 4 private String password ; 5 public String getUsername() { 6 return username; 7 } 8 public void setUsername(String username) { 9 this.username = username; 10 } 11 public String getPassword() { 12 return password; 13 } 14 public void setPassword(String password) { 15 this.password = password; 16 } 17 //创建login方法 18 public void login(){ 19 //获得并打印表单数据 20 System.out.println("username :" + username ); 21 System.out.println("password :" + password ); 22 } 23 24 25 }
第二种方式:创建一个javabean(如User),并在action中进行声明和提供set、get方法,请求页面上使用ognl表达式
1 public class ActionData extends ActionSupport { 2 //第二种:直接在action类中声明javabean,并提供set和get方法 3 private User user ; 4 5 public User getUser() { 6 return user; 7 } 8 9 public void setUser(User user) { 10 this.user = user; 11 } 12 13 14 //创建login方法 15 public void login(){ 16 //获得并打印表单数据 17 System.out.println(user); 18 } 19 20 21 }
注:此种方式要求在页面上必须使用ognl表达式。
模型驱动:
要求:action必须要实现ModelDriven接口;实例化模型对象(即javabean);重写getModel方法将实例化的模型返回(此时页面不使用ognl表达式)
1 public class ActionData extends ActionSupport implements ModelDriven<User>{ 2 //第三种:使用模型驱动,直接将数据封装 3 private User user = new User(); 4 5 @Override 6 public User getModel() { 7 // TODO Auto-generated method stub 8 return user; 9 } 10 11 //创建login方法 12 public void login(){ 13 //获得并打印表单数据 14 System.out.println(user); 15 } 16 17 18 }
内省
在程序运行期间获得javabean的set和get方法,使用到如下这个类:
java.beans.PropertyDescriptor //描述javabean可以通过一组存储器方法导出一个属性
使用如下一个javabean(先前的User类):
1 public class User { 2 private String username ; 3 private String password ; 4 public User() { 5 super(); 6 } 7 public User(String username, String password) { 8 super(); 9 this.username = username; 10 this.password = password; 11 } 12 public String getUsername() { 13 return username; 14 } 15 public void setUsername(String username) { 16 this.username = username; 17 } 18 public String getPassword() { 19 return password; 20 } 21 public void setPassword(String password) { 22 this.password = password; 23 } 24 @Override 25 public String toString() { 26 return "User [username=" + username + ", password=" + password + "]"; 27 } 28 29 }
下面创建一个方法来动态的为User对象的属性进行赋值和输出
1 //内省 2 public class PropertyDescriptorTest { 3 @Test 4 public void test() throws Exception{ 5 //构造一个PropertyDescriptor对象 6 PropertyDescriptor descriptor = new PropertyDescriptor("username", User.class); 7 //实例化一个User对象 8 User user = new User(); 9 //获得User的setUsername方法 10 Method methodRead = descriptor.getWriteMethod(); 11 //执行set方法进行属性设置 12 methodRead.invoke(user, "韩菱纱"); 13 //获得User的get方法并执行 14 String username = (String) descriptor.getReadMethod().invoke(user); 15 //进行信息的打印 16 System.out.println("username:" + username); 17 } 18 }
ognl表达式(表达式、OgnlContext上下文、root根)
即对象图导航语言的缩写,是一种强大的表达式语言,通过表达式的语法可以存取对象的任意属性,调用对
象的任意方法,遍历整个对象的结构图等功能。在struts2框架集成了ognl。下面简单了解一下ognl的作用。
第一:支持对象操作,调用对象的方法
1 @Test 2 public void test1() throws Exception{ 3 //获得上下文对象 4 OgnlContext context = new OgnlContext(); 5 //调用对象的方法(String的length方法) 6 Object value = Ognl.getValue("'hello'.length()",context,context.getRoot()); 7 //结果输出 8 System.out.println(value); 9 }
第二:支持静态成员访问
1 @Test 2 public void test2_1() throws Exception { 3 //获得ognl上下文 4 OgnlContext context = new OgnlContext(); 5 //操作静态成员访问 6 Object pi = Ognl.getValue("@java.lang.Math@PI", context, context.getRoot()); 7 //数据输出 8 System.out.println(pi); 9 } 10
注:输出类和成员变量的时候前面别忘了添加@符号并且静态成员变量必须是public权限的。
第三:访问ognl上下文
利用context向上下文中存储数据,并打印
1 @Test 2 public void test2() throws Exception{ 3 //获得上下文对象 4 OgnlContext context = new OgnlContext(); 5 //在上下文中存储数据(保存在了context中),访问必须要加# 6 context.put("username","tom"); 7 //根据键取得数据 8 Object value = Ognl.getValue("#username", context, context.getRoot()); 9 //进行数据的输出 10 System.out.println(value); 11 }
1 @Test 2 public void test2_3() throws Exception{ 3 //获得上下文对象 4 OgnlContext context = new OgnlContext(); 5 //在上下文中存储数据(保存在了context中),访问必须要加# 6 context.put("username","tom"); 7 //将数据存入root 8 context.setRoot(context); 9 //根据键取得数据 10 Object value = Ognl.getValue("username", context, context.getRoot()); 11 //进行数据的输出 12 System.out.println(value); 13 }
1 @Test 2 public void test3() throws Exception{ 3 //获得上下文对象 4 OgnlContext context = new OgnlContext(); 5 //创建一个map集合,并向其中添加数据 6 Map<String,String> map = new HashMap<String,String>(); 7 map.put("username", "fox"); 8 //向context中添加数据 9 context.put("username", "tom"); 10 //将map数据存入root(OgnlContext实现了map接口) 11 context.setRoot(map); 12 //从root中取得数据 13 Object value = Ognl.getValue("username",context,context.getRoot()); 14 System.out.println(value); 15 //从上下文中取得数据 16 Object value2 = Ognl.getValue("#username", context, context.getRoot()); 17 System.out.println(value2); 18 }
注:从根中获得数据,不需要添加#号,从上下文中获得数据,需要添加#
第四:操作集合(支持赋值操作和表达式串联)
1 @Test 2 public void test4() throws Exception{ 3 //获得上下文对象 4 OgnlContext context = new OgnlContext(); 5 //创建一个ArrayList集合 6 Object value = Ognl.getValue("{'hello','good','well'}", context, context.getRoot()); 7 //将集合存入root 8 context.setRoot(value); 9 //通过索引获得结果 10 Object val = Ognl.getValue("[1]", context,context.getRoot()); 11 //打印数据 12 System.out.println(val); 13 System.out.println("***********************"); 14 //创建一个集合LinkedHashMap类型 15 Object value2 = Ognl.getValue("#{'username':'tom'}", context, context.getRoot()); 16 System.out.println(value2.getClass()); 17 }
1 @Test 2 public void test6() throws Exception { 3 //创建上下文对象 4 OgnlContext context = new OgnlContext(); 5 //创建一个LinkedHashMap集合 6 Object val = Ognl.getValue("#{'username':'苏瑶'}", context, context.getRoot()); 7 //将集合存入root 8 context.setRoot(val); 9 //获得username从root中 10 Object value = Ognl.getValue("username", context, context.getRoot()); 11 //打印数据 12 System.out.println(value); 13 //使用赋值操作 14 Object value2 = Ognl.getValue("username='韩菱纱'", context, context.getRoot()); 15 //进行数据打印 16 System.out.println(value2); 17 //再次从root中获得username 18 Object value3 = Ognl.getValue("username", context, context.getRoot()); 19 //打印数据 20 System.out.println(value3); 21 }
ognl表达式在struts2中只要是用来取得值栈中的数据。
valueStack值栈
值栈的主要目的是将action中产生的数据携带到页面上即valueStack就是一个容器。在Struts2框架中将valuestack设计
成一个接口。
com.opensymphony.xwork2.util.ValueStack
我们使用的主要是它的实现类:
com.opensymphony.xwork2.ognl.OgnlValueStack
当浏览器向我们发送一个请求,服务器就会创建一个Action来处理请求,struct2中的action是一个多例,每一次请
求都会有一个新的action对应,所以它不存在线程安全问题。特别注意:一个valueStack对应一个action,valuestack
贯穿整个action的生命周期。浏览器将请求(request对象)提交到一个action,action的处理结果会保存到它所对应
的valuestack中,在前台页面,通过ognl表达式,从值栈中获得数据。
struts2框架将valuestack保存在了request中。下面来看一下struts2的源码:
从web.xml文件中查看过滤器:
查看过滤器源码,看doFilter方法
继续进入serviceAction方法:
观察该方法:
试着从request域中取出valuestack,并判断该request中是否存在值栈,如果不存在就获得一个值栈(其实值栈是通过request设置属性存入的)。继续查看该方法的下面的代码:
以上代码中将值栈存入了request域之中。
valueStack内部结构
查看下面的strust2源码:
从以上的代码中进入valuestack(接口):
进而选择进入ValueStack的实现类(OgnlValuestack):
查看OgnlValuestack类:
可见:ValueStack主要由两部分组成,CompoundRoot继承了ArrayList集合,也就说值栈中的root是一个ArrayList集合,主要存储的是action的相关数据。Map<String,Object> context就是一个map集合,也就是说值栈的context是一个map集合,主要存储了一些引用,主要是关于web开发中的相关信息(比如:parameter请求参数、request请求对象中的所有属性、session会话对象中的所有属性、application对象中的所有属性等,这些都是以map形式存储的)。注意,在Struts2框架之中,通过ognl表达式来获取valueStack中的数据,如果不使用“#”即从值栈的CompoundRoot中获取数据,反之,如果使用#,就从context中来获得数据。
获得ValueStack对象
第一种:直接通过request对象来获得
public class ValueStackTest { @Test public void test1(){ ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY); } }
第二种:使用ActionContext获得
1 @Test 2 public void test2(){ 3 ValueStack valueStack = ActionContext.getContext().getValueStack(); 4 }
在获得值栈对象的时候,使用到了ActionContext,下面简单了解一下这个类
ActionContext是action上下文,struts2框架使用actionContext来保存Action在执行过程中所需要的一些对象如是session、application等。ActionContext的获取是通过自身的静态方法getContext获得,Struts2会根据每一次的http请求来创建对应的ActionContext,它是与当前线程绑定的,每一次的请求就是一个线程,对应一个request,
每一次请求,创建一个Action,每一个action对应一个ActionContext,每一次请求也对应一个valuestack。
即:request--Action--ActionContext--ValueStack,它们都是对应着一次请求(一个线程)。
下面来看一下struts2的源代码:
首先,当浏览器发送请求后,servlet引擎为我们创建了对应的request对象(带有http请求信息),这个请求会被struts2的过滤器拦截,此时过滤器会做一些额外的操作如处理乱码问题(post)等,除此之外,还执行了如下方法
createActionContext(request,response)创建一个ActionContext对象。此时要特别注意:
从上面的代码中可以看到ActionContext是一个ThreadLocal的变量,也就是说它是和当前线程绑定的。每一个线程拥有自己的ActionContext。下面进入createActionContext方法:
从以上代码可以看出,struts2过滤器拦截请求后会创建一个ActionContext对象并与当前线程进行绑定。第一次接收请求的时候oldContext一定是空的,所以会执行else中的代码,并创建一个ActionContext对象,该ActionContext持有值栈的context引用。特别注意,在值栈的context中也持有一个root的引用。此时,也就可以
理解为在ActionContext中存有valuestack。
ThreadLocal线程绑定
Java在处理多线程的问题上,为线程安全提供了一些工具类如ThreadLocal类,代表一个线程局部变量,通过
把数据放在ThreadLocal中就可以让每一个线程创建一个该变量的副本,从而避免并发访问的线程安全问题。
ThreadLocal是线程局部变量的意思,将为每一个使用该变量的线程都提供一个变量值的副本,使得每一个线程
都可以独立的改变自己的副本,而不会和其他线程的副本冲突,从线程的角度来看,就好像每一个线程都完全拥有
该变量一样,ThreadLocal提供了三个public方法:
get():返回此线程局部变量中当前线程副本的值
remove():删除此线程局部变量中当前线程的值
set(T value):设置此线程局部变量中当前线程副本中的值
代码示例:
1 class Account{ 2 /*定义一个ThreadLocal类型的变量,该变量是一个线程局部变量 3 * 每个线程都会保留该变量的一个副本 4 * */ 5 private ThreadLocal<String> name = new ThreadLocal<>(); 6 //初始化一个name成员变量 7 public Account(String str){ 8 this.name.set(str); 9 //访问当前线程的name副本 10 System.out.println("---" + this.name.get()); 11 } 12 public String getName(){ 13 return this.name.get(); 14 } 15 public void setName(String str){ 16 this.name.set(str); 17 } 18 } 19 class MyTest extends Thread{ 20 private Account account ; 21 public MyTest(Account account,String name){ 22 super(name); 23 this.account=account; 24 } 25 public void run(){ 26 for(int i=0;i<10;i++){ 27 //当i==6时输出账户名替换成当前线程名 28 if(i==6){ 29 account.setName(getName()); 30 } 31 System.out.println(account.getName() + "账户的i值:" + i); 32 } 33 } 34 } 35 36 public class ThreadLocalTest { 37 public static void main(String[] args) { 38 //启动两个线程,两线程共享一个Account 39 Account account = new Account("初始名"); 40 /*虽然两个线程共享同一个账户,但由于账户名是Threadlocal类的,所以每一个线程 41 * 都完全拥有各自的账户名副本 42 * */ 43 new MyTest(account, "A").start(); 44 new MyTest(account, "B").start(); 45 } 46 }
向valueStack中存储数据
特别注意,使用valueStack来存储数据时,主要是向root中进行数据存储。关于向值栈中存储数据主要介绍两种
方式:手动向值栈存储数据、struts2框架自动向值栈中存储数据。下面具体来看:
手动向值栈存储数据:
1 @Test 2 public void test2(){ 3 //获得值栈对象 4 ValueStack valueStack = ActionContext.getContext().getValueStack(); 5 //手动向值栈中存入数据 6 valueStack.push("菱纱"); 7 //手动向值栈中存入数据 8 valueStack.set("username", "lingsha"); 9 }
可见使用set和push向值栈的root中存储数据,说是两个方法其实也可以说是一种方法就是push方法。因为set方法
是将数据封装到一个map集合中,再次调用push方法将map集合存入root中即set方法中底层还是使用push方法向值
栈root中存储。
Struts2框架自动向valuestack中存储数据:
每次访问,这个action对象会被存储到valuestack的root中。还有就是如果自定义的action使用模型驱动来接收数据,那么
这个模型对象也会被存储到值栈的root中。
valueStack操作--获取数据
创建Action类
1 //用于测试从值栈中获得数据 2 public class ActionValueStack extends ActionSupport{ 3 4 public String test(){ 5 //获得值栈对象 6 ValueStack valueStack = ActionContext.getContext().getValueStack(); 7 //向值栈中存入数据 8 valueStack.push("韩菱纱"); 9 //向值栈中存入数据 10 valueStack.set("username", "lingsha"); 11 //跳转页面 12 return SUCCESS; 13 } 14 }
在struts.xml中进行配置
1 <!-- 获得valuestack数据 --> 2 <action name="actiontest" class="com.it.action.ActionValueStack" method="test"> 3 <result name="success">/test.jsp</result> 4 </action>
test.jsp页面取出
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@taglib uri="/struts-tags" prefix="s" %> 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>Insert title here</title> 9 </head> 10 <body> 11 <s:debug></s:debug> 12 username=<s:property value="username"/> 13 <hr/> 14 user=<s:property value="[1].top"/> 15 </body> 16 </html>
下面直接获取action中的数据(要求必须提供get方法,才能够取出,不一定要提供对应的成员变量),我们知道action会自动被struts2存入值栈的。
修改之前的action类:
1 //用于测试从值栈中获得数据 2 public class ActionValueStack extends ActionSupport{ 3 4 //添加一个地址属性 5 private String address = "琼华派"; 6 //提供get方法 7 public String getAddress(){ 8 return address ; 9 } 10 //不添加属性直接提供一个get方法返回一个name 11 public String getName(){ 12 return "剑林"; 13 } 14 15 public String test(){ 16 //获得值栈对象 17 ValueStack valueStack = ActionContext.getContext().getValueStack(); 18 //向值栈中存入数据 19 valueStack.push("lingsha"); 20 //向值栈中存入数据 21 valueStack.set("username", "lingsha"); 22 //跳转页面 23 return SUCCESS; 24 } 25 }
修改页面,对于action中的数据,直接通过属性名进行取出即可:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@taglib uri="/struts-tags" prefix="s" %> 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>Insert title here</title> 9 </head> 10 <body> 11 <s:debug></s:debug> 12 username=<s:property value="username"/> 13 <hr/> 14 user=<s:property value="[1].top"/> 15 <hr/> 16 <s:property value="address"/> 17 <hr/> 18 <s:property value="name"/> 19 </body> 20 </html>
接下来通过代码来看一下模型驱动时从值栈中取数据的一个注意点:
修改action代码:
1 //用于测试从值栈中获得数据 2 public class ActionValueStack extends ActionSupport implements ModelDriven<User>{ 3 4 private User user = new User(); 5 6 @Override 7 public User getModel() { 8 // TODO Auto-generated method stub 9 return user; 10 } 11 12 public String test(){ 13 14 //特别注意此时重新创建一个User对象 15 user = new User(); 16 //在Action处理业务中,对user对象重新赋值 17 user.setUsername("张三"); 18 user.setPassword("456"); 19 20 return SUCCESS; 21 } 22 23 24 }
访问时的路径(拼接数据):
1 http://localhost:8080/struts2_review/actiontest.action?username=tom&password=123
jsp页面进行修改:
1 <%@ page language="java" contentType="text/html; charset=UTF-8" 2 pageEncoding="UTF-8"%> 3 <%@taglib uri="/struts-tags" prefix="s" %> 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>Insert title here</title> 9 </head> 10 <body> 11 <s:debug></s:debug> 12 <s:property value="username"/> 13 <hr/> 14 <s:property value="password"/> 15 <hr/> 16 <s:property value="model.username"/> 17 <hr/> 18 <s:property value="model.password"/> 19 </body> 20 </html>
注:Action类的配置不变。
查看运行结果:
接下来对以上的运行结果进行分析:
。。。。。。。。
持续更新中。。。。
知道的不多, 如有什么错误的地方敬请指正。。