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類的配置不變。
查看運行結果:
接下來對以上的運行結果進行分析:
。。。。。。。。
持續更新中。。。。
知道的不多, 如有什么錯誤的地方敬請指正。。