Struts2框架封裝數據:(在action中如何獲取請求參數)
兩種方式:
1.屬性驅動
a.直接在action類中提供與請求參數名稱匹配的成員屬性,並提供get/set方法;
b.建立一個javabean模型,在javabean中提供與請求參數名稱匹配的成員屬性,並提供get/set方法;
在action類中提供類型爲該javabean成員變量n,並提供該javabean的get/set方法。。
頁面中的參數名稱爲:n.成員變量
eg:user.username,user.password,要使用這種ognl表達式。
以上兩種方式的優缺點:
第一種比較簡單,在實際操做中須要將action屬性再賦值給javabean來封裝數據來傳遞操做,會很麻煩;
第二種:不須要再次封裝值到javabean,可是它要求頁面上把必須使用ognl表達式,存在頁面不通用問題;
2.模型驅動
步驟:
1.讓Action類實現一個接口ModeDriven<JavaBean>
2.在Action類中實例化模型對象(就是要new出來javabean)
3.重寫getModel方法將實例化的模型返回。
eg:前端
1 public class LoginAction implements ModelDriven<User>{ 2 private User user = new User(); 3 @Override 4 public User getModel(){ 5 return user; 6 } 7 }
對於模型驅動它與屬性驅動對比,在實際開發中使用比較多,模型驅動缺點,它只能對一個模型數據進行封裝。java
Struts2.0Action中獲取servlet api
方法一:ServletActionContext獲取 web
static ActionContext getActionContext(HttpServletRequest request)
static ActionMapping getActionMapping()
static PageContext getPageContext()
static HttpServletRequest getRequest()
static HttpServletResponse getResponse()
static ServletContext getServletContext()
static ValueStack getValueStack(HttpServletRequest request)
static void setRequest(HttpServletRequest request)
static void setResponse(HttpServletResponse response)
static void setServletContext(ServletContext servletContext)spring
eg:api
HttpServletRequest request = ServletActionContext.getRequest(); HttpSession session = request.getSession(); ServletContext servletContext = ServletActionContext.getServletContext(); String username = request.getParameter("username"); String password = request.getParameter("password");
方法二:採用注入的方式安全
分析:在action執行以前會走一些默認的攔截器,其中有一個名爲servletConfig的攔截器,這個攔截器會判斷你當前的action是否實現了指定的接口,若是實現了他就幫你把須要的對象注入到當前的action中。服務器
實現的接口以下:session
ServletRequestAware
ServletResponseAware
ServletContextAware
。。。。。。數據結構
eg:app
1 public class LoginApi implements ServletRequestAware{ 2 private HttpServletRequest request; 3 public void login() { 4 String username = request.getParameter("username"); 5 System.out.println(username); 6 } 7 @Override 8 public void setServletRequest(HttpServletRequest request) { 9 this.request = request; 10 } 11 }
OGNL表達式
概述:
object-graph navigation language(對象圖導航語言),它是一種功能強大的表達式語言,經過它簡單一致的表達式語言,能夠存取對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。
ognl相似於el,可是比el更增強大
struts2框架內置了ognl表達式
ognl自己就是一個項目,它是能夠單獨使用的。
ognl做用:
1.支持對象的操做,調用對象的方法
2.支持靜態成員訪問
3.支持賦值操做與表達串聯
4.訪問ognl上下文,訪問ActionContext
5.操做集合對象
ognl三要素:
表達式
OgnlContext 上下文
Root 根
單獨使用Ognl示例:


