简单介绍Struts2


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类的配置不变。

查看运行结果:

 接下来对以上的运行结果进行分析:

 

。。。。。。。。

持续更新中。。。。

知道的不多, 如有什么错误的地方敬请指正。。

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM