struts的入門:
1.下載struts
2.新建項目
導入jar包.
struts解壓目錄/apps/struts-blank.war
解壓以後就有所須要的jar包
3.配置struts前端控制器
在web.xml中配置filter
<filter>
<filter-name>struts</filter-name>
<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
4.新建一個index.jsp
編寫一個a標籤
<a href="/s2_day01/hello">a_入門</a>
5.新建一個類(action)
一個普通的類
提供一個公共的有返回值的,返回值類型string,名稱爲execute的方法
6.建立配置文件
名稱:struts.xml
位置:src目錄
導入約束
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
"http://struts.apache.org/dtds/struts-2.3.dtd">
package 標籤:
name屬性:起個包名,保證這個項目中惟一
extends屬性:聲明當前包繼承於某個包 通常使用的默認值"struts-default"
namespace屬性:和action標籤的name屬性組成訪問路徑的
action標籤:建立路徑和類的對應關係
name屬性:和namespace屬性組成訪問路徑的
class屬性:自定義的action的全限定名
result標籤:配置邏輯視圖(action的返回值)和資源的跳轉的
name屬性:action中方法的返回值(邏輯視圖)
7.跳轉到1.jsp
a.讓action中的方法有一個返回值 返回值任意 bb
b.在struts.xml配置返回值對應的頁面 默認使用的是請求轉發
struts的簡易的執行流程(只是方便你們理解的,過程是不許確.在第四天的時候講準確的執行流程)
參考excle
經過剛纔的執行流程:
filter的init方法主要的做用之一:加載配置文件
filter的doFilter方法的做用,纔是執行攔截器和action的
加載的配置文件有那些?
struts提供好的
default.properties :提供了一些常量
struts-default.xml :配置了默認的攔截器及跳轉方式等操做
struts-plugin.xml :struts的一些插件的配置文件(如今暫時沒有)
咱們本身編寫的
★struts.xml :主要配置action和路徑的對應關係等一系列主要信息
struts.properties:提供了一些常量(通常咱們不提供)
web.xml中過濾器的初始化參數
注意:
由於咱們配置加載是有順序的,全部後面配置的同名配置會把以前的配置覆蓋掉.
------------------------------------------
配置文件詳解
常量的配置:
咱們能夠在struts.xml,struts.properties,web.xml中配置
推薦在struts.xml
在struts.xml中經過 <constant name="" value=""/>
例如:
<!-- action的後綴名 -->
<constant name="struts.action.extension" value="abc"/>
瞭解:
在struts.properties配置常量
在src下本身建立一個struts.properties
struts.action.extension=abc
理解:
在web.xml中配置過濾器的初始化參數
<!-- 配置filter的初始化參數 -->
<init-param>
<param-name>struts.action.extension</param-name>
<param-value>xyz</param-value>
</init-param>前端
常見的常量:
struts.action.extension:配置後綴名
struts.devMode:開發中模式 這個版本的默認值 false(若值爲true的時候,配置文件修改後不須要重啓服務器,可是有安全問題)
----------------------------
action的配置:
package標籤:
name屬性:起個包名,保證這個項目中惟一,方便讓別人繼承用的.
extends屬性:聲明當前包繼承於某個包 通常使用咱們直接或者間接繼承"struts-default" 就可使用這個包下的全部內容
namespace屬性:和action標籤的name屬性組成訪問路徑的
寫法:
不寫 等價於 namespace=""
根路徑 namespace="/"
帶路徑 namespace="/customer" ★
action標籤:建立路徑和類的對應關係
name屬性:和namespace屬性組成訪問路徑的 注意:版本不一樣,寫法不同.咱們的版本中不能出現 "/" (其實就是一個常量的配置問題:struts.enable.SlashesInActionNames)
class屬性:自定義的action的全限定名
method屬性:配置action要執行的方法名稱 默認值:execute
-------------------------------
include的配置
將其餘的自定義struts的配置文件包含到struts.xml中.方便團隊開發維護.
例如:
<include file="cn/itcast/a_hello/struts_hello.xml"></include>
--------------------------------------------------
action的編寫方式
(瞭解)方式1:普通的類
(理解)方式2:實現Action接口
提供了5個字符串常量(邏輯視圖)
success:成功訪問的時候
error:錯誤的時候
login:往登陸頁走的時候
none:頁面不跳轉
input:struts內部使用,當struts內部發生錯誤的時候,返回input
★方式3:繼承ActionSupport類
action的訪問方式
(瞭解)方式1:經過設置method訪問
★★方式2:通配符配置
<!-- 通配符配置 -->
<action name="demo2_*" class="cn.itcast.c_access.Demo2AccessAction" method="{1}"></action>
變態的寫法:
類名:ProductAction,OrderAction
方法名:save ,update
訪問路徑:
/ProductAction_save.action
/OrderAction_save.action
配置文件:
<action name="*_*" class="cn.itcast.c_access.{1}" method="{2}"></action>
★方式3:動態方法執行方式
前提:
開啓容許動態方法執行
在struts.xml中配置一個常量
struts.enable.DynamicMethodInvocation=true
路徑寫法:
/user!方法名.action
配置文件
<action name="user" class="cn.itcast.c_access.UserAction"></action>
案例分析:
看圖
技術點:
獲取request對象
ServletActionContext.getRequest();
-----------------------------------------
struts入門
獲取請求
頁面跳轉
入門案例:
導入jar包:解壓目錄下/apps/struts-blank.war
編寫action類:
方式3:繼承ActionSupport類
配置文件:
web.xml中配置核心過濾器 StrutsPrepareAndExecuteFilter
在src下本身建立一個struts.xml
導入約束
package標籤
name屬性
namespace屬性
extends屬性
action標籤
name屬性
class屬性
method屬性
result標籤
name屬性
標籤體:服務器內部路徑
----------------------
簡易執行流程
配置文件及其加載順序
struts提供好的
咱們本身編寫的
注意:
後面的同名配置會覆蓋以前的配置
配置文件中:
常量的配置
在struts.xml經過constant標籤配置
include配置
包含其餘的struts文件.團隊開發中使用
action的訪問方式
方式2:通配符配置
方式3:動態方法執行方式
*-*-*--*-*-*-*-*-*-*-**-*-*-*-*--*-*-*-*-*-*-*-*-*-java
訪問servlet的api方式
★方式1:經過ServletActionContext的靜態方法訪問
getRequest()
getResponse()
getServletContext()
(瞭解)方式2:經過接口注入的方式
咱們須要讓本身的action實現如下幾個接口
ServletRequestAware
ServletResponseAware
SessionAware
ServletContextAwareweb
(理解)方式3:經過ActionContext的方法訪問
獲取ActionContext對象(當成工具類使用)
ActionContext context = ActionContext.getContext();
獲取請求參數
Map<String , Object > context.getParameters()
域操做:
(至關於)往request域中放入數據:put(String key,Object Value)
往session域中放入數據: getSession().put(String key,Object Value)
往application域中放入數據: getApplication().put(String key,Object Value)
★action是多實例的
result配置:
action標籤下有result標籤:用來配置頁面跳轉
name屬性:邏輯視圖的名稱(方法的返回值) 默認值:success
type屬性:跳轉的方式
經常使用值:
dispatcher 轉發到jsp上 默認值
redirect 重定向到jsp上
chain 轉發到action上
redirectAction 重定向到action上
擴展:
stream 文件下載
標籤體:跳轉的路徑的
跳轉到jsp上 寫jsp的內部路徑
跳轉到當前包下的action上 直接寫action的名字
配置方式分類:
全局結果頁面配置:供當前包下的全部action共享.
經過package標籤下的子標籤
global-results
局部結果頁面配置:僅當前action可使用的
就是在action下配置result標籤
封裝數據
★方式1:屬性驅動set方式(適用參數個數少,例如分頁)
表單以前怎麼寫 如今還怎麼寫
在action中須要提供一些屬性的set方法
★方式2:屬性驅動頁面表達式方式(ognl表達式,封裝到多個對象中)
修改表單裏面的每一個子標籤的name屬性 javabean對象名稱.屬性名稱
在action中提供一個javabean對象且提供他的get和set方法
例如:
action中提供一個成員屬性 private User uu; //提供get和set方法
標籤子標籤中name屬性寫法 <input type="text" name="uu.username"/>
★★方式3:模型驅動(ModelDriven)
頁面寫法仍是之前的寫法
1.要求action實現ModelDriven接口
2.在action要提供一個javabean的成員字段且必須初始化
3.重寫接口中getModel的方法
4.經過getModel方法將javabean的成員字段返回
批量封裝
大前提:
須要在action提供給一個集合(list仍是map),提供集合的set和get方法
批量封裝成list
頁面表達式寫法:
name="集合屬性名稱[index].bean屬性名"
例如: name="ll[1].username"
批量封裝成map
頁面表達式寫法:
name="集合屬性名稱['鍵名'].bean屬性名"
例如:
name="mm['aa'].age"
搭建環境:
導入jar包
hibernate
驅動
日誌
struts
導入頁面
配置文件:
hibernate.cfg.xml
log4j.properties
struts.xml
web.xml中配置核心過濾器
建立持久化類和映射文件(複製)
建立action,service,dao
配置action
展現全部的客戶
客戶保存
步驟:
1.修改menu.htm中 "新增客戶"的鏈接
/crm_/jsp/customer/add.jsp(不推薦)
可使用轉發的方式訪問jsp
/crm/customer_addUI.action
2.在action中提供一個addUI的方法
直接轉發到jsp便可
3.修改add.jsp中表單信息
action屬性
子標籤的name屬性
4.在action提供一個保存的方法 save方法
模型驅動
在save方法中獲取封裝後的對象
調用service完成保存操做
重定向到customer_findAll.actionapache
-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*--*-編程
ognl表達式:咱們主要用它在頁面上來獲取值棧的數據.el也能夠獲取值棧中的數據
值棧:ValueStack 自己就是一個容器(一系列集合),存放請求參數和各大域中的數據及其它的數據
ognl表達式:
對象圖導航語言,是一種表達式語言
struts2的默認表達式語言是ognl
主要做用:
調用對象的方法
訪問類的靜態屬性
訪問類的靜態方法
★獲取值棧中的數據.
....
演示一下在jsp中使用ognl表達式(瞭解)
調用對象的方法:獲取 字符串"hello"的長度 <s:property value="'hello'.length()"/><br>
<!-- 格式:@類的全限定名@屬性名 -->
訪問類中的靜態屬性:獲取 π 的值 <s:property value="@java.lang.Math@PI"/><br>
<!--
格式:@類的全限定名@方法名()
注意:配置容許ognl訪問靜態方法 struts.ognl.allowStaticMethodAccess
-->
訪問類中的靜態方法:獲取隨機數 <s:property value="@java.lang.Math@random()"/><br>
值棧:
ValueStack
百度百科上:
ValueStack實際上就是一個容器。它由Struts框架建立,當前端頁面如jsp發送一個請求時,
Struts的默認攔截器會將請求中的數據進行封裝,並放入ValueStack
個人理解:
我把他稱之爲 struts的臨時數據中轉站.當請求來的時候,struts框架會爲每個請求建立一個值棧.
struts會將請求中的數據及其餘域中的數據封裝到值棧中.當請求結束的時候,值棧也就銷燬了.
以前獲取參數的時候,找request對象,今天咱們經過值棧獲取請求參數
以前獲取域中的數據的時候,找各個域,今天咱們經過值棧獲取各個域中的數據
以前咱們往域中放入數據的時候,找各個域.今天咱們也能夠經過值棧放到各個域中數據.
ValueStack是一個接口,咱們使用的是實現類 OgnlValueStack,ValueStack是貫穿action的生命週期的.
值棧的結構
一系列集合,主要分紅兩部分
root 本質上就是一個list集合(咱們之後主要往root中存放數據)
context 本質上就是一個map集合 map<String ,Object >
主要存放的數據有如下內容
key value
request request域中的數據(map)
session session域中的數據(map) ★
application application域中的數據(map) ★
attr 四個域中的數據按順序又存放了一遍. map
parameters 請求的參數 (map)
root root對象(地址值)
自定義key 自定義value 至關於往request中存放數據
ActionContext和值棧的關係.
actioncontext叫作action的上下文.咱們就把它當成是一個工具類
源碼描述:
當一次請求來的時候,struts框架會爲每個請求建立一個值棧.還會建立一個ActionContext對象.
將全部的數據放入值棧的context區域,將值棧再放入ActionContext中
繼續將ActionContext綁定到當前線程中.(ThreadLocal) 上面的操做都是struts幫咱們完成的
最後,咱們獲取數據或者操做數據的地方 在action中或者jsp中.如何在action中獲取ActionContext對象.
由於一次請求對應的是一個線程.只須要經過獲取當前線程綁定的actioncontext對象便可.就是咱們以前學習的
ActionContext.getContext();
ActionContext中有全部的數據(請求參數及各個域中的數據).
咱們把值棧中的Context賦值給了ActionContext中的context集合.以後獲取域中數據或請求參數的時候直接找actoincontext中的context集合便可.
獲取值棧
ActionContext.getContext().getValueStack();
往值棧中存放數據(通常是在action存放)
往root中存數據(★★)
方式1:經過值棧的api的api
push(Object obj)
set(String key,Object value):底層是先建立一個map集合,而後將數據放入map集合中,而後再將map放入root中
結論:
push對象,set集合.
方式2:經過Action的成員屬性
由於action自己就放在root中.
往context中存數據
注意:
操做值棧的Context 只須要操做ActionContext中的context
往request域中放入數據 至關於 put(String,Object)
往session域中放入數據 getSession().put(String,Object)
往application域中放入數據 getApplication().put(String,Object)
struts往值棧的context中放入數據的時候,給一些域起個兩個key,一個是長名字的key,一個是短名字的key.
長名字的key是struts底層使用的.爲了方便咱們獲取數據另外起個短名字的key
從值棧中獲取數據(通常是在jsp上獲取)
獲取root中的數據
經過 <s:property value="ognl表達式"/> 獲取數據
ognl直接寫對象的屬性名稱或者寫key名稱
獲取context中的數據
經過 <s:property value="ognl表達式"/> 獲取數據
ognl #key名
el獲取context中的數據,也能夠獲取root中的數據.
${username}
以前在web這樣寫的時候,依次從小到大四個域中查詢指定名稱的值.底層調用的是pageContext中findAttribute(key)的方法
findAttribute方法的底層:
先調用pageContext.getAttribute(key)
判斷是否能獲取到值.
若獲取到了,直接返回,且結束該次查找.
若沒有獲取到,調用request.getAttribute(key)
判斷是否能獲取到值.
若獲取到了,直接返回,且結束該次查找.
若沒有獲取到,調用session.getAttribute(key)
判斷是否能獲取到值.
若獲取到了,直接返回,且結束該次查找.
若沒有獲取到,調用application.getAttribute(key)
判斷是否能獲取到值.
若獲取到了,直接返回,且結束該次查找.
若沒有獲取到,返回null
咱們的${username}對findAttribute方法返回值進行了改造,若返回值爲null則返回一個""
${}或者ognl方式不存在空指針異常和角標越界異常.
今天咱們使用el的時候也能夠獲取到root中的數據,這是怎麼作的呢?
獲取的順序:
pageContext--request--root--context(大map)--session--application
就是struts對request.getAttribute方法進行了加強
使用的是裝飾者模式對request進行了包裝
先調用request原來的方法,看看是否有返回值,若沒有返回值調用valuestack對象的findValue(key)
findValue方法是先找root中數據,root中沒有再去找context(大map)中的數據.
從而也就能解釋下put到context中的數據 至關於放入request域中了
<s:property/>標籤的底層也是java代碼,代碼其實也是調用了findValue(key)
例如:
獲取put到context中的數據:<s:property value="#rkey"/><br/>
獲取put到context中的數據:<s:property value="#request.rkey"/><br/>
獲取put到context中的數據:<s:property value="rkey"/><br/>
★最終的結論
使用ognl獲取root中的數據 <s:property value="屬性名稱或者key的名稱"/>
使用ognl獲取context中的數據 <s:property value="#key名稱"/>
最重要的一句話 使用el也能夠獲取值棧中的數據.
ognl的特殊符號使用
#
★主要做用:
獲取context中的數據
手動構建一個map集合 在struts的form標籤中使用
%
主要做用:
強制計算ognl表達式
struts標籤的文本框:<s:textfield value="%{#request.username}" name=""></s:textfield>
$
主要做用:
在struts的配置文件(xml或者properties)中獲取值棧中的數據.
例如在文件下載時使用.
<result name="aa" type="stream">
<param name="content-disposition">attachment;filename=${filename}</param>
</result>
★循環:
<s:iterator value="{'男','女'}" var="s">
<s:property value="#s"/>
</s:iterator>
<s:iterator value="{'男','女'}">
<s:property/>
</s:iterator>
s:iterator有begin,end,step,var,value,status(至關於c標籤中varStatus)
★判斷:
<s:if test=""></s:if>
<s:elseif test=""></s:elseif>
<s:else test=""></s:else>
使用值棧和ognl替代以前的request域和el|jstl
以前查詢客戶list放入request域中,今天放入值棧(root)中
以前在list.jsp遍歷的時候使用的el|jstl,今天咱們可使用ognl和struts標籤配置 api
*-*-*-**-*-*-*-*-*-**-*-*-*-*-*-*-*-*-*-*-*-*-*-**-*瀏覽器
struts的註解開發
攔截器:只能攔截對action的訪問,struts的核心.
和咱們以前過濾器很類似
filter:能過濾全部的請求和響應
攔截器:只能攔截對action的訪問
其實就是在action(方法)執行以前或者以後,加入一些可重用的代碼,也能夠阻止方法的執行.(aop:面向切面編程)
動態代理
一次請求有可能匹配到多個過濾器,咱們把這些過濾器稱之爲過濾器鏈 FilterChain
訪問某一個方法的時候也會匹配到多個攔截器,咱們把這些攔截器稱之爲攔截器鏈.在struts中通常稱之爲攔截器棧
Interceptor:接口
intercept(ActionInvocation invocation) :執行攔截操做的----相似於filter的doFilter
invocation.invoke();至關於放行操做 ---- 相似於 chain.doFilter(..)
----------------------------------------
struts的簡易執行流程(不許確)
struts的較爲詳細執行流程(準確)
請求-->核心過濾器-->doFilter方法中作了一系列操做(設置編碼,建立actioncontext和值棧,包裝request),而後判斷
這次請求訪問的是不是actoin
若不是action:放行
如果action:繼續往struts的核心中走
---------------------------------------------------------
是action:繼續往struts的核心中走-->建立一個action的代理對象-->將執行權交個ActionInvocation對象,將這次訪問全部執行
的攔截器放入一個集合中,順序執行這些攔截器-->執行目標action中方法-->根據result再跳轉到相應的資源上-->倒序執行這些
攔截器-->走核心過濾器放行方法以後的操做,到達咱們的服務器-->服務器拿到數據以後,解析成響應行,頭,體,返回給瀏覽器
自定義攔截器:
1.編寫一個攔截器(實現Interceptor或者繼承Interceptor的實現類:例如,MethodFilterInterceptor,這個攔截器能夠指定對某些方法攔截,也能夠指定對某些方法進行忽略)
2.配置攔截器
方式1:
a.註冊攔截器
b.綁定路徑(在action中使用攔截器)
方式2:
a.註冊攔截器棧
b.綁定路徑(在action中使用攔截器棧)
例如:
方式1:
--<package name="demo1" namespace="/" extends="struts-default">
-- <!-- 配置攔截器 -->
-- <interceptors>
-- <!-- 1.註冊攔截器 -->
-- <interceptor name="Demo1MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo1MyInterceptor"></interceptor>
-- </interceptors>
--
--
-- <action name="demo1" class="cn.itcast.interceptor.a_hello.Demo1Action">
--
-- <!-- 2.綁定路徑,配置這個action執行的時候會執行那些攔截器 -->
-- <interceptor-ref name="Demo1MyInterceptor"></interceptor-ref>
--
-- <!-- 注意:一旦在action中顯式的聲明瞭使用某個攔截器,默認的攔截器就再也不執行了.咱們須要顯式的配置下默認的攔截器 -->
-- <interceptor-ref name="defaultStack"></interceptor-ref>
-- </action>
--</package>
方式2:
--<package name="demo1" namespace="/" extends="struts-default">
-- <!-- 配置攔截器棧 -->
-- <interceptors>
-- <!-- 註冊攔截器 -->
-- <interceptor name="Demo1MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo1MyInterceptor"></interceptor>
-- <interceptor name="Demo2MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo2MyInterceptor"></interceptor>
-- <interceptor name="Demo3MyInterceptor" class="cn.itcast.interceptor.a_hello.Demo3MyInterceptor"></interceptor>
--
--
-- <!-- 註冊攔截器棧 -->
-- <interceptor-stack name="MyStack">
-- <interceptor-ref name="Demo1MyInterceptor"></interceptor-ref>
-- <interceptor-ref name="Demo2MyInterceptor">
-- <!-- 對execute方法進行忽略,就是不攔截,多個方法用逗號隔開便可 -->
-- <param name="excludeMethods">execute</param>
-- </interceptor-ref>
-- <interceptor-ref name="Demo3MyInterceptor"></interceptor-ref>
-- </interceptor-stack>
-- </interceptors>
--
--
-- <action name="demo1" class="cn.itcast.interceptor.a_hello.Demo1Action">
--
-- <!-- 2.綁定路徑,配置這個action執行的時候會執行那個攔截器棧 -->
-- <interceptor-ref name="MyStack"></interceptor-ref>
--
-- <!-- 注意:一旦在action中顯式的聲明瞭使用某個攔截器,默認的攔截器就再也不執行了.咱們須要顯式的配置下默認的攔截器 -->
-- <interceptor-ref name="defaultStack"></interceptor-ref>
-- </action>
--</package>
案例-權限攔截
步驟:
1.先作登陸
建立User表,插入一條記錄
建立user的持久化類和映射文件(hibernate 03)
建立user的action,service,dao;配置action
把login.htm改爲login.jsp
修改表單的提交路徑: /crm_/user_login.action
須要給用戶名和密碼提供name屬性
須要在Action提供一個login方法
調用service的find4login(user),查詢有無此對象
如有:將用戶放入session中,重定向到 index.htm上. 在頁面上取出session中用戶名稱
若無:生成錯誤提示信息,請求轉發到login.jsp上.在頁面上取出錯誤信息.
2.再作攔截
自定義攔截器
判斷session中有無用戶
如有:放行
若無:生成錯誤提示信息,轉發到登陸頁面,放行
攔截那些action
客戶裏面的全部action
用戶裏面的全部action
細節:
1.在攔截器中獲取action
ActionSupport action = (ActionSupport) invocation.getAction();
2.添加錯誤提示信息及在頁面上展現錯誤信息
action中: addActionMessage("權限不足,請先登陸"); 或者 addActionError("權限不足,請先登陸");
jsp中: 使用struts標籤獲取<s:actionmessage/> 或者 <s:actionerror/>
3.在login.jsp中寫一段js代碼
判斷login.jsp是否在最大的窗口中打開,若不是的話,就讓他是最大的窗口
if(top.location != self.location){
top.location = self.location;
}
struts的註解開發
xml中配置了
package 繼承於誰,名稱空間
action 訪問路徑和類的對應,要執行的方法,結果頁面跳轉
攔截器
註解:
導入jar包.
struts的解壓目錄下/lib/struts2-convention-plugin-2.3.24.jar
須要在action中提供註解
類上的註解
@ParentPackage("struts-default")//聲明父包 至關於extends屬性
@Namespace("/")//聲明名稱空間
擴展:
@Results({@Result(name="",type="",location="")})//至關於全局的結果配置,僅適用於當前action下的全部方法
方法上的註解
@Action(value="user_save")
還有:
@Action(value="user_save",results={
@Result(name="aa",location="/1.jsp"),
@Result(name="bb",type="redirect",location="/2.jsp")
}
)
擴展:
攔截器沒有註解,攔截器還須要在xml中配置,咱們能夠經過註解配置訪問那個方法的時候使用某個攔截器
@Action(value="save",interceptorRefs={
@InterceptorRef(value="Demo1MyInterceptor")
})
注意:
action必須存在於 action | actions | struts | struts2這些包下安全