Struts2

Struts2概述

1.struts2 框架應用在javaee三層結構中web層框架

2.struts2框架在struts和webwork基礎之上發展全新的框架

其他框架:
springMVC

struts2框架入門

1.導入jar包

asm asm-commons asm-tree
commons-fileupload commons-io commons-lang3 
freemarker javassist 
log4j-api log4j-core 
ognl
strtuts2-core

2.創建Action類,創建execute方法,返回string

每次訪問servlet時候,都會執行service方法
    寫類繼承    HttpServlet,重寫類裏面的方法
    在web.xml中配置servlet訪問路徑,或者註解
訪問action,默認執行execute方法
    配置action類訪問路徑

配置action類訪問路徑
    創建struts2核心配置文件
        核心配置文件名稱和位置是固定的
        位置必須在src下面,名稱struts.xml

struts.xml:

<struts>
    <package name="hellodemo" extends="struts-default" namespace="/">
        <!-- name:訪問名稱 -->
        <action name="hello" class="cn.itcast.action.HelloAction">
            <!-- 配置方法的返回值到頁面 -->
             <result name="ok">/hello.jsp</result>
        </action>
    </package>
</struts>
http://127.0.0.1/項目名/hello(.action)

此時還不能訪問,因爲還沒有配置過濾器
過濾器在服務啓動時就執行
servlet在第一次訪問時執行

OpenSessionInViewFilter要在struts前面

<!-- Struts2框架的核心過濾器的配置 -->
<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>

查看源代碼

class StrutsPrepareAndExecuteFilter implements StrutsStatics,filter
1.過濾器在服務器啓動時候創建,創建過濾器時候執行init方法
在init方法中主要加載配置文件
包含自己創建的配置文件和strtus2自帶配置文件
struts.xml
web.xml

struts2配置
struts2的核心配置文件
src下strts.xml
名稱和位置固定
在配置文件中主要三個標籤:package,action,result,標籤裏面的屬性

package

1.類似於代碼包,區別不同的action,要配置action,必須首先寫package標籤。在package裏面才能配置action.
2.package標籤屬性
    name:屬性值跟功能本身沒有關係,也就是說可以隨意命名
    在一個配置文件可以寫多個package標籤,name屬性不能相同

extends:
extends="struts-default"
屬性值固定,struts-default
寫了這個屬性之後,在package裏面配置的類具有action功能

namespace屬性:
namespace屬性值和action標籤裏面的name屬性值構成訪問路徑
一般可不寫,默認“/”

action:

1.action標籤配置action訪問路徑
2.action標籤屬性
    name:
    namespace屬性值和action標籤裏面的name屬性值構成訪問路徑
    在package標籤裏面有多個action標籤,但是action的name屬性不能相同
    class:
    action全路徑
    method:
    比如在action裏面默認執行的方法execute方法,但是在action裏面寫其他的方法,讓其他方法方法可以執行,使用method進行配置

result:

根據action的方法返回值,配置到不同的路徑裏面
result標籤屬性
name:
和方法的返回值一樣
<!--配置方法的返回值到頁面-->
<result name="ok">/hello.jsp</result>
type:
配置如何到路徑中(轉發或者重定向)
屬性默認做轉發操作

3.修改struts默認常量值

常用的方式
在struts.xml中進行配置

其他兩種方式:
在src下面創建struts.properties進行修改
在web.xml

常用常量介紹:
struts.i18n.encoding=UTF-8
表單提交數據到action裏面,在action可以獲取表單提交數據
表單提交數據有中文,有亂碼問題
post提交直接設置編碼
get提交做編碼轉換
如果在action獲取表單通過post方式提交中文,中文亂碼問題幫解決了,不需要自己處理問題

模塊開發:
在覈心配置文件中引入配置文件

<!--引入hello.xml文件-->
<include file="cn/itcast/action/hello.xlm"></include>

Action編寫方式

1.action編寫有三種方式

第一種 創建普通類,這個類不繼承任何類,不實現任何接口
第二種 創建類,實現接口Action
實現接口中方法,裏面還有String常量
第三種 創建類,繼承類ActionSupport
ActionSupport本身就實現了Action接口

訪問action的方法

1.有三種方式實現

第一種 使用action標籤的method屬性,在這個屬性裏面寫執行的action的方法

    method="add"
    <package name="methoddemo" extends="struts-default" namespace="/">
        <action name="addAction" class="cn.itcast.method.BookAction" method="add"></action>
        <action name="updateAction" class="cn.itcast.method.BookAction" method="update"></action>
    </package>
action裏面每個方法都需要配置,如果有很多方法,需要多次配置

第二種 使用通配符方式實現

