1. 程式人生 > >2018.12.19 Struts2 框架總複習

2018.12.19 Struts2 框架總複習

總結Struts2 框架

struts2技術的優勢

  • 專案開源,使用及拓展方便
  • 提供Exception處理機制
  • Result方式的頁面導航,通過Result標籤很方便的實現重定向和頁面跳轉
  • 通過簡單、集中的配置來排程業務類,使得配置和修改都非常容易
  • 提供簡單、統一的表示式語言來訪問所有可訪問的資料
  • 提供標準、強大的驗證框架和國際化框架
  • 提供強大的、可以有效減少頁面程式碼的標籤
  • 提供良好的Ajax支援
  • 擁有簡單的外掛,只需放入相應的Jar包,任何人都可以擴充套件Struts2框架,比如自定義攔截器、自定義結果型別、自定義標籤等,為struts2定製需要的功能,不需要什麼特殊配置,摒棄可以釋出給其他人使用
  • 擁有智慧的預設設定,不需要另外進行繁瑣的設定。使用預設設定就哭完成大多數專案程式開發所需要的功能

常見的Web層框架

  • Struts2
  • Struts1
  • WebWork
  • SpringMvc

    Web層框架都會有一個特點就是基於前端控制器模式實現的

什麼是前端控制器模式呢?

在圖中傳統方式的開發,有一次請求就會對應一個Servlet。這樣機會產生很多的Servlet,而struts2江蘇哦哦於的請求都會先先經過一個前端控制器,在前端控制器中實現框架的部分功能,剩下具體擦坐要提交到具體的Action中。那麼所有的請求都會經過前端控制器,那麼用什麼來實現前端控制器呢?過濾器就是最好的一個實現方式。因為需要所有的請求都可以被過濾器攔截,然後再過濾器中實現部分的功能。所以Struts2的前端控制器也是有過濾器來實現的。

Struts2框架的快速搭建

實現步驟:

  • 下載Struts2的開發包 https://struts.apache.org/
  • 選擇對應的版本下載 然後解壓出來一個資料夾

目錄結構的總結

apps:該資料夾村用於存放官方提供的Struts2示例程式,這些程式可以作為學習的資料,可以為學習提供參照。各示例都是war檔案,可以通過zip方式進行解壓
docs:該資料夾用於存放官方提供的Sturt2文件,包括struts2快速入門、struts2的文件以及API文件等內容
lib:該資料夾用於存放struts2的核心類庫,以及struts2的第三方外掛類庫
src:該檔案用於存放該版本struts2框架對應的原始碼
有了struts2的開發環境,就可以進行操作了

  • 建立Web專案引入相應的jar包(不需要全部都引入,參考apps下面的專案來)

    struts2-blank.war是一個空的工程,可以解壓這個然後進去web-inf/lib 的檔案下複製jar包

Struts2專案以來的額基礎JAR包說明

到此為止,一個struts2專案就搭建好了。下面來複習做一個簡單的測試吧

建立一個頁面,在WebContent下建立一個頁面 test.jsp,寫一個超連結訪問Action的

接下來我們寫一個Action,就是在類中建立一個 名為execute 的預設執行方法 返回值是String 方法無引數

String型別的值就是一個邏輯檢視(邏輯檢視:相當於對一個真實的頁面,取一個別名) 通過這樣的方式來實現頁面的跳轉

這個是一個普通的類如何程式設計一個Action類呢,接下來完成配置Action

接下來是最關鍵的也是最容易忘記的一步。配置我們的前端控制器,也叫核心過濾器StrutsPrepareAndExecuteFilter

標準的web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
  <display-name>struts</display-name>
   <filter>
        <filter-name>struts2</filter-name>
        <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>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
</web-app>

到此就能正常進入測試了是否能用

還是很成功的

下面來總結一寫執行的流程
從客戶端傳送請求過來,先經過前端控制器(核心過濾器 StrutsPrepareAndExecuteFilter)過濾器中執行一組攔截器(一組攔截器完成部分功能),在其預設棧中的攔截器會得到執行,這個具體的可以看之前的部落格。攔截器執行完成之後,就會執行目標Action,在Action中返回一個結果檢視,根據Result的配置進行頁面的跳轉

