簡單介紹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