1 在action標籤裏面name屬性,name屬性值裏面寫符號 * 星號
"*"理解:表示匹配任意內容 
{1}表示匹配第一個*的內容。Book_add,{1}代表add 
    <package name="methoddemo" extends="struts-default" namespace="/">
        <action name="Book_*" class="cn.itcast.method.BookAction" method="{1}"></action>
    </package>

第三種 動態訪問實現(不用)

2.演示錯誤

1.如果action方法有返回值,在配置文件中沒有配置,出現錯誤
2.acrion方法返回String
3.action裏面的方法可以沒有返回值,沒有返回值的時候,在result標籤不需要配置
-把方法寫成void
-讓返回值,返回"none"  

1.結果頁面配置

全局結果頁面
如果在一個package裏面有多個action,方法裏面的返回值相同,到頁面也是相同,這個時候就可以使用全局結果頁面配置
<package name="demo" extends="strtus-default" namespace="/">
        <global-result>
            <result name="success">/hello.jsp</result>
        </global-result>
        <action name="addAction" class="cn.itcast.method.BookAction" method="add"></action>
        <action name="updateAction" class="cn.itcast.method.BookAction" method="update"></action>
    </package>
局部結果頁面
平時在action裏面寫result的方式就是局部結果頁面
既有全局結果頁面又有局部結果頁面以局部結果頁面爲準

result標籤type屬性
type:
針對到頁面中配置:
默認值,做轉發操作,dispatcher
做重定向操作,redirect,地址欄變化
針對到其他action裏面:
chain,轉發到acton,一般不用,有緩存問題
redirectActon ,重定向到action
    <package name="demo" extends="strtus-default" namespace="/">
        <action name="addAction" class="cn.itcast.method.BookAction" method="add">updateAction</action>
        <action name="updateAction" class="cn.itcast.method.BookAction" method="update">/<helo class="jsp"></helo></action>
    </package>

2.在action獲取表單提交數據,action沒有request對象,所以不能直接使用request對象

使用ActionContext類獲取
使用靜態的getContext()獲取當前線程的ActionContext對象,然後調用getParameters(),此方法返回包含所有HttpServletRequest參數信息
裏面得到的是以數組形式返回的object

使用ServletActionContext類獲取
調用靜態方法,得到對象 
    getRequest(),HttpServletRequest對象
    getResponse(),HttpServletResponse對象
    getServletContext(),ServletContext對象
    getPageContext(),PageContext對象

使用接口注入方式獲取
implements ServletRequestAware

3.struts2提供獲取表單數據方式

屬性封裝

    直接把表單提交屬性封裝到action的屬性裏面
    實現步驟:
        在action成員變量位置定義變量,變量名稱和表單輸入項的name屬性值一樣
        生成變量的set方法
    struts2自動封裝到變量裏面,沒有封裝到對象中

模型驅動封裝

    可以把表單數據封裝到對象裏面
    實現步驟:
        action實現接口ModelDriven
        實現裏面的方法,getModel方法把創建對象返回,創建對象不是聲明 
        在action裏面創建實體類對象
    要求:表單輸入項name屬性值和實體類屬性名稱一樣

在一個action中,不能同時使用屬性封裝和模型驅動封裝,同時使用時,只會執行模型驅動封裝。

表達式封裝

把表單數據封裝到實體類對象裏面

第一步 在action裏面聲明實體類

    private User user;

第二步 生成實體類變量的set和get方法

    public void setUser(User user){
        this.user = user;
    }
    public User getUser(){
        return user;
    } 

第三步 在表單輸入項的name屬性值裏面寫表達式形式

    jsp中修改:
    username:<input type="text" name="user.username">

比較表達式封裝和模型驅動封裝
1.使用表達式封裝和模型驅動封裝都可以把數據封裝到實體類對象裏面
2.不同點:
    使用模板驅動只能把數據封裝到一個實體類對象裏面,在一個action裏面不能使用模型驅動把數據封裝到不同的實體類對象裏面
    使用表達式封裝可以把數據封裝到不同的實體類對象裏面 list[index]

4.struts2獲取數據封裝到集合中

封裝到list集合
    在action聲明List
    生成list變量的set和get方法
    在表單輸入項裏面寫表達式 map['key值']

封裝到map集合
    聲明map集合
    生成get和set方法
    在表單輸入項的name屬性值裏面寫表達式

實例:
示例中,添加結束後,返回列表。不能直接返回jsp裏面,因爲沒數據。可以redirectAction到action

    <result name="list">list.jsp</result>
    <!-- action方法裏面有list方法-->
    <result name="addCustomer" type="redirectActon">customer_list</result>

ognl概述

EL表達式在jsp中獲取域對象裏面的值
OGNL是一種表達式,這個表達式功能更加強大
    在struts2裏面操作值棧數據
    一般把ognl在struts2操作,和struts2標籤一起使用操作值棧