Struts2的配置檔案的載入順序:

每次從客戶端傳送請求到伺服器都要經過Struts2的核心過濾器StrutsPrepareAndExecuteFilter,這個過濾器有兩個功能:預處理和執行。在預處理中主要就是用來載入配置檔案的。對應的是過濾器中的init方法,而執行是用來執行一組攔截器完成部分功能的,對應的是過濾器的doFilter方法。

載入struts2的配置檔案的方法

init_DefaultProperties();


init_TraditionalXmlConfigurations();

//載入struts.xml  struts-default.xml
init_LegacyStrutsProperties();


-->載入順序是
    default.properties
    struts-default.xml
    struts-plugin.xml
    struts.xml     ----配置Action以及常量
    struts.properties  ---配置常量
    web.xml -----配置核心過濾器

注意:後加載配置檔案中常量的值會將先載入的配置檔案中常量的值給覆蓋

struts.xml常見配置

Action的配置

Struts2的框架的核心配置檔案是struts.xml檔案,該檔案主要用來配置Action和請求的對應關係。

package的配置

Struts2框架的核心元件是Action和攔截器,它使用包來管理Action和攔截器。每個包就是多個Action、多個攔截器、多個攔截器引用的集合。在struts.xml檔案中,package元素用於定義包配置,每個package元素定義了一個包配置,每個package元素定義了一個包配置。package元素的常用屬性

    表中就是package元素的常用屬性,其中,在配置包時,必須指定name屬性,就是包的標識。
    除此之外,還可以指定一個可選的extends屬性,extends屬性值必須是另一個包的name屬性值,但該屬性值通常都設定為struts-default,這樣該包中的Action就具有了Struts2 框架預設的攔截器等功能了。除此之外,Struts2 還提供了一種所謂的抽象包,抽象包不能包含Action定義。為了顯式指定一個包是抽象包,可以為該package元素增加abstract="true'屬性。
    在package中還有namespace的配置,namespace 屬性與action標籤的name屬性共同決定了訪問路徑


namespace三種配置:
    預設名稱空間:跟名稱空間就是namespace
    跟名稱空間:就是namespace="/"
    帶名稱的名稱空間:帶名稱的名稱就是namespace="/demo1"

struts2常量的配置

Struts2常量配置共有3種方式,分別如下:
    在struts.xml檔案中使用<constant>元素配置常量。
    在struts properties檔案中配置常量。
    在web.xml檔案中通辻< init-param>元素配置常量。
為了讓大家更好地掌握這3種Struts2常量配置的方式,接下來分別對它們迸行講解,具體如下:
    1、在struts.xml檔案中通辻<constant>元素配置常量
        在struts.xml檔案中通過<constant>元素來配置常量,是最常用的方式。在struts.xml檔案中通過<constant .../> 元素來配置常量時,需要指定兩個必填的屬性name和value
        name:該屬性制定了常量的常量名
        value:該屬性制定了常量的常量值
        

struts.xml中配置常量

struts.properties 的格式配置常量

web.xml 中配置常量

分模組配置


Action的編寫的方式

Action的是一個POJO的類

在struts2中,Action可以不繼承特殊的類或實現任何特殊的介面,僅僅是一個POJO。POJO全稱Plain Ordinary Java Object(簡單的Java物件),只要具有一部分getter/setter 方法的那種類,即使可以稱為POJO。一般在這個類中,要有一個公共的無參構造方法和一個execute() 方法。

package com.legend.action;

public class TestAction {

    /**
     * 引數的返回值必須是String 型別
     * 方法不能帶有引數
     * 可以丟擲異常
     * 方法的許可權修飾符是public
     */
    public String execute() throws Exception {
        System.out.println("Hello,Struts2被執行了......");
        return "success";
    }
    
}

Action類實現一個Action的介面(實際開發中很少使用)

package com.legend.d_api;

import com.opensymphony.xwork2.Action;
/**
 * Action類詳解
 * 方式2:實現一個介面Action
 *      裡面有execute方法,提供action方法的規範
 *      Action介面預置了一些字串,可以在返回結果時使用。為了方便
 * @author qichunlin
 *
 */
public class Demo4Action implements Action{

