1. 程式人生 > >struts2框架 轉載 精華帖

struts2框架 轉載 精華帖

作用範圍 nload 業務邏輯 指定 規範 叠代 分析 引入 所有

一、Struts2簡介

參考《JavaEE 輕量級框架應用與開發—S2SH》

Struts框架是流行廣泛的一個MVC開源實現,而Struts2是Struts框架的新一代產品,是將Struts1和WebWork兩種技術進行兼容、合並的全新的MVC框架。Struts2框架充分發揮了Struts1和WebWork這兩種技術的優勢,拋棄原來Struts1的缺點,使得Web開發更加容易。

Struts1運行原理:
技術分享圖片

Struts1工作流程:
(1)客戶端向Web應用發送請求,請求被核心控制器ActionServlet攔截;
(2)ActionServlet根據請求決定是調用業務邏輯控制器還是將請求轉發給相應JSP頁面;
(3)若調用業務邏輯控制器,則業務邏輯控制器再調用相應的模型來處理用戶的請求;
(4)處理的結果再通過JSP呈現給用戶

Struts1缺點:
(1)Struts1僅支持JSP作為表現層技術
(2)在Model2的基礎上發展得來,完全基於Servlet API,與Servlet API嚴重耦合,一旦脫離Web服務器,Action的測試將變得非常困難
(3)Action類必須繼承其提供的Action基類,實現處理方法時又必須使用Struts1的專有API,這種入侵式設計的最大弱點在於:一旦系統需要重構,這些Action類將沒有價值。

Struts2結合Webwork的優勢:
(1)Struts2支持更多表現層技術,有更好的適應性。
(2)Action無須跟Servlet API耦合,使得測試更加容易,同時提高代碼重用性;而且不耦合任何Servlet API(攔截器機制)
(3)Struts2具有更好的模塊化和可擴展性(插件機制)。

二、Struts2框架結構與工作原理

參考《JavaEE 輕量級框架應用與開發—S2SH》
博文推薦:struts2的核心與工作原理

Struts2是以WebWork為核心,采用攔截器機制對用戶的請求進行處理

框架結構:
技術分享圖片
工作流程:
(1)客戶端瀏覽器發送HTTP請求到Web應用
(2)Web容器將請求傳遞到標準ActionContextCleanUp過濾器以消除屬性,而不讓後續過濾器清楚,以延長Action中屬性(包括自定義屬性)的生命周期。ActionContextCleanUp作用
(3)再經過如stimesh等其他過濾器後,請求傳遞給StrutsPrepareAndExecuteFilter核心控制器
(4)StrutsPrepareAndExecuteFilter調用ActionMapper(Action映射器)確定調用哪個Action,再將控制權轉移給ActionProxy代理
(5)ActionProxy代理調用配置管理器ConfigurationManager從配置文件struts.xml中讀取配置信息,然後創建ActionInvocation對象
(6)ActionInvocation在調用攔截器鏈中的攔截器後再調用Action,根據Action返回的結果字符串查找對應的Result
(7)Result調用視圖模板,再以相反的順序執行攔截器鏈,返回HTTP響應
(8)HTTP響應以相反的順序返回給核心控制器StrutsPrepareAndExecuteFilter以及其他web.xml中定義的過濾器,最終返回給客戶端

三、一個Struts2的簡易Demo

(1)導入Struts所需的Jar包,這裏使用struts-2.3.31版本。下載地址
將struts-2.3.31\apps\struts2-blank.war解壓出來,並在struts2-blank\WEB-INF\lib中獲取運行struts2的最小包
技術分享圖片
特別註意版本對應問題,由於不同版本的框架封裝的內容會有所不同,當跟著教程做的時候,如果步驟完全相同但是出現異常,那麽很大可能是因為版本叠代修改了部分內容所致。

(2)在web.xml中配置核心控制器StrutsPrepareAndExecuteFilter
任何MVC框架需要與Web應用整合時都需要借助web.xml配置文件,由於StrutsPrepareAndExecuteFilter本質上是一個過濾器,在web.xml中用< filter>以及< filter-mapping>進行配置。而Web應用加載了StrutsPrepareAndExecuteFilter之後就有了Struts2的基本功能。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns="http://java.sun.com/xml/ns/javaee" 
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 
    id="WebApp_ID" version="3.0">
  <display-name>Struts2Demo</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  <!-- 配置StrutsPrepareAndExecuteFilter核心控制器 -->
  <filter>
      <!-- 過濾器名 -->
      <filter-name>struts2</filter-name>
      <!-- StrutsPrepareAndExecuteFilter核心控制器的實現類 -->
      <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
  </filter>
  <filter-mapping>
      <!-- 過濾器名 -->
      <filter-name>struts2</filter-name>
      <!-- 過濾器過濾所有請求 -->
      <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

配置核心控制器StrutsPrepareAndExecuteFilter就是用其實現類過濾所有的請求。Struts-2.5.8版本中的核心控制器實現類更改為org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter

(3)創建用戶輸入視圖register.jsp

<%@ page language="java" import="java.util.*" contentType="text/html; charset=UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>用戶註冊</title>
  </head>
  <body>
    <form action="register.action" method="post">
        username:<input type="text" name="username"/><br/>
        password:<input type="password" name="password"/><br/>
        <input type="submit" value="註冊"/><br/>
    </form>
  </body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

< form>標簽中的action屬性為表單參數提交到的地址

(4)創建業務Action

