簡述struts2執行流程,Struts2教程

 2023-12-06 阅读 21 评论 0

摘要:Struts2教程 ? 一、初識Struts2   Struts2是一個基于MVC設計模式的Web應用框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。許多框架在大家一開始學習的時候都覺得比較繁瑣和多此一舉
Struts2教程

?

一、初識Struts2

  Struts2是一個基于MVC設計模式的Web應用框架,它本質上相當于一個servlet,在MVC設計模式中,Struts2作為控制器(Controller)來建立模型與視圖的數據交互。許多框架在大家一開始學習的時候都覺得比較繁瑣和多此一舉,但大體都有相同的目的,那就是增強可擴展性。Struts2的核心其實就是通過改配置文件的方式將請求和視圖(結果)分開。

1.1 開發環境搭建

  首先下載Struts2,地址http://struts.apache.org/,我這里下載的版本是2.5.10.1,解壓之后有如下4個文件夾

  

簡述struts2執行流程,  所需的基本jar包有以下9個。struts2-core是開發的核心類庫,struts2UI標簽的模板使用freemarker編寫,OGNL是對象圖導航語言,通過它來讀寫對象屬性。

  

1.2 Struts2配置文件

  ①web.xml文件

  主要完成對StrutsPrepareAndExecuteFilter的配置,它的實質是一個過濾器,負責初始化整個Struts框架并且處理所有的請求。在2.5以及2.1.3之前的版本filter-class會不同,請自行查詢官方文檔,filter-name和url-pattern是默認寫法,不建議修改。

<filter><filter-name>struts2</filter-name><filter-class>org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping><filter-name>struts2</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>
  ②struts.xml文件

  Struts2的核心配置文件就是struts.xml文件,在這個配置文件里面我們可以根據需要再包括其它一些配置文件。在通常的應用開發中,我們每個人來寫不同的模塊,每個人單獨配置一個struts.xml文件,最后合并,這樣也利于管理和維護。

  struts.xml中包含全局屬性、用戶請求和相應Action之間的對應關系、Action可能用到的參數和返回結果以及各種攔截器的配置,具體將在以下幾節中慢慢介紹。

struts2最新版本、  struts.xml可以從解壓過后的示例程序里復制,拷貝到工程的src目錄下,注釋或刪除掉struts標簽中的內容,來填寫我們需要的配置。

  ③struts.properties(default.properties)

  default.properties文件在struts2-core.jar中的org.apache.struts2包下,里面保存著許多Struts是的默認屬性,如編碼格式、是否啟用開發模式等等。當要修改某些屬性時,建議在struts2的xml配置文檔中進行更改,格式如下面一行代碼,而不建議自己新建一個struts.properties文件。

<constant name="" value=""></constant>
  ④struts-default.xml

  此文件是struts2框架默認加載的配置文件,它定義了struts2一些核心bean和攔截器,它會自動包含到struts.xml文件中(實質是通過<package ?extends="struts-default">),并為我們提供了一些標準的配置。我們可以在struts2-core.jar中找到這個文件。

二、struts.xml配置

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC"-//Apache Software Foundation//DTD Struts Configuration 2.5//EN""http://struts.apache.org/dtds/struts-2.5.dtd">
<struts><constant name="struts.ognl.allowStaticMethodAccess" value="true"/><package name="user" namespace="/user" extends="struts-default"><action name="user" class="com.dhcc.struts2.action.UserAction"><result>/user_add_success.jsp</result></action></package> 
</struts>
例子

2.1?配置文件的優先級

  在struts2中一些配置(比如常量)可以同時在struts-default.xml(只讀性),strtus-plguin.xml(只讀性),struts.xml,struts.properties和web.xml文件中配置,它們的優先級逐步升高,即是說后面的配置會覆蓋掉前面相同的配置。

  以struts.i18n.encoding=UTF-8的配置為例進行說明:

struts1和struts2的區別、  在struts.xml配置形式如下:

<constant name="struts.i18n.encoding" value="gbk"></constant>

  在struts.properties的配置形式如下:struts.i18n.encoding=UTF-8

  在web.xml中配置如下:

<filter><filter-name>struts2</filter-name>    <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class><init-param><param-name>struts.i18n.encoding</param-name><param-value>UTF-8</param-value></init-param>
</filter>

2.2 package配置

屬性名

是否必須

struts2工作原理。說明

Name

Package的唯一標識,不允許同名

Extends

請簡述Struts2開發環境的搭建步驟?否

指定要繼承的包

Namespace

指定名稱空間

struts2框架,Abstract

聲明包為抽象否

  package元素的namespace屬性及action的name屬性,它們共同定義了action所映射到的實質文件。

  namespace默認值“”,即不配置namespace屬性,如果action不能進行完整路徑匹配,則會來此namespace下進行匹配。namespace也可以配置成namespace="/"。它代表配置為項目的根。總結action的名稱探索順序:完全對應、逐步追溯到上級目錄查找、"/"下查找、默認namespace下查找。

struts2的執行流程。?  namespace引發的鏈接問題:當我們為action配置了namespace時,訪問此action的形式總會是如下形式:.../webappname/xxx/yyy/ActionName.action,而當此action成功執行跳轉到某個jsp頁面時,如想在此jsp頁面寫鏈接,一定要寫絕對路徑,因為相對路徑是相對.../webappname/xxx/yyy/,而如果以后我們修改了action的namespace時,相對路徑又要變,所以鏈接不能寫成相對路徑。 可以在建立一個jsp文件時,加上如下內容:

<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

  我們寫絕對路徑可以參此內容。還可以參<head>下的<base href="<%=basePath%>">?來完成絕對路徑的書寫。

三、Action

3.1 新建一個Action

 第一步,新建一個Class,繼承ActionSupport ,ActionSupport實現了execute()方法。

package com.struts2.test;
import com.opensymphony.xwork2.ActionSupport;
public class UserAction extends ActionSupport {public String add() {return "success";}public String del() {return "success";}public String update() {return "success";}public String query() {return "success";}
}

 第二步,配置此Action,在struts.xml中加入如下內容:

<package name="user" extends="struts-default" namespace="/user"><action name="addUser" class="com.asm.UserAction" method="add"><result name="success">/user/addUser.jsp</result></action><action name="delUser" class="com.asm.UserAction" method="del"><result name="success">/user/delUser.jsp</result></action><action name="updateUser" class="com.asm.UserAction" method="update"><result name="success">/user/updateUser.jsp</result></action><action name="queryUser" class="com.asm.UserAction" method="query"><result name="success">/user/queryUser.jsp</result></action>
</package>

 上面的method方法的值來源于CRUDAction中方法的名字,這樣當我們訪問上面的每一個Action時,它實質是和method指定的方法關聯上。如果沒有為action指定class,默認就是ActionSupport類,如果沒有為action指定method屬性,則默認執行execute方法,如果沒有指定result的name屬性,默認值為success。

 第三步,編寫相應的jsp頁面,在此略去crud文件夾下的四個跳轉jsp頁面(addSuccess.jsp等),重點是crud.jsp頁面。內容如下:

<html>
<%String path=request.getContextPath();
%><body><a href="<%=path %>/user/addUser.action">添加數據</a><br><a href="<%=path %>/user/delUser.action">刪除數據</a><br><a href="<%=path %>/user/queryUser.action">查詢數據</a><br><a href="<%=path %>/user/updateUser.action">修改數據</a><br></body>
</html>

? 最后發布測試。

3.2?動態調用DMI

  不使用method實現統一,我們在struts.xml中增加如下內容:

<action name="op" class="com.struts2.test.UserAction"><result name="add">/user/addUser.jsp</result><result name="del">/user/delUser.jsp</result><result name="query">/user/queryUser.jsp</result><result name="update">/user/updateUser.jsp</result>
</action>

  然后再在crud.jsp中定義如下鏈接:

<a href="<%=path %>/user/op!add.action">添加數據</a><br>
<a href="<%=path %>/user/op!del.action">刪除數據</a><br>
<a href="<%=path %>/user/op!query.action">查詢數據</a><br>
<a href="<%=path %>/user/op!update.action">修改數據</a><br>

  注意查看上面的鏈接地址,它們都是針對op這個action,然后再加地上“!+UserAction中相應的方法名”,最后再寫上.action即可以訪問到相應result的name指定的jsp。大家會發現跟上面不同的是,result的name不再都是SUCCESS,這樣才能區分開要訪問的頁面,但千萬不要忘記在UserAction中相應的方法也要返回add/del/query/update,而不是SUCCESS。如果不想使用動態方法調用,我們可以通過常量來關閉,即在struts.xml中增加如下配置:

<constant name="struts.enable.DynamicMethodInvocation" value="false"/>

3.3 通配符

  為了使用通配符,只需要改寫配置文件即可。將3.1節中的配置文件改為如下內容可達到相同的效果:

<package name="user" extends="struts-default" namespace="/user"><action name="*User" class="com.asm.UserAction" method="{1}"><result name="success">/crud/{1}User.jsp</result>
</package>

  當有.../addUser.action請求時,如果不能在當前應用中找到完全相同的addUser名字的Action時,通配符配置這時就起作用了。

?  其實如果我們有良好的編程命名習慣,所有的Action我們都只需要進行一次配置。舉例:規定所有的Action類都用XXXAction來命名,類中所有的CRUD方法都用add/del/update/query。Jsp頁面也用add/del/update/query_XXX.jsp這樣的形式。即配置文件可以寫成如下形式:

<action name="*_*" class="com.struts2.test.{2}Action" method="{1}"><result name="success">.../{1}_{2}.jsp</result>
</action>

  name中第一個*代表CRUD操作的名字,第二個*代表類的名字。所以訪問鏈接地址舉例如:.../del_User.action將訪問到UserAction類的del方法,成功后跳到del_User.jsp頁面。說明{0}是代表name中所有的*組合。

?3.4 接收參數

  ①Action屬性接收參數

  UserAction中建兩個屬性name和age,并且要生成相應的get/set方法。

public class UserAction extends ActionSupport {   private String name;private int age;public int getAge() {return age;}public String getName() {return name;}public void setAge(int age) {this.age = age;}public void setName(String name) {this.name = name;}
} 

  在傳參的jsp頁面,有一個表單

<form action="<%=request.getContextPath()%>/addUser.action" method="get">名字:<input type="text" name="name"><br>年齡:<input type="text" name="age"><br><input type="submit" value="login">
</form>

  這樣name和age就能接收到傳入的值。需要注意的是,傳參參照的action中的方法名,而非屬性名。

  ②DomainModel接收參數

  UserAction中有一個域模型private User user,注意不要自己new對象,User類中有name和age屬性和對應的get/set方法。UserAction中要生成User對象對應的get/set方法。

  訪問http://.../user/user!add?user.name=a&user.age=8 即可對user賦值,相當于調用了user的set方法。

public class UserAction extends ActionSupport {   private User user;public User getUser() {return user;}public void setUser(User user) {this.user = user;}  
}    
  • 如果傳入的參數個數和域模型的屬性個數不同,可以用DTO(Data Transfer Object)。比如傳入的參數還有一個isAdmin,那么我們建一個UserDTO,包含name,age和isAdmin三個屬性,用UserDTO去接收參數,然后用UserDTO再生成相應的User

  ③ModelDriven接收參數

public class UserAction extends ActionSupport implements ModelDriven<User>{   //需要實現ModelDriven接口private User user = new  User();  //ModelDriven需要自己new@Overridepublic User getModel() {return user;}   
}

3.5 訪問Scope對象(request、session、application,HttpServletRequest、HttpSession、ServletContext)

  ①與Servlet解耦合的非IOC方式

public class LoginAction extends ActionSupport {ActionContext context;Map request;Map session;Map application;public String execute() throws Exception {context=ActionContext.getContext();request=(Map) context.get("request");session=context.getSession();application=context.getApplication();request.put("req", "requst屬性");session.put("ses", "sesion屬性");application.put("app", "application屬性");return SUCCESS;}
}
主動獲取

  ②與Servlet解耦合的IOC方式

public class Login2Action extends ActionSupport implements RequestAware,SessionAware,ApplicationAware { //實現XxxAware接口,重寫setXxx()方法
    Map request;Map session;Map application;public String execute() throws Exception {request.put("req", "requst屬性");session.put("ses", "sesion屬性");application.put("app", "application屬性");return SUCCESS;}public void setRequest(Map<String, Object> request) {this.request=request;}public void setSession(Map<String, Object> session) {this.session=session;}public void setApplication(Map<String, Object> application) {this.application=application;}
}
依賴注入與控制反轉

  ③與Servlet耦合的非IOC方式

public class Login3Action extends ActionSupport { //獲取的純粹的Scope對象,它與容器相關
    HttpServletRequest request;HttpSession session;ServletContext application;public String execute() throws Exception {request = ServletActionContext.getRequest();session = request.getSession();application = ServletActionContext.getServletContext();request.setAttribute("req", "requst屬性");session.setAttribute("ses", "sesion屬性");application.setAttribute("app", "application屬性");return SUCCESS;}
}
主動獲取

  ④與Servlet耦合的IOC方式

public class Login4Action extends ActionSupport implements ServletRequestAware,ServletContextAware{ //實現XxxAware接口,重寫SetXxx()方法
    ActionContext context;HttpServletRequest request;HttpSession session;ServletContext application;public String execute() throws Exception {context=ActionContext.getContext();session=request.getSession();    request.setAttribute("req", "requst屬性");session.setAttribute("ses", "sesion屬性");application.setAttribute("app", "application屬性");return SUCCESS;}public void setServletRequest(HttpServletRequest request) {System.out.println("測試:"+request);this.request=request;}public void setServletContext(ServletContext application) {System.out.println("測試:"+application);this.application=application;}
}
依賴注入與控制反轉DI/IOC

  之后可以在jsp中使用EL表達式${requestScope.req}或通過request.getAttribute這樣的方式獲取對象值

3.6 default-action-ref?配置統一訪問

  當訪問沒有找到對應的action時,默認就會調用default-action-ref指定的action。在struts.xml文件的package中增加如下內容:

<default-action-ref name="error"></default-action-ref><action name="error"><result>/other/error.jsp</result></action>

  上面一段內容就是說當我們訪問的action不能被找到時便指向名為error的action中去,接著我們在下面配置了這個error Action。但是要注意,一個package內只配置一個<default-action-ref>,如果配置多個,就無法預測結果了。此時我們只要輸入.../myStruts2/luanFangWen.action這樣的形式,它就會去訪問這個默認的<default-action-ref>,通常我們會為它配置一個錯誤頁面,以提示用戶訪問的頁面不存在。?在web開發中,我們還可以把這個默認的action訪問配置成主頁,這樣當用戶訪問一些不存在的action時,總會跳到主頁上去。

  通過此配置,只要是訪問一個不存在的action便會轉向到.../other目錄下的error.jsp頁面。但是如果訪問是其它的不存在資源則仍是報tomcat所標識的404錯誤,我們可以在web.xml中作如下配置:

<error-page><error-code>404</error-code><location>/other/404error.jsp</location>
</error-page>

四、Result配置

4.1?type類型

  在前面的許多案例中我們所用到的Action基本都繼承自ActionSupport這個類,而在這個類中我們定義了五個字段:SUCCESS,NONE,ERROR,INPUT,LOGING。我們可以直接返回這些字段值,這些字段值實質是被定義成:String SUCCESS=”success”這樣的形式,所以我們只要在Result元素中用它們的小寫即可。

<result name="success" type="dispatcher"><param name="location">/default.jsp</param>
</result>

  如果我們都采用默認的形式,最終可以簡寫成:<result>/default.jsp</result>

Type類型值

作用說明

chain

用來處理Action鏈

dispatcher

用來轉向頁面,通常處理JSP

redirect

重定向到一個URL

redirectAction

重定向到一個Action

plainText

  顯示源文件內容,如文件源碼

freemarker

處理FreeMarker模板

httpheader

控制特殊http行為的結果類型

stream

?

向瀏覽器發送InputSream對象,通常用來處理文件下載,還可用于返回AJAX數據。

velocity

處理Velocity模板

xslt ??

??處理XML/XLST模板

json

序列化action為json

  當一個Action處理后要返回的Result是另一個Action,就需要使用chain和redirectAction。以chain為例,它的param有4個值可配,actionName(默認)、namespace、method和skipActions。namesapace的默認值當前namespace,可以省略不寫。method用于指定轉向到一個目標action所調用的方法,默認是調用下一個action的execute方法,所以也可以省略。SkipActions是一個可選的屬性,一般不用。

<package name="public" extends="struts-default"><!-- Chain creatAccount to login, using the default parameter --><action name="createAccount" class="..."><result type="chain">login</result></action><action name="login" class="..."><!-- Chain to another namespace --><result type="chain"><param name="actionName">dashboard</param><param name="namespace">/secure</param></result></action>
</package><package name="secure" extends="struts-default" namespace="/secure"><action name="dashboard" class="..."><result>dashboard.jsp</result></action>
</package>
example

  注意:如果result中指定type類型為redirect,要想傳遞參數可以在result指向的jsp頁面中附加參數即可,我們可以在test2 action的result中寫成:

<result name="success" type="redirect">/test2Suc.jsp?username=${username}</result>

  隨后在test2Suc.jsp頁面中引用時會出現三個問題:

  1.EL表達式引用失效,(EL表達式應該使用${param.username}形式)。我們也可以使用<%=request.getParameter("username")%>獲取參數值。

  2.由于在前面的TestAction中設定的值為中文,而附加到這里的uri請求的參數后面時會出現亂碼問題。(可以使用URI編碼再解碼解決此問題)

  3.值棧取值失效:因為每一次request共享同一個值棧,所以服務器端的forward跳轉也是能共享同一值棧得。但是當redirect重定向到test2Suc.jsp頁面,這時其實就是重發的一次request,所以前一個action保存的值棧內容全部失效。這也就是為什么我們要附加參數的原因。

4.2?global-results(全局result)

  如果我們所有的action均有可能跳到相同的頁面,則不防使用全局result。為了方便引用我們專門建立一個package來存放公共的result。在會用到個全局的跳轉時,只需要繼承自這個公共的package即可。建立公共包,代碼如下:

<package name="pubResult" extends="struts-default" abstract="true"><global-results><result name="error">/error.jsp</result></global-results>
</package> 

  由于它下面沒的action配置,所以我們可以像默認的struts-default包一樣,聲明abstract=true,這樣聲明表示此packgage下不會有action,它一般是用來讓別的package繼承。隨后再在要用到全局result中引用這個公共的package。代碼如下:

<package name="testGlobal" extends="pubResult" ><action name="error" class="com.struts2.ErrorAction"></action><action name="error2" class="com.struts2.Error2Action"></action>
</package>

  這樣操作相當于把全局的result加到了此package下的所有action中去。

4.3 動態result(了解)

  action中的變量r,設置了get/set方法,在struts.xml中使用${r}根據不同的值對應到不同的result。

public class DynaAction extends ActionSupport {private String username;private String nextAction;public String execute() throws Exception {if (username.equals("admin")) {nextAction = "admin";} else if (username.equals("user")) {nextAction = "user";} else {nextAction = ERROR;}return SUCCESS;}...省略get/set方法    
}
action示例
<package name="dynaTest" extends="pubResult"><action name="dyna" class="com.asm.DynaAction"><result name="success" type="chain">${nextAction}</result></action><action name="admin" ><result>/admin.jsp</result></action><action name="user"><result>/user.jsp</result></action>
</package>
struts.xml示例

  當把參數傳遞到DynaAction中去時,如果傳遞的值為admin,我們便設定了nextAction的值admin,在配置文件中我們通過${nextAction}(用在struts配置文件中的ognl,其實nextAction的值是存在值棧中,我們通過${}這樣的形式取出,在此只作了解,后面的章節詳細介紹)來獲取值便為admin,隨后再繼續把請求傳遞到下一個Action中去(此時也即admin.action),為了方便我們設定了兩個ForwardActionadmin.action和user.action。這樣便可以跳到指定的jsp頁面。 原理:dyna.action執行后會繼續把請求傳遞給下一個Action,而下一個Action的到底是哪一個Action,是通過DynaAction中動態指定的,比如這里是根據傳遞的username的值指定。

五、ValueStack(值棧)

  1.ValueStack是一個接口,在struts2中使用OGNL(Object-Graph Navigation Language)表達式實際上是使用實現了ValueStack接口的類OgnlValueStack.它是ValueStack的默認實現類.

  2.ValueStack貫穿整個action的生命周期,每一個action實例都擁有一個ValueStack對象,其中保存了當前action對象和其他相關對象.

  3.struts2把ValueStack對象保存在名為:struts.valueStack的request域中.即ValueStack作用域為request.當action創建的時候,ValueStack就創建了,action被銷毀的時候,ValueStack就銷毀了

  4.ValueStack中的數據分兩部分存放:root(對象棧,也稱Object Stack,CompoundRoot)和context(Map棧,OgnlContext),Struts將把動作和相關對象壓入Object Stack,而把各種各樣的映射關系壓入Context Map。

  • 其中的root對象是CompoundRoot,CompoundRoot繼承了ArrayList,提供了額外的方法:push(),和pop()方法,用來對root對象中所包含的數據進行存取。正是由于這兩個方法,CompoundRoot變成了一個棧結構。struts2中,一個請求在最終到達Action的方法之前,Action對象本身會被壓入ValueStack(實際上就是放到ValueStack的CompoundRoot中),所以action對象是CompoundRoot中的一個元素。
  • 其中的context對象是OgnlContext,它實現了map接口,在valuestack的默認實現類中,即OgnlValueStack類中,調用ongl中的方法:Ognl.createDefaultContext(..)給context賦值,查看源代碼可知,此方法返回的是一個OgnlContext對象。

  5.獲取valueStack的三種方法:

 ValueStack v1 = ActionContext.getContext().getValueStack();ValueStack v2 = ServletActionContext.getValueStack(ServletActionContext.getRequest());ValueStack v3 = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");

  6.ValueStack內存結構圖

  

  在jsp中使用struts的<s:debug/>標簽可以在頁面上生成一個超鏈接,通過該鏈接可以查看ValueStack和Stack Context 中的所有值信息,如下圖(Stack Context下面沒有截全,大家自己動手試一下看一看):

  

  7.常用的存儲數據的方法

  ⑴向對象棧中存數據,即ValueStack中的root(CompoundRoot)對象 

   *?先得到root,再把數據壓入到root中,這中方式是放入到棧底.
??????????????? ValueStack valueStack = ActionContext.getContext().getValueStack();
??????????????? valueStack.getRoot().add(new Person());
? ? ? ? *?先得到root,利用add(index,Object)把一個對象壓入到root中指定位置.
??????????????? ValueStack valueStack = ActionContext.getContext().getValueStack();
??????????????? valueStack.getRoot().add(0,new Person());//這里0,表示壓入棧頂.
? ? ? ? *?存放一個map到對象棧中
??????????????? ValueStack valueStack = ActionContext.getContext().getValueStack();
??????????????? valueStack.set("msg","dude"); //先封裝成Map,在把Map放入到對象棧中,且放入棧頂.
? ? ? ? *?利用valueStack的push方法把一個對象直接壓入棧頂
??????????????? ValueStack valueStack = ActionContext.getContext().getValueStack();
??????????????? valueStack.push(new Person());

  ⑵從值棧中獲取數據

   ? ?*?通過request,session等向map中存儲數據

    ? ActionContext.getContext().getValueStack().peek();

? ? ? ? ? ? ? ? ActionContext.getContext().getValueStack().getRoot().get(0);

  ⑶向map棧中存數據,即ValueStack中的context(OgnlContext)

??????? *?通過request,session等向map中存儲數據
??????????????? ServletActionContext.getRequest().setAttribute("username","joey");
??????????????? ServletActionContext.getSession().put("pwd","123");
? ? ?  ?*?直接向map棧中放數據
??????????????? ActionContext.getContext().put("msg","how you doing"); ??

  8.利用OGNL表達式取ValueStack中的數據
????????(1)<s:property />:取棧頂的元素。取Stack Context中的值時,應加#,如<s:property value=“#parameter.t” />
????????(2)<s:iterator />:取棧頂的元素。此標簽的value屬性值無論來自對象棧還是Map棧,都可以不加#前綴(<s:select/>標簽也適用),因為此標簽在迭代的時候,總是把當前正在迭代的元素放入到棧頂。value可以不寫,默認是迭代棧頂元素。

?六、OGNL(Object Graphic Navigatinon Language)對象圖導航語言

  OGNL是Struts2中使用的一種表達式語言,它可以用于JSP的標簽庫中,以便能夠方便的訪問各種對象的屬性;它用于界面將參數傳遞到Action(并進行類型轉換)中,還可以用于struts2的配置文件中。

  下面用一個例子來談ognl的定義,在這個例子中,我們的LoginAction中有一個User對象,而在User對象中又有一個Address對象,這些對象之間依靠這種類的字段進行關聯,或者說是依靠字段屬性進行導航,

  (1)值棧中Action的普通屬性:<s:property value="username" />

  (2)值棧中Action的普通方法:<s:property value="方法()" />

  (2)值棧中對象的普通屬性:<s:property value="user.age" />  //如果自己不new,user.xxx只有傳入值才會構造user,需要參數為空的構造函數

                ?<s:property value="user.address.city" />

  (3)值棧中對象的普通方法:<s:property value="user.方法()" />

                ?<s:property value="user.name.length()" />

  (4)靜態方法:?<s:property value="@全類名@方法()" /> ?//在某些版本中,struts.ognl.allowStaticMethodAccess的默認值為false,我們只需在struts.xml中增加如下內容:

          <constant name="struts.ognl.allowStaticMethodAccess" value="true"/>

  (5)靜態屬性:?<s:property value="@全類名@屬性" />

  (6)默認類Math的訪問:<s:property value="@java.lang.Math@min(1,2)"/><br>

              ??<s:property value="@@min(1,2)"/><br>

              <s:property value="@@PI"/> ? ?//因為是默認的類,所以可以省略類名

  (7)普通類的構造方法:<s:property value="new com.dhcc.vo.Student('jack','20','85.5')"/><br> ?//只new出對象,顯示的時候其實是調用對象的toString方法

              ?<s:property value="new com.dhcc.vo.Student('jack','20','85.5').name"/>

  (8)集合對象:

     ?訪問list:<s:property value="users"/> ? ?//[user1,user2,user3]

?    ?訪問list中某個元素:<s:property value="users[0]"/>

     ?訪問list中某個屬性的集合:<s:property value="users.{age}"/> ??

     ?訪問list中某個屬性的集合的特定值:<s:property value="users[0].age"/> ? | ? <s:property value="users.{age}[0]"/>

     ?訪問set:<s:property value="dogs"/> ? ?

     ?訪問set中某個元素:set無序,不能取下標

     ?訪問map:<s:property value="dogMap"/> ? ? ?//{dog1:d1,dog2:d2}

     ?訪問map中某個元素:<s:property value="dogMap.dog1"/> ?或者 ?<s:property value="dogMap['dog1']"/>

     ?訪問map中所有鍵:<s:property value="dogMap.keys"/><br>

     ?訪問map中所有值:<s:property value="dogMap.values"/><br>

     ?訪問容器的大小:<s:property value="users.size()"/><br> ?//不加()也可以

  (9)投影:?#是指取出符合條件的所有Student對象,而^#是指取出符合條件的第一個對象,$#是指取出符合條件的最后一個對象。

     ?選擇年齡等于20的user信息:<s:property value="users.{?#this.age==20}"/><br>

     ?選擇年齡大于20的user名字信息:<s:property value="users.{?#this.age>20}.{name}"/><br> ??

     ?選擇年齡大于20的第一個user名字信息:<s:property value="studentList.{^#this.grade>60}.{name}"/>

                       ??<s:property value="users.{?#this.age>20}.{name}[0]"/><br> ?

     ?選擇年齡大于20的最后一個user名字信息:<s:property value="studentList.{&#this.grade>60}.{name}"/><br> ?

  (10)N語法top語法

     ?N語法[0]<s:property value="[0]"/><br> //[com.dhcc.struts2.action.UserAction@6a35f7e3, com.opensymphony.xwork2.DefaultTextProvider@6239dff6]

     ?N語法[1]:<s:property value="[1]"/><br>    //[com.opensymphony.xwork2.DefaultTextProvider@6239dff6]

     ?N語法[0].top:<s:property value="[0].top"/><br>  //com.dhcc.struts2.action.UserAction@6a35f7e3

     ?N語法[1].top:<s:property value="[1].top"/><br>  //com.opensymphony.xwork2.DefaultTextProvider@6239dff6

     ?N語法top:<s:property value="top"/><br>    //com.dhcc.struts2.action.UserAction@6a35f7e3

     ?N語法取值:<s:property value="[0].user.username"/><br>  

     ?N語法取值:<s:property value="top.user.username"/><br>