    @Override
    public String execute() throws Exception {
        // TODO Auto-generated method stub
        return null;
    }
    
    
}

在Action介面中提供了5個已經定義的五個常量如下:

Action類繼承ActionSupport類(推薦)

package com.legend.d_api;

import com.opensymphony.xwork2.ActionSupport;

/**
 * Action類詳解
 * 方式3:繼承一個類ActionSupport
 *      幫我們實現了Validateable,ValidateAware,TextProvider,LocaleProvider
 *      如果我們需要用到這些介面的實現時就不需要自己來實現了
 * @author qichunlin
 *
 */
public class Demo5Action extends ActionSupport{

    
    public String method() throws Exception {
        // TODO Auto-generated method stub
        return LOGIN;
    }
    
}

Action訪問

在Action標籤中有一個屬性method,通過method的配置來指定Action中的某個方法執行.

第一種:通過配置method屬性完成

Action類

struts.xml配置

第二種:通過萬用字元的配置完成

在<action>的name屬性中使用的 * 表任意字元,method 中的{1}代表name 屬性中的出現的第一個*所替代的字元

第三種:動態方法呼叫

動態發發在訪問Struts2中預設是不開啟的,如果使用需要開啟一個常量

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

動態方法訪問主要控制的是在頁面端,所以編寫Action和配置Action都很簡單,關鍵是訪問路徑的編寫。在做測試的時候主要是直接訪問沒有頁面


Day02 Struts2

1.Struts2訪問Servlet的API

前面已經對Struts2的額流程已經執行完成了,但是如果表單中有引數如何進行接受又或者我們需要向頁面儲存一些資料,又要如何完成?這就下面我們學習ServletAPI的目的來實現這個功能。

1.1 通過ActionContext類訪問

Struts2框架提供了Actioncontext類來訪問Servlet API ,ActionContext是Action執行的上下文物件,在Actioncontext中儲存了Action執行所需要的所有物件,包括parameters、request、session、application等。

ActionContext類訪問ServletAPI


put方法使用

獲取當前執行緒的ActionContext物件

通過引數key來查詢當前ActionContext中的值

返回一個包含所有HttpServletRequest引數資訊的 Map物件

專案測試

ServletAPI.jsp頁面

提交的Action配置

ServletAPI2.jsp頁面

struts.xml

web.xml配置

控制檯列印前端頁面接收的資料

從後臺向前端輸出的資料

****

1.2 通過特定的介面訪問

專案測試

2.結果頁面配置

在struts.xml檔案中。使用result元素來配置Result邏輯是圖與物理檢視之間的對映,result元素可以有name和type屬性,但這兩中屬性都不是必選的。

  • name屬性:指定邏輯檢視的名稱,預設值是success
  • type屬性:指定返回的檢視資源的型別,不同的型別代表不同的結果輸出,預設值是dispatcher。
在結果頁面的配置中,Struts2有兩種配置的方式,一種是全域性結果頁面,一種成為區域性結果頁面。全域性結果是指在這個包下的所有返回相同的字串的值,都可以向這個頁面進行跳轉。區域性結果是指在某個Action中返回的字串的值,會向這個頁面跳轉

2.1 全域性結果頁面

在package節點下面的節點位置順序

Content Model : 
    (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-
 results?, global-exception-mappings?, action*)

資料填充

result-type 型別

紅色標記的是比較常見的
如果用的時候可以檢視文件。javadoc裡面有對應的用法

提供具體的使用方法

<?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>
<!-- 是否開啟開發模式
    struts.enable.DynamicMethodInvocation = false
 -->
    <constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
    
    <package name="result" namespace="/" extends="struts-default">
        <!-- 轉發 -->
        <action name="Demo1Action" class="com.legend.action.Demo1Action" method="execute">
            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
        
        <!-- 重定向 -->
        <action name="Demo2Action" class="com.legend.action.Demo2Action" method="execute">
            <result name="success" type="redirect">/hello.jsp</result>
        </action>
        
        <!-- 轉發到action -->
        <action name="Demo3Action" class="com.legend.action.Demo3Action" method="execute">
            <result type="chain">
                 <!-- action的名字 -->
                 <param name="actionName">Demo1Action</param>
                 <!-- action所在的名稱空間 -->
                 <param name="namespace">/</param>
            </result>
        </action>
        
        <!-- 轉發到action -->
        <action name="Demo4Action" class="com.legend.action.Demo4Action" method="execute">
            <result type="redirectAction">
                <!-- action的名字 -->
                <param name="actionName">Demo1Action</param>
                <!-- action所在的名稱空間 -->
                <param name="namespace">/</param>
            </result>
        </action>
    </package>
    
    <!-- 引入xml檔案 -->
    <include file="com/legend/b_api/struts.xml"></include>
    <include file="com/legend/c_param/struts.xml"></include>