public class RegisterAction {
    private String username;
    private String password;
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public String execute() throws Exception{
        if(username!=null&&username.length()>0&&password!=null&&password.length()>0){
            return "success";
        }else{
            return "fail";
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

如代碼所示,RegisterAction是一個POJO,其屬性應與input.jsp中的表單name屬性對應。則當表單提交時,表單數據會通過setter()方法給Action對象賦值。
除此之外,Action類提供execute()方法返回結果字符串。

Struts2中的Action類優勢:

  • Action類完全是一個POJO,從而提高代碼的課重用率;
  • Action類無須與任何Servlet API耦合,便於測試和應用;
  • Action類的業務處理方法execute()將String作為返回值可以映射到任何視圖上,也可以是Action

(5)在src下創建struts.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
    "http://struts.apache.org/dtds/struts-2.3.dtd">
<struts>
    <!-- 指定Struts2處於開發階段,可以進行調試 -->
    <constant name="struts.devMode" value="true"/>
    <!-- Struts2的Action都必須配置在package裏。這裏使用默認的package -->
    <package name="default" namespace="/" extends="struts-default">
        <action name="register" class="action.RegisterAction">
            <!-- 配置execute()方法返回值與視圖資源之間的映射關系 -->
            <!--  
            <result name="success">/result.jsp</result>
            <result name="error">/error.jsp</result>
            -->
            <result name="success">/index.jsp</result>
        </action>
    </package>
</struts>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

極客學院Struts2配置文件Wiki
MyEclipse環境中,在src下創建的struts.xml在部署時會自動發布到WEB-INF/classes目錄下
當Struts2生成ActionProxy代理時,需要訪問Struts2的配置文件,有struts.xml(配置Action相關信息)與struts.properties(配置Struts2全局屬性)兩種。
如上的struts.xml,用< constant>元素設置Struts2的全局屬性,在< package>中定義了一個名為register的Action,並指定了實現類以及< result>元素用來指定execute()方法返回值與視圖資源之間的映射關系。
而struts.properties則以key=value的形式存儲全局屬性。

#指定Web應用的默認編碼集
struts.i18n.encoding=UTF-8
#當struts.xml修改後是否重新加載該文件,在開發階段最好打開
struts.configuration.xml.reload=true
#設置瀏覽器是否緩存靜態內容,在開發階段最好關閉
struts.serve.static.browserCache=false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Struts2中的全局屬性詳解
註意:若使用MyEclispe開發,則struts.xml在第一行會報錯,主要是因為MyEclipse沒有找到對應的dtd文件,但這完全不會影響運行。強迫癥可以把struts-2.3.31\src\core\src\main\resources目錄下的dtd文件導入到MyElipse中,如何導入

Demo運行流程分析:
(1)用戶在input.jsp中輸入數據提交後,所發送請求被核心控制器StrutsPrepareAndExecuteFilter過濾
(2)StrutsPrepareAndExecuteFilter調用ActionMapper,根據表單中action地址來確定名為register的Action類處理該請求
(3)然後Struts2框架讀取配置文件struts.xml信息生成ActionProxy
(4)ActionProxy根據package中action元素中的name和class屬性確定Action實現類為RegisterAction,並調用
(5)表單中的數據被setter()方法賦值給RegisterAction對象
(6)ActionProxy根據execute()返回值以及action元素中的result元素來確定返回哪個視圖資源給用戶

四、Action業務處理

1、Action實現方式
Action是Struts2應用的核心,用於處理用戶的請求。
而Struts2框架實現Action類有以下三種方式

  • 普通POJO類,通常包含返回值為字符串的無參execute()方法
  • 實現Action接口
  • 繼承ActionSupport類

(1)POJO類
如demo所示,謹記Action中的屬性名與表單中的元素屬性名完全相同,且對於表單中的每個元素一定要有對應的getter/setter方法,這樣Struts2才能夠自動將請求參數賦值給對應的Action屬性

(2)實現Action接口方式
Struts2提供了一個Action接口,定義了Action處理類應該實現的通用規範

/*
 * Action接口
 */
public interface Action {
    //定義Action接口中包含的一些結果字符串
    public static final String ERROR="error";
    public static final String INPUT="input";
    public static final String LOGIN="login";
    public static final String NONE="none";
    public static final String SUCCESS="success";

    //處理方法
    public String execute() throws Exception;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 定義了5個字符串常量,用於規範execute()方法的返回值
  • 定義了execute()方法,規範Action類應該包含execute()方法,且方法返回值是字符串

(3)繼承ActionSupport類方式
Struts2框架為Action接口提供了一個實現類ActionSupport,該類提供了很多默認方法,如默認處理用戶請求的方法、數據校驗的方法、獲取國際化信息的方法等
ActionSupport類是Struts2的默認Action處理類,如果配置Action類時沒有指定class屬性,系統自動默認使用ActionSupport類作為Action的處理類,對用戶的請求進行處理。
API文檔位置:struts-2.3.31/docs/xwork-apidocs/com/opensymphony/xwork2/ActionSupport.html

2、結合ServletAPI
有些時候Action類不訪問ServletAPI是不能實現業務邏輯的,例如跟蹤HTTP Session的狀態。Struts2也提供了一些方法訪問ServletAPI
(1)通過ActionContext
在Struts2框架中,Action可以通過ActionContext類來訪問ServletAPI
API文檔位置:struts-2.3.31/docs/xwork-apidocs/com/opensymphony/xwork2/ActionContext.html

(2)通過實現訪問ServletAPI的接口並重寫相應方法

接口名描述
ServletContextAware 實現該接口的Action可以直接訪問Web應用的ServletContext實例
ServletRequestAware 實現該接口的Action可以直接訪問用戶請求的HttpServletRequest實例
ServletResponseAware 實現該接口的Action可以直接訪問服務器響應的HttpServletResponse實例

Struts2的特色是Action不再與任何ServletAPI耦合,所以不推薦這種方式直接訪問Servlet API

(3)通過ServletActionContext工具類
API文檔位置:struts-2.3.31/docs/struts2-core-apidocs/org/apache/struts2/ServletActionContext.html

五、Struts2配置詳解

參考《JavaEE 輕量級框架應用與開發—S2SH》
配置文件降低了各組件之間的耦合,是聯系整個Struts2框架的紐帶,通過配置文件將Struts2的核心控制器StrutsPrepareAndExecuteFilter、業務控制器Action以及視圖等組件關聯在一起,實現相應的功能。雖然Struts2提供了Convention插件來管理Action、result,但大多數情況下配置文件采用XML形式。

1、全局屬性的配置
可以通過配置全局屬性來改變Struts2框架的一些默認行為,在Struts2中可以使用struts.xml、struts.properties以及web.xml進行配置
如果三個文件同時存在,則會按照struts.xml、struts.properties、web.xml的順序加載常量,後面的會覆蓋前面的,不過通常都在struts.xml中配置。
此外,struts.xml以及struts.properties應該保存在WEB-INF/classes目錄下,MyEclipse環境下可以保存在src下
(1)通過< constant>元素在struts.xml中定義常量

<struts>
    <!-- struts.i18n.encoding的值默認為UTF-8 -->
    <constant name="struts.i18n.encoding" value="GBK">
</struts>
  • 1
  • 2
  • 3
  • 4

(2)在struts.properties中定義

struts.i18n.encoding=GBK
  • 1

(3)通過元素在web.xml中配置

<filter>
    <init-param>
        <param-name>struts.i18n.encoding </param-name>
        <param-value> GBK</param-value>
    </init-param>
</filter>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

2、通過包< package>對核心組件進行組織和管理
如demo代碼所示,Struts2配置文件中的包,是由多個Action、多個攔截器、多個攔截器引用組成的集合

<struts>
    <!-- Struts2的Action都必須配置在package裏。這裏使用默認的package -->
    <package name="default" namespace="/" extends="struts-default">
        <action name="register" class="action.RegisterAction">
            <result name="success">/index.jsp</result>
        </action>
    </package>
</struts>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

其中常用屬性如下:
(1)name
指定包的名字,當存在多個包時作為唯一標識

(2)extends
指定包所繼承的其他包。
struts-default是Struts2框架默認的抽象包,包含了大量結果類型的定義、攔截器及其引用定義等,是配置Action的基礎,因此定義包時都要繼承struts-default包。
定義時,父包要先於子包;Action相同,後面的覆蓋前面

(3)namespace
指定包的命名空間,沒有指定namespace值則為默認命名空間”/”
Struts2以命名空間的方式來管理Action,同一個命名空間不能有同名的Action
若namespace=”/”,則訪問Action的URL為:http://ip:port/applicationname/register.action
若namespace=”/user”,則訪問Action的URL為:http://ip:port/applicationname/user/register.action

配置命名空間後,Struts2按照以下順序搜索Action:
- 指定命名空間,不存在則往下搜索
- 默認命名空間,不存在則往下搜索
- 報錯

3、< include>元素包含其他配置文件
常用於團隊模塊化開發後的整合

<struts>
    <include file="struts-others.xml"/>
</struts>
  • 1
  • 2
  • 3

< include>元素引用的xml文件必須是完整的Struts2配置文件,實際上在< include>元素引用文件時,會單獨解析每個xml文件

4、< action>配置
Struts2使用package下的action元素來配置Action,配置時需要指定action元素的name和class屬性
- name:指定該Action所處理請求的URL,如name=register,則處理的URL為register.action
- class:指定Action實現類,如果沒有指定,則默認使用ActionSupport類

除此之外,action元素還可以使用method屬性讓Action調用指定方法而不是execute()方法來處理用戶請求。
有時候,一個Action類中包含多個處理業務的方法,而不是execute()方法,如

public class UserAction {
    private String user;
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }

    public String add() throws Exception{
        return "add";
    }
    public String del() throws Exception{
        return "del";
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

若要調用add方法以及del方法,則要通過method屬性

<action name="addUser" class="action.UserAction" method="add"></action>
<action name="delUser" class="action.UserAction" method="del"></action>
  • 1
  • 2

像這種情況,Struts2還支持 * 通配符以減少冗余。利用通配符在定義Action的name屬性時使用模式字符串 * ,接下來就可以在class、method屬性以及< result>子元素中使用{N}的形式代表前面的第N個 * 所匹配的字符串。
如上述代碼可轉化為下面的代碼:

<action name="*User" class="action.UserAction" method="{1}"></action>
  • 1

有了通配符以及{N},就可以通過設計name來大大簡化代碼的編寫

5、result配置
Struts2框架通過配置文件中< action>的< result>子元素配置邏輯視圖名和物理視圖資源之間的映射關系。
配置< result>元素時通常需要指定name和type屬性:
- name屬性指定邏輯視圖名,也就是execute()返回的結果字符串
- type屬性指定結果類型,默認為dispatcher,表示請求轉發到JSP頁面。

(1)作用範圍:局部result與全局result

  • 局部result——< result>元素作為< action>元素的子元素,針對該Action有效
<struts>
    <package name="default" namespace="/" extends="struts-default">
        <action name="register" class="action.RegisterAction">
            <result name="success">/index.jsp</result>
        </action>
    </package>
</struts>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 全局result——< result>元素作為< global-results>元素的子元素,針對所有Action有效
<struts>
    <package name="default" namespace="/" extends="struts-default">               
                    <global-results>
            <result name="success">/index.jsp</result>
        </global-results>
        <action name="register" class="action.RegisterAction"></action>
    </package>
</struts>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

如果一個Action中包含了與全局result同名的局部result,則局部result會覆蓋全局result。亦即Action會首先搜索局部result,沒有匹配項再搜索全局result。

(2)結果類型
通過設置type屬性值來確定返回的結果類型
Struts2學習之結果類型總結
Struts2返回JSON對象的方法總結

6、異常處理
Struts2框架提供了聲明式異常處理方式,通過在struts.xml文件中配置< exception-mapping>元素,指定exception與result屬性確定映射關系
- exception屬性,用於指定Action出現異常所映射的異常類型
- result屬性,用於指定Action拋出異常時,系統轉入屬性值對應的< action>或< global-results>中的< result>元素

根據作用範圍的不同,又可分為
- 局部異常映射——< exception-mapping>作為< action>的子元素,針對該Action
- 全局異常映射——< exception-mapping>作為元素的子元素,針對所有Action
與result作用範圍類似,先局部,再全局

六、過濾器與攔截器

1.過濾器Filter
過濾器Filter是Servlet中較為實用的一種技術,允許Servlet對用戶請求進行預處理,並對Servlet響應進行後續處理.
在Struts2中,其核心控制器StrutsPrepareAndExecuteFilter就是一個過濾器,用來對用戶請求進行預處理以及後處理
參考詳談Filter過濾器

2.攔截器Interceptor
和過濾器類似,攔截器用於在Action被調用之前對請求進行預處理,以及Action被調用後進行後續處理
參考Struts2攔截器
此外,眾多默認攔截器的用法可參考攔截器詳解

3.案例:Struts2權限驗證功能的過濾器實現與攔截器實現
Struts2 角色權限

七、Struts2標簽庫與OGNL表達式

在JSP中,為了減少JSP中嵌入大量的Java代碼,JSP規範制定了JSP標準標簽庫JSTL(JSP Standard Tag Library),提高了JSP頁面的可讀性和可維護性。
而Struts2也有自己獨特的標簽庫,而且更為強大,不僅可以替代JSTL標簽庫,還適用於任何表示層技術(如Velocity、FreeMarker等)

解壓Struts2提供的struts2-core-x.x.x.jar文件,可以在META-INF目錄下找到struts2標簽庫描述文件struts-tags.tld
在JSP中使用標簽庫時,需要使用taglib指令引入標簽庫

<%@ taglib prefix="s" uri="/struts-tags" %>
  • 1

其中prefix=”s” 指定了標簽庫的前綴,uri=”/struts-tags”指定了標簽庫描述文件的路徑。
如果Sevlet規範版本是2.3及以下,還需要在web.xml中增加對標簽庫的定義

<taglib>
    <taglib-uri>/struts-tags</taglib-uri>
    <taglib-location>/WEB-INF/lib/**struts2-core-2.0.11.1.jar**</taglib-location>
</taglib>

struts2框架 轉載 精華帖