?    說明:規定棧頂的對象為[0],而我們只使用[0]的意思是從值棧中第一個對象取,一直取至棧底。N的意思是從值棧中的第N個對象開始,取到棧底為止。如果要想訪問某個對象,需要使用[N].top,純top可以簡潔地取出值棧中的棧頂對象。當我們通過chain鏈訪問時,值棧中可能有兩個以上的Action對象。

?  (11)獲取Stack Context中的信息

    除了可以從值棧中獲取信息,還可以從Stack Context中獲取信息,只是要加上#,因為這些對象都是存在一般的Context Map中,而不是存在值棧中。

名稱?

作用?

例子?

parameters

包含當前HTTP請求參數的Map

#parameters.id[0]作用相當于request.getParameter("id")

request

包含當前HttpServletRequest的屬性(attribute)的Map

#request.userName相當于request.getAttribute("userName")

session

包含當前HttpSession的屬性(attribute)的Map

#session.userName相當于session.getAttribute("userName")

application

包含當前應用的ServletContext的屬性(attribute)的Map

#application.userName相當于application.getAttribute("userName")

Attr

用于按request > session > application順序訪問其屬性

#application.userName相當于application.getAttribute("userName")?

  (12)OGNL總結

    OGNL有一個上下文的概念,這個上下文件實質就是一個Map結構,它實現了java.utils.Map接口,在struts2中上下文的實現為ActionContext,下面是上下文的結構示意圖:

    

  當struts2接受一個請求時,會迅速創建ActionContext,ValueStack,action。然后把action存放進ValueStack,所以action的實例變量可以接受OGNL訪問。

  訪問上下文中的對象需要使用#號標注命名空間,如#application、#session。另外OGNL會設定一個根對象,在struts2中根對象就是ValueStack值棧對象,如果要訪問根對象中對象的屬性,則可以省略#命名空間,直接訪問該對象的屬性即可。在struts2中,根對象的實現類為OgnlValueStack,該對象不是我們想象的只存放單個值,而是存放一組對象,在OgnlValueStack類里有一個List類型的變量,就是使用這個List變量來存放一組對象。在root變量(List類型)中處于第一位的對象叫棧頂對象,通常我們在Ognl表達式里直接寫上屬性的名稱即可訪問root變量里對象的屬性,搜索順序是從棧頂對象開始尋找,如果棧頂對象不存在該屬性,就會從第二個對象尋找,如果沒有找到就從第三個對象尋找,依次往下尋找。?注意:struts2中 ,OGNL表達式需要配合struts的標簽才可以使用。

七、struts標簽

7.1通用標簽

  添加struts標簽庫:<%@ taglib uri="/struts-tags" prefix="s" %>

?  ①<s:property>

  default:可選屬性,如果需要輸出的屬性值為null,則顯示屬性指定的值

  escapeHtml:可選屬性,指定是否格式化html代碼。類似的還有escapeCsv和escapeXml

  value:可選屬性,指定需要輸出的屬性值,如果沒有指定該屬性,則默認輸出ValueStack棧頂的值

<s:property value="username" default="管理員" /><br/>
<s:property value="''<hr/>>" escapeHtml="false" />

  ②<s:set> ?此標簽主要用于設置一些屬性值

  scope:指定變量被設置的范圍,該屬性可以接受applicationsessionrequestpageaction。如果沒有設置該屬性,則默認放置在OGNL Context中,我們可以通過#號來引用。

  value:賦給變量的值,如果沒有設置該屬性,則將ValueStack棧頂的值賦給變量。

  var:屬性的引用名稱,id/name均過時。此名稱用于引用push到ValueStack的值

<s:set var="UserName" value="user.name"/>
Hello, <s:property value="#UserName"/>
<s:set var="janesName">Jane Doe</s:set>
<s:property value="#janesName"/>

?

posted on 2017-06-30 13:54 ErBing 閱讀(...) 評論(...) 編輯 收藏

轉載于:https://www.cnblogs.com/erbing/p/7028616.html

版权声明:本站所有资料均为网友推荐收集整理而来,仅供学习和研究交流使用。

原文链接:https://hbdhgg.com/1/191621.html

发表评论:

本站为非赢利网站,部分文章来源或改编自互联网及其他公众平台,主要目的在于分享信息,版权归原作者所有,内容仅供读者参考,如有侵权请联系我们删除!

Copyright © 2022 匯編語言學習筆記 Inc. 保留所有权利。

底部版权信息