</struts>   

3.Struts的資料封裝------Action處理請求引數的方式

Struts2的資料封裝分為兩大類,一類是屬性驅動,一類是模型驅動。

3.1 屬性驅動(分為兩種,一種只需要提供屬性的set方法;另一種可以通過表示式直接封裝到物件中。)

在Struts2中,可以直接在Action中定義各種Java基本資料型別的欄位,使這些欄位與表單欄位資料相對應,並利用這些欄位進行資料傳遞。

3.1.1 屬性驅動方式一:提供屬性的set方法的方式

Demo8Action的編寫


頁面

struts.xml

控制檯

總結:該方式如果屬性很多回顯得資料冗餘,修改起來很麻煩

3.1.2 屬性驅動方式二:頁面提供表示式的方式

物件實體

Demo9Action

頁面

控制檯

相比之下,這種方式,比上面的方式更加符合日常程式設計,面向物件的需求。


3.2 模型驅動

通過實現ModelDriver介面來接收請求的引數,Action類必須實現ModelDriver介面,並且要重寫getModel() 方法,這個方法返回的就是Action所使用的資料模型物件。
模型驅動方式通過JavaBean模型進行資料傳遞。只要是普通的JavaBean,就可以充當模型部分,採用這種方式,Java Bean所封裝的屬性與表單的屬性一一對應,JavaBean將作為資料傳遞的載體。

編寫Action類

頁面

控制檯

總結:大部分我們會優先使用模型驅動的方式,因為Struts2內部有很多結果是圍繞模型驅動設計的。但如果頁面向多個物件中封裝,那麼就需要使用屬性驅動的方式二了。

3.3 Struts2中封裝集合型別資料

在實際開發中,有些時候我們需要批量插入使用者或者批量插入其他的物件,在Action中需要接受多個Action中封裝的物件,然後進行傳遞。表單的資料就要封裝到集合中了,一般是List和Map

頁面

Action類(用的是屬性驅動,定義集合,提供getset方法)


Day03

1.OGNL

1.1 什麼是OGNL

OGNL的全稱是物件圖導航語言(Object-Graph Navigation Language),它是一種功能強大的開源表示式語言,使用這種表示式語言,可以通過某種表示式語法,存取Java物件的任意屬性,呼叫Java物件的方法,同時能夠自動實現必要的型別轉換。如果把表示式看作是一個帶有語義的字串,那麼OGNL無疑成為了這個語義字串與Java物件之間溝通的橋樑。

1.2 OGNL 的作用