OGNL是一個單獨的項目
    導入jar包 ognl 

ognl入門案例

使用ognl+struts2標籤實現計算字符串長度
objName.methodName()
在java代碼中,調用字符串.length();
    使用struts2標籤,在jsp中引入標籤庫
    <%@ taglib uri="/struts-tags" prefix="s"%>
    使用struts2標籤實現操作
    <!--使用ognl+struts2標籤實現計算字符串長度
        value屬性值:ognl表達式
    -->
    <s:property value="'haha'.length()"/>

什麼是值棧

1.之前在web階段,在servlet裏面進行操作,把數據放到域對象裏面,在頁面中使用el表達式獲取到,域對象在一定範圍內,存值和取值
2.在struts2裏面提供本身一種存儲機制,類似於域對象,是值棧,可以存儲和取值
    在action裏面把數據放到值棧裏面,在頁面中獲取到值棧數據

1.servlet和action區別
    servlet:默認在第一次訪問時候創建,創建一次,單實例對象
    action:訪問時候創建,每次訪問action時候,都會創建action對象,創建多次,多實例對象
2.值棧存儲位置
    每次訪問action時候,都會創建action對象
    在每個action對象裏面都會有一個值棧對象

如何獲取值棧對象

常用方式:使用ActionContext類裏面的方法得到值棧對象

    //獲取ActionContext類對象
    ActionContext context = ActionContext.getContext();
    //調用方法得到值棧對象
    ValueStack stack = context.getValueStack();
每一個ActionContext裏面只有一個值棧

值棧內部結構

第一部分root,結構是list集合,ArrayList

一般操作的是root裏面的數據

第二部分context,結構map集合,Map

context存儲的對象引用

向值棧放數據

s:debug標籤
    調試,查看值棧結構和存儲值
    沒做任何操作,棧頂元素是cn.itcast.action.ValueStackDemoAction,action引用
    action對象裏面有值棧對象
    值棧對象裏面有action引用

第一種 獲取值棧對象,調用值棧對象裏面的set方法

ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
stack.set(); HashMap

第二種 獲取值棧對象,調用值棧對象裏面的push方法

stack.push(); String

第三種 在action定義變量,生成變量的get方法

    一般使用第三種方式,因爲第三種方式不申請新的空間,節省空間 
向值棧放字符串

向值棧放對象
    定義對象變量
    生成變量的get方法
    在執行的方法裏面向對象中設置值 
向值棧放list集合
    定義list集合變量
    生成變量的get方法
    在執行方法裏面向list集合設置值

從值棧獲取數據

使用struts2標籤+ognl表達式獲取值棧數據
    <s:property value="ognl表達式"/>
從值棧獲取字符串
    <s:property value="存儲字符串名稱"/>
從值棧獲取對象
    <s:property value="存儲對象.屬性"/>
從值棧獲取list集合

第一種方式:

    <s:property value="list[0].usernaem"/>

第二種方式:

    s:iterator標籤使用
    <!--
        <s:iterator>:遍歷值棧的list集合

        <c:foreach items="" var="user">
        ${user.username}
        </c:foreach>
    -->
    <s:iterator value="list">
        <s:property value="list所存儲對象屬性"></s:property>
    </s:iterator>

第三種方式

    <!--
        遍歷值棧list集合,得到每個user對象
        機制:把每次遍歷出來的對象放到context裏面
        獲取context裏面數據特點:寫ognl表達式,使用特殊符號:#
    -->
    <s:iterator value="lsit" var="user">
        <s:property value="#user.username"></s:property>
    </s:iterator>
使用set,push方法如何取值?
    <!-- 獲取set方法設置的值,根據名稱獲取值 stack.set("itcast","abck") -->
    <s:property value="itcast"></s:property>
    <!-- 使用push方法獲取值,沒有名稱,只用設置的值 -->
    <!-- 向值棧存放數據,把向值棧放數據存放到數組裏面,數組名稱top,根據數組獲取值 -->
    <!-- stack.push("abcd") -->
    <!-- [0].top是ognl寫法 -->
    <s:property value="[0].top"></s:property>

EL表達式獲取值棧數據

<!-- 使用foreach標籤+el表達式獲取值棧list集合數據 -->
<!-- 導入jstl+standard jar包 -->
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<c:forEach items="${list}" var="user">
    ${user.usernaem}
    ${user.password}
    ${user.address}
</c:forEach>

爲什麼EL表達式可以獲取值棧數據?
EL表達式獲取域對象值
向域對象裏面放值使用setAttribute方法,獲取值使用getAttribute方法
底層增強request對象裏面的方法getAttribute方法
    首先從request域獲取值,如果獲取到,直接返回
    如果從request域獲取不到值,到值棧中把值獲取出來,把值放到域對象裏面