1 package test; 2 3 import java.util.HashMap; 4 import java.util.Map; 5 6 import org.junit.Test; 7 8 import ognl.Ognl; 9 import ognl.OgnlContext; 10 import ognl.OgnlException; 11 12 public class OgnlTest { 13 @Test 14 public void test() throws OgnlException { 15 //獲取上下文對象OgnlContext 16 OgnlContext context = new OgnlContext();//OgnlContext implements java.util.Map 17 Object root = context.getRoot();//得到根root,初始值爲null,須要設置root根值 18 19 //數據操做(取值) 20 //示例1:支持對象的訪問 21 Object value = Ognl.getValue("'hello'.length()",context,root);//傳入表達式、OgnlContext上下文對象context、根 22 System.out.println(value); 23 24 //示例2:支持靜態成員的訪問(語法格式 @類全名@成員變量/成員方法) 25 Object MathRandom = Ognl.getValue("@java.lang.Math@random()",context,root); 26 Object mathPI = Ognl.getValue("@java.lang.Math@PI",context,root); 27 System.out.println(MathRandom); 28 System.out.println(mathPI); 29 30 //示例3:訪問Ognl上下文 (語法格式 在鍵名稱前加#號) 31 context.put("username", "張三丰");//向上下文中存入數據 32 Object contextValue = Ognl.getValue("#username",context,root); 33 System.out.println(contextValue); 34 35 //示例4:訪問root根值(語法格式 當root根值中存入的是Map集合時,直接寫須要取的鍵名;當root根值中存入的是List集合時,直接寫索引便可。eg:"[index]") 36 Map<String, String> map = new HashMap<String,String>(); 37 map.put("username", "張無忌"); 38 context.setRoot(map); 39 Object rootValue = Ognl.getValue("username", context, context.getRoot()); 40 System.out.println(rootValue+"..."); 41 42 //示例5:操做集合 43 Object arrayList = Ognl.getValue("{1,2,3,4,5}", context, context.getRoot());//至關於建立了一個list集合 44 System.out.println(arrayList.getClass()); 45 Object linkedHashMap = Ognl.getValue("#{'username':'lisi','password':'123','age':18}",context,rootValue);//至關於建立了一個map集合 46 System.out.println(linkedHashMap.getClass()); 47 48 //示例6:支持表達式賦值(對錶達式的值進行從新賦值) 49 Object value2 = Ognl.getValue("#username",context,rootValue); 50 Object exitsValue2 = Ognl.getValue("#username='老王'",context,rootValue); 51 System.out.print(value2+"->"); 52 System.out.println(exitsValue2); 53 54 //示例7:支持表達式串聯(串聯就是當有多個表達式存在時,執行最後一個表達式的值) 55 Object value3 = Ognl.getValue("#username",context,rootValue); 56 Object exitsValue3 = Ognl.getValue("#username,'hello'",context,rootValue); 57 System.out.print(value3+"->"); 58 System.out.println(exitsValue3); 59 } 60 }
struts2.0框架中使用Ognl表達式
在struts2.0框架中咱們使用ognl表達式從valueStack中獲取數據
在struts2.0框架中咱們可使用ognl+valueStack達到在頁面(jsp)上來獲取相關的數據;
要想在jsp頁面上使用ognl表達式,就須要結合struts2框架的標籤<s:property value = "ognl表達式"/>來使用;
使用步驟:
在jsp中引入標籤庫:<%@ taglib uri="/struts-tags" prefix="s"%>
編寫ognl表達式:eg:<s:property value = "'hello'.length()"/>
valueStack 值棧
valueStack主要目的就是爲action中產生的數據攜帶到頁面上,也就是說valueStack就是一個容器。
在struts2框架中valueStack被設計成一個接口com.opensymphony.xwork2.util.ValueStack,咱們主要使用的是它的實現類com.opensymphony.xwork2.ognl.OgnlValueStack.
當客戶端向咱們發送一個請求,服務器就會創始一個Action來處理請求,struts2中的action是一個多例的,每一次請求都會有一個新的action對應,因此它不存在線程安全的問題,一個valueStack對應一個action,valueStack貫穿整個action的生命週期。struts2框架將valueStack保存在request中。
valuleStack 內部結構
valueStack主要有兩部分組成:
valueStack實現類OgnlValueStack中主要有成員變量CompoundRoot root;Map<String,Object> context;
CompoundRoot root : 它就是一個ArrayList,它主要存貯action的相關數據,用戶手動存入的數據;
Map<String,Object> context : 就是一個Map,context中主要存儲了關於web開發中常見對象;
eg:
parameters:請求參數
request:請求對象中全部屬性
session:會話對象中全部屬性
application:application對象中的全部發展
。。。。。。
context中其實存儲都是都是這些對象的Map信息。
在struts2框架中咱們經過ognl表達式來獲取valueStack中的數據:
沒有使用#就會從CompoundRoot root中獲取數據;
若是使用#就會從Map<String,Object> context 中來獲取數據;
ValueStack獲取:
方式一:直接經過reqeust對象來獲取
ValueStack valueStack = (ValueStack)ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
方式二:使用ActionContext來獲取
ValueStack valueStack = ActionContext.getContext().getValueStack();
ActionContext的介紹:
ActionContext它是action上下文,struts2框架使用ActionContext來保存Action在執行過程當中所須要的一些對象,eg:session,application。。。
ActionContext是跟本地線程所綁定的。若是要獲取直接能夠經過以下代碼獲取到。
ActionContext context = ActionContext.getContext();
struts2會根據每一次的http請求來建立對應的ActionContext,它是與當前縣城綁定的。每一次請求,就是一個線程,對應着一個request,Action,ActionContext,ValueStack。
ServletActionContext extends ActionContext
ValueStack操做-存儲數據
注意:咱們使用valueStack來存儲數據時主要是向root中存儲;
手動存儲:(push&set都是向root中來存儲)
push(Object); //向root中存儲一個Object類型的數據;
set(key,Object);//向root中存入一個Map集合,底層會先從root中找第一個元素即下標爲0的元素,看它是不是Map,當它是Map,而且該Map中能夠檢索到key=OgnlValueStack.MAP_IDENTIFIER_KEY的值則返回該map而後向該map中存入數據;不然會建立一個HashMap,而後存入 key=OgnlValueStack.MAP_IDENTIFIER_KEY,value=""的一個值,而後向該map中存入數據。
push()/set()底層都是調用的ArrayList中add(index,Object)方法,且每次add都是向索引爲0的位置插入數據;因此該root中的數據結構爲棧結構,先進後出。
eg:ValueStack valueStack = ActionContext.getContext().getValueStack();
valueStack.push();
valueStack.set();
struts2.0框架自動向valueStack->root中存儲數據:
每次請求,訪問action,action這個對象會被自動push()存儲到valueStack中;
當action實現了ModelDriven接口時,會將模型對象自動push()存儲到到valueStack中;
ValueStack操做-獲取數據
<s:debug/> 在jsp頁面中可使用此標籤進行調試,先要將strusts的jar包導入方可以使用。
在客戶端頁面中該標籤被解析爲一個超連接,點擊開能夠看到valueStack值棧,分爲兩部分,上面爲root,下面爲context;(root中struts會自動存入action對象)
當取root中Map集合裏面的值時,jsp頁面ognl表達式只須要寫map中對應key的值方可取出對應的value值;
當取root中其餘元素的值時,須要使用下標來取,當你取某一個下標的值時,會將root中以這個下標爲起始後的全部值都取到,因此須要加上top,取第一個值便可。eg:<s:property value="[1].top"/>
當取root中action對象中的值時,其實底層是調用的action的getter方法獲得getter方法的返回值;直接寫action中成員變量(實際上是get方法名稱去掉get首字母小寫)的名稱就能夠得到到該值。
根據root取action對象的語法規則,是否root中存入action對象的值是將全部的值封裝到一個map而後存入到root中?
當action繼承了ModelDriver,須要取得對象模型驅動的值時,直接用該對象屬性名稱取值便可;
當該action的邏輯方法中對模型對象重複賦值後,要取得賦值後的新值時,須要使用model.對象屬性名取值。(底層是使用getModel()方法)
(從action中取得模型對象的值,思考,是否取對象的屬性值亦是直接用該對象屬性名稱取值便可)
EL表達式能夠從valueStack中獲取數據
由於struts2對request作出了加強操做,重寫了getAttribute()方法,當el表達式request域對象中取不到值就會取valueStack中取值。
Ognl表達式中的特殊符號
ognl是一般要結合struts2的標識一塊兒使用,主要是#、%、$這三個符號的使用:
#號:它是從context中獲取數據;
eg:向域對象request中存入名爲username的zhangsan值,由於web開發中經常使用的對象都是存儲在valueStack->context中,那麼在ognl中獲取:<s:property value="#request.username"/>
還能夠經過parameters對象得到到前端傳來的參數:<s:property value="#parameters.username"/>
%號:用因而否強制解析ognl表達式
eg:
<s:property value="%{#request.username}"/> 會解析ognl
<s:property value="%{'#request.username'}"/> 不會解析ognl
$號: 主要是從配置文件中來獲取valueStack中數據
當跳轉方式爲重定向的時候,咱們還想要將上一個頁面的valueStack中的值帶入到重定向以後的頁面,那麼能夠將須要的值拼接到跳轉路徑的後面:
eg:
<action>
<!-- 能夠將上個頁面valueStack的值經過${表達式}方式獲取拼接到跳轉頁面後面 -->
<result name = "" type = "redirect">/ognl.jsp?username=${username}</result>
</action>
關於登錄失敗的處理:
在用戶登錄時,用戶名或密碼錯誤,將自定義的錯誤信息存儲到valueStack中,在登錄頁面經過ognl表達式獲取錯誤信息展現:
其實在實際開發時,咱們通常會讓action取繼承ActionSupport類,那麼就是使用父類提供的對錯誤操做的處理:
this.addActionError("用戶名或密碼錯誤"); //用於對用戶名密碼的邏輯判斷
在頁面上能夠直接使用struts2提供的標籤來顯示錯誤信息:
<s:actionerror/>
相似的還有:
this.addFieldError(fieldName,errorMessage); ---> <s:fielderror/> //用於對用戶名和密碼的校驗(長度/數字開頭。。。)
this.addActionMessage(aMessage); ---> <s:actionmessage/> //用於顯示普通的消息
關於展現數據:
方案一:
將須要展現的數據封裝到多個javabean中,將多個javabean封裝到一個List中,將該List存入valueStack->root中,在前端頁面經過struts的<s:iterator>標籤來獲取:
<s:iterator value="ognl表達式" var="變量名">
<tr>
<td><s:property value="#變量名.beanAttributeName"/></td>
</tr>
</s:iterator>
注意:若是使用var,它存儲在context中,因此在使用時要添加#號,也能夠以下方案:
<s:iterator value="ognl表達式">
<tr>
<td><s:property value="beanAttributeName"/></td>
</tr>
</s:iterator>
說明:上面寫法就表示直接在ognl表達式中取到的對象直接遍歷該對象屬性值
方案二:
咱們在action中聲明一個List集合屬性,而且提供getter/setter方法,在邏輯方法中給該list成員賦值,由於valueStack->root中會自動存儲action的相關屬性,因此就能夠直接在頁面上取得該list的屬性值。
Interceptor攔截器介紹:
struts2.0中Interceptor它基於spring aop思想,而aop思想本質時經過動態代理來實現,咱們的struts2攔截器主要時攔截action操做,在action執行先後進行一些其餘功能操做。
(經過對action產生動態代理對象,對代理對象的方法加強,在執行代理對象的方法以前會執行定義的全部攔截器棧,攔截器棧在這裏是採用遞歸調用的模式)
(Filter過濾器是攔截請求的,Interceptor攔截器是攔截action執行的)
攔截器鏈(攔截器棧)簡單說,就是能夠將多個攔截器造成一個鏈,在訪問他們時依次訪問。
struts2.0的執行流程圖:
自定義Interceptor攔截器介紹:
使用interceptor能夠在action執行指定方法先後進行處理工做,例如,完成權限控制。
如何定義Interceptor?
1.全部Interceptor都要實現接口com.opensymphony.xwork2.interceptor.Interceptor,重寫intercept()方法(須要實現的功能);
2.在配置文件struts.xml中的<package>標籤下配置自定義的Interceptor。
<interceptors>
<interceptor name="interceptor1" class=""></interceptor>
<interceptor name="interceptor2" class=""></interceptor>
<interceptor-stack name="mystack">
<interceptor-ref name="interceptor1"/>
<interceptor-ref name="interceptor2"/>
</interceptor-stack>
</interceptors>
3.在action中使用Interceptor
在struts.xml中的<action>中直接配置攔截器或者攔截器棧
<interceptor-ref name="[interceptor1/mystack]"></interceptor-ref>
注意:當咱們顯示的引入一個自定義的Interceptor,那麼默認的defaultStack就不會在導入,須要手動導入。
eg:
<action>
<interceptor-ref name = "mystack"/>
<!-- 手動導入defaultStack -->
<interceptor-ref name = "defaultStack"/>
</action>
又或者直接在自定義的mystack棧中引入defaultStack,只須要在action中引入mystack便可。
Interceptor練習:
@Override
public String intercept(ActionInvocation invocation)throw Exception{
invocation.getAction(); //獲得當前訪問的action,有了action對象能夠向前臺傳遞信息(addActtionError,addFieldError,addActionMessage...)
return invocation invoke(); // 表示放行
return "viewPath"; //表示轉發到該action的viewPath視圖
}
注意:咱們在struts.xml文件中配置action時候,可使用*通配符,這是它能夠處理多個方法,你指定的interceptor只想攔截某一個方法,該如何處理? 咱們可使用Interceptor接口的一個實現類(MethodFilterInterceptor)來完成操做邏輯操做同上,只是須要在struts.xml文件中聲明該攔截器時傳入指定的參數,指示須要攔截的方法,或者不須要攔截的方法便可。 eg: <interceptors> <interceptor name = "" class = ""> <!-- 如下兩種方式選擇一種便可 --> <param name = "excludeMethods"></param> //包含的方法 <param name = "includeMethods"></param> //不包含的方法 </interceptors>