Struts2預設的表示式語言就是OGNL,它具有一下的特點:

  • 支援物件方法呼叫。例如:objName.methodName();

  • 支援靜態方法呼叫和值訪問,表示式的格式為@[類全名(包括包路徑)@[方法名 | 值名] 例如:@[email protected]('foo%s','bar').

  • 支援賦值和表示式串聯 例如:price=100,discount=0.8,calculatePrice(),在方法中進行懲罰計算會返回80

  • 訪問OGNL上下文 (OGNLContext)和ActionContext

  • 操作集合物件

1.3 OGNL的要素

OGNL的操作實際上就是圍繞OGNL結構的三要素而進行的,分別是表示式(Expression)、根物件(RootObject)、上下文環境(Context),

分析OGNL的結構

1.3.1 表示式

表示式是整個OGNL的核心,OGNL會根據表示式去物件中取值。所有OGNL操作都是針對表示式解析後進行的。它表明了此次OGNL操作要做什麼。表示式就是一個帶有語法含義的字串,這個字串規定了操作的型別和操作的內容。OGNL支援大齡的表示式語法

1.3.2 根物件(Root)

Root物件可以理解為OGNL的操作物件,表示式規定了做什麼,而Root物件則規定了對誰操作。OGNL稱為物件圖導航語言,所謂物件圖,即以一個任意一個物件為根,通過OGNL可以訪問與這個物件關聯的其他物件。

1.3.3 Context物件

    實際上OGNL的取值還需要一個上下文環境,設定了Root物件,OGNL可以對Root物件進行取值或者寫值等操作,Root物件所在的環境就是OGNL的上下文環境(Context)上下文環境就是一個Map型別的物件,在表示式中訪問Context中的物件,需要使用#好加上物件名稱,即  #物件名稱  的形式。

1.2 具體的應用

通用寫法

訪問物件的方法

String name = (String) Ognl.getValue("getName()", oc, oc.getRoot());//預設取得值是root元素的
        String name2 = (String) Ognl.getValue("#user1.getName()", oc, oc.getRoot());//指定呼叫user1中的額方法

//給User賦值/修改
String name3 = (String) Ognl.getValue("setName('小花'),getName()", oc, oc.getRoot());//預設取得值是root元素的
        String name4 = (String) Ognl.getValue("#user1.setName('小白'),#user1.getName()", oc, oc.getRoot());//指定呼叫user1中的額方法
                

訪問物件的靜態方法

String name = (String) Ognl.getValue("@[email protected]('hello world')", oc, oc.getRoot());//預設取得值是root元素的
        Double PI = (Double) Ognl.getValue("@[email protected]", oc, oc.getRoot());//預設取得值是root元素的
        Double PI2 = (Double) Ognl.getValue("@@PI", oc, oc.getRoot());//預設取得值是root元素的
        

獲取root中的屬性值

String name = (String) Ognl.getValue("name", oc, oc.getRoot());

獲取Context中的屬性值

String name = (String) Ognl.getValue("#user1.name", oc, oc.getRoot());

為屬性賦值

String name2 = (String) Ognl.getValue("#user1.name='123',#user1.name", oc, oc.getRoot());//賦值的同時還把值取出來
        Integer age = (Integer) Ognl.getValue("#user2.age", oc, oc.getRoot());//賦值
        


2. 值棧 (ValueStack)

2.1 什麼是值棧

ValueStack是Struts的一個介面,字面意義是值棧,OgnlValueStack是ValueStack的實現類,客戶端發起一個struts2架構會建立一個action例項建立一個Ognl值棧例項,OgnlValueStack貫穿整個Action的生命週期,struts2中使用OGNL將請求Action的引數封裝為物件儲存到值棧中,並通過OGNL表示式中讀取棧中的物件屬性值。

2.2 值棧的內部結構

在OgnlValueStack中包括兩部分,值棧和map(即ognl上下文)

2.3 ActionContext和ValueStack的關係

在建立ActionContext 的時候 建立ValueStack的物件,將ValueStack物件給ActionContext。
ActionContext中又一個ValueStack的引用,ValueStack中也有一個ActionContext的引用,
ActionContext獲取ServletAPI 的時候,依賴值棧了。

2.4 操作值棧

對Action中的屬性提供get方法的方式

因為Action本身在值棧中,Action中的屬性也就預設在值棧中了,所以我們可以通過Action的屬性提供get的方式來操作值棧。

2.5 EL的特殊字元的使用

'#' 號的使用

獲取context的資料

<s:property value="#request.name" />

用於構建一個Map集合

<s:iterator value="#{'aaa':'111','bbb':'222','ccc':'333'}" var="entry">
    <s:property value="key" />-----<s:property value="value" />
    <s:property value="#entry.key" />-----<s:property value="#entry.value" /><br/>
</s:iterator>

<s:radio list="#{'1':'男','2':'女'}" name="sex"></s:radio>

'%' 號的使用

強制解析OGNL表示式

<s:textfiled name="name" value="%{#request.name}" />

強制不解析OGNL表示式

<s:textfiled name="name" value="%{'#request.name'}" />

'$' 號的使用

在配置檔案中使用OGNL表示式

在struts的配置檔案中使用   .XML檔案或者屬性檔案