ognl表達式#,%使用

# 獲取context裏面數據

獲取context裏面數據,寫ognl時候,首先添加符號
#ocntext的key名稱.域對象名稱

% 在struts2標籤中表單標籤

在struts2標籤裏面使用ognl表達式,如果直接在struts表單標籤裏面使用ognl表達式不識別,只有%之後纔會識別

Struts2攔截器概述

struts2是框架封裝了很多功能,struts2裏面封裝的功能都是在攔截器裏面
struts2裏面每次執行默認的攔截器
struts2裏面默認攔截器位置
struts2-core struts-default.xml

1 攔截器底層使用兩個原理

aop思想
面向切面編程,不通過修改源代碼方式拓展功能

責任鏈模式
過濾鏈:一個請求可有多個過濾器進行過濾,每個過濾器只有做放行才能到下一個過濾器

aop思想和責任鏈模式如何應用到攔截器裏面?
攔截器在action對象創建之後,action的方法執行之前執行
在action方法執行之前執行默認攔截器,執行過程使用aop思想,在action沒有直接調用攔截器的方法,使用配置文件方式進行操作
在執行攔截器時候,執行很多的攔截器,這個過程使用責任鏈模式
加入執行三個攔截器,執行攔截器1,執行攔截器1之後做放行操作,執行攔截器2,執行攔截器2之後做放行,執行攔截器3,執行攔截器3之後放行,執行action方法

執行action
execute.executeAction(request,response,mapping)
創建action對象,使用動態代理方式
ActionProxy proxy = getContainer().getInstance(ActionProxyFactory.class).createActionProxy(namespace,name,method,extraCotext,true,false)
執行action方法
proxy.execute()
執行很多的攔截器,便利執行
if(interceptors.hasNext())
類似於放行的操作的方法
return invocation.invoke()

過濾器和攔截器區別:

過濾器:過濾器理論上可以任意內容,比如html,jsp,servlet,圖片路徑
攔截器:攔截器只可以攔截action

servlet和action區別:

servlet默認第一次訪問時創建,創建一次,單實例對象
action每次訪問時候創建,創建多次,多實例對象

在struts2裏面有很多的攔截器,這些攔截器是struts2封裝的功能,可以自己寫

攔截器結構

繼承類

class ModelDrivenIntercepter extends AbstractInterceptor
calss AbstractInterceptor implements Interceptor

接口裏面有三個方法

init 初始化
destroy 銷燬
intercept(ActionInvocation invocation) 攔截邏輯操作

開發中使用
寫類,繼承MethodFileterINterceptor類實現
讓action中某個方法不被攔截

讓攔截器和action有關係
不是在action調用攔截器的方法,而是通過配置文件方式讓建立關係

自定義登錄攔截器

1 需求:在項目中,有很多的action的超鏈接,實現只有登錄狀態纔可以點擊action的超鏈接實現功能,如果不是登錄狀態,點擊action超鏈接返回到登錄頁面

2 登錄的狀態:使用session域對象實現

登陸成功之後,把數據放到session裏面
判斷session是否有值,可以知道是否是登錄狀態

示例:
判斷是否登錄,判斷session裏面是否有名稱username的值

攔截器實現過程:
創建類,繼承MethodFilterInterceptor類

重寫MethodFilterceptor類裏面的方法寫攔截器邏輯

配置action和攔截器關係(註冊攔截器)
    1.在要攔截的action標籤所在的package標籤裏面聲明攔截器
    <interceptors>
        <interceptor name="攔截器名字" calss=""></interceptor>
    </interceptors>
    2.在具體的action標籤裏面使用聲明的攔截器
    <interceptor-ref name="loginintercept"></interceptor-ref>
    3.struts2裏面執行很多的默認攔截器,但是如果在action裏面配置自定義攔截器,默認的攔截器不會執行
    解決:把默認的攔截器手動使用一次
    <interceptor-ref name="defaultStack"></interceptor-ref>

    配置攔截器,對action裏面所有的方法都進行攔截

    配置不攔截:
    <interceptors>
        <interceptor name="攔截器名字" calss="">
            配置action裏面不進行攔截的方法
            name:excludeMethods
            值:action不攔截的方法名稱
            <param name="excludeMethods">方法名稱login,add</param>
        </interceptor>
    </interceptors>

    出現框架嵌套網頁問題:
    jsp 標籤form target="_parent"

Struts2標籤庫

struts2標籤使用jsp頁面中
s:property 和ogml表達式在jsp頁面中獲取值棧數據
s:property 獲取值棧list集合數據,表示變量list集合
s:debug:查看debug屬性

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章