第一節、MVC以及Struts2簡介
第二節、Action生命周期以及接收表單數據
第三節、Struts2配置以及Struts.xml詳解
-
Struts2 主要配置文件
Web.xml 設置過濾器以及annotation初始化參數 Struts.xml 主配置文件 Struts.properties 默認屬性文件 Struts-default.xml 默認配置文件 Struts-plugin.xml 插件配置文件
-
Struts2 主要配置加載次序
由上至下,以此為: Struts-default.xml Struts-plugin.xml Struts.xml Struts.properties Web.xml 如果在多個文件中配置了同一個Struts2常量,則后一個文件中的配置的常量值將覆蓋前面文件中配置的常量值。在不同文件中配置常量的方式是不一樣的,但不管哪個文件中,配置Struts2常量都要指定兩個屬性:常量name和常量value 推薦在struts.xml文件中配置Struts2常量
-
Struts-default.xml 配置信息
Bean元素屬性 class:必選,指定了Bean實例的實現類 type:可選,通常是通過某個接口或者在此前定一個過的Bean name:可選,它指定的Bean實例的名字,對於有相同type的多個Bean,name必須唯一 scope:可選,指定Bean的作用域,只能是default、singleton、request、session和thread之一 static:可選,它指定Bean是否使用靜態方法注入。通常而言,當指定了type屬性時,該屬性就不應該設置為true optional:可選,指定Bean是否是一個可選Bean
-
default.properties 默認屬性信息
##字符集 struts.i18n.encoding=UTF-8 struts.objectFactory.spring.autoWire = name struts.objectFactory.spring.useClassCache = true struts.objectFactory.spring.autoWire.alwaysRespect = false struts.multipart.parser=jakartastruts.multipart.saveDir=struts.multipart.maxSize=2097152 ##請求后綴 struts.action.extension=action,, struts.serve.static=true struts.serve.static.browserCache=true struts.enable.DynamicMethodInvocation = false struts.enable.SlashesInActionNames = false struts.mapper.action.prefix.enabled = false struts.mapper.action.prefix.crossNamespaces = false struts.tag.altSyntax=true ##開發模式 struts.devMode = false struts.i18n.reload=false struts.ui.theme=xhtmlstruts.ui.templateDir=template struts.ui.theme.expansion.token=~~~struts.ui.templateSuffix=ftl struts.configuration.xml.reload=false struts.velocity.configfile = velocity.properties struts.velocity.contexts = struts.velocity.toolboxlocation= struts.url.http.port = 80struts.url.https.port = 443 struts.url.includeParams = none struts.dispatcher.parametersWorkaround = false struts.freemarker.templatesCache=false struts.freemarker.beanwrapperCache=false struts.freemarker.wrapper.altMap=true struts.freemarker.mru.max.strong.size=0 struts.xslt.nocache=false struts.mapper.alwaysSelectFullNamespace=false struts.ognl.allowStaticMethodAccess=false struts.el.throwExceptionOnFailure=false struts.ognl.logMissingProperties=false struts.ognl.enableExpressionCache=true struts.handle.exception=true
-
Struts.xml 配置信息
<struts>
<!--重置屬性—>
<constant name="struts.devMode" value="true"> </constant>
<constant name="struts.i18n.encoding" value="urf-8"></constant>
<!--定義包—>
<package name="default" namespace="/" extend="struts-default">
<!--動作—>
<action name="" class="">
<result name="" class="" ></result>
</action>
</package>
</struts>
Constant 常量 Package 包 解決Action重名,方便繼承 -name 包名 -extends 父包名 -namespace 命名空間 Action -name 動作名 -class 實現類 global-results 全局結果 Result 局部結果
第四節、Action 高級
-
method 屬性
<action name="admin" class="net.nw.action.AdminAction" method="add">
<result>result.jsp</result>
</action>
-
DMI動態方法調用
<action name="admin" class="net.nw.action.AdminAction">
<result>result.jsp</result>
</action>
<a href="<%=path%>/admin/admin!add.action">添加</a>
-
Forword Action(頁面跳轉)
-
默認Action
<default-action-ref name="error"></default-action-ref>
<action name="error">
<result>error.jsp</result>
</action>
-
通配符映射
<action name="Student*" class="net.nw.struts2.action.StudentAction" method="{1}">
<result>/Student{1}_success.jsp</result>
</action>
{0} 表示匹配所有內容
{1} 表示前面的第一個*的內容
* 0-N不包括 "/"
** 0-N包括 "/"
\ 轉義符
-
Zero Configuration (Annotation配置)
引入struts2-convention-plugin-2.2.1.jar包
//web.xml
<filter>
……
<init-param>
<param-name>actionPackages</param-name>
<param-value>net.nw.action</param-value>
</init-param>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
//注解
@parentPackage(value="struts-default")
@Namespace(value="/")
@Result(name="login_success",location="/login_success.jsp")
@Results({
@Result(name="login_success",location="/login_success.jsp","type="redirect"),
@Result(name="login_failure",location="/login_failure.jsp","type="redirect")
})
-
包含模塊
<include file="admin.xml">
-
出錯頁面
<action name="**">
<result>error.jsp</result>
</action>
第五節、訪問Web元素以及Result類型
-
Action訪問web對象四種方式:
1.創建request,session,application Map對象
Map request = (Map)ActionContext.getContext().get("request");
Map session = ActionContext.getContext().getsession();
Map application = ActionContext.getContext().getApplication();
2.實現RequestAware,SessionAware,ApplicationAware接口 Map對象(常用)
3.創建傳統的HttpServletRequest、HttpSession、ServletContext對象
HttpServletReques request = ServletActionContext.getRequest(); HttpSession session = request.getSession(); ServletContext application = session.getServletContext();
4.實現ServletRequestAware、ServletContextAware接口
-
Result類型
Dispatcher:轉發到URL,通常是JSP(服務器) Redirect:重定向到URL,通常是JSP(客戶端) Chain:轉發到一個Action(服務器) redirectAction:重定向到一個Action(客戶端) freemarker:處理FreeMarker模型 Httpheader:控制特殊HTTP行為的結果類型 Stream:向瀏覽器發送InputSream對象,通常用來處理文件下載,還可用於返回AJAX數據 Velocity:處理Velocity模版 Xslt:處理XML/XLST模版 plainText:顯示原始文件內容,例如文件源代碼
第六節、Validation框架和i18n
-
Exception異常處理
<global-results>
<result name = "error" > /error.jsp</result>
</global-results>
<global-exception-mappings>
<exception-mapping result="error" exception="java.lang.Exception"></exception>
</global-exception-mappings>
-
Validation框架
分為validate() / XML / Annotation 三種方式
重寫validate() 方法,驗證action中所有的方法。
@Override
public void validate(){
if(! false){
this.addFieldError("validate_error","驗證錯誤!");
}
super.validate();
}
編寫ActionName-validation.xml,驗證action中所有的方法。
//Login-validation.xml
<!DOCTYPE validators PUBLIC "-//Apache Struts//XWork Validator 1.0.3//EN"
"http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">
<validators>
<field name="username">
<field-validator type="requiredstring">
<message>用戶名不能為空</message>
</field-validator>
<field-validator type="email">
<message>用戶名必須為郵箱格式</message>
</field-validator>
</field>
<field name="password">
<field-validator type="requiredstring">
<message>密碼不能為空</message>
</field-validator>
<field-validator type="stringlength">
<param name="minLength">6</param>
<param name="maxLength">20</param>
<message>密碼長度必須在 ${min} ~ ${max}之間</message>
</field-validator>
</field>
</validators>
validateMethodName(), 驗證指定方法
//User.java
public void validateLogin(){
if(! false){
this.addFieldError("validate_error","驗證錯誤!");
}
}
Struts.xml配置, 驗證指定方法
//User.java
@Override
public void validate(){
if(! false){
this.addFieldError("validate_error","驗證錯誤!");
}
super.validate();
}
//Struts.xml
<action>
<interceptor name="defaultStack">
<param name="validation.includeMethods">add</param>
</interceptor>
</action>
Annotation注解
@Action(interceptorRefs=@InterceptorRef(value="defaultStack",params={"validation.includeMethod},"add"))
@SkipValidation (推薦)
出錯信息 <s:filederror cssStyle="color:red" />
-
i18n
i18n:Internationalization 國際化
L10n:localization 本地化
創建資源文件(包名_語言_國家.properties) App_en_US.properties App_zn_CN.properties
Struts.xml加載屬性文件
<constant name="struts.custom.i18n.resources" value="APP"></constant>
//.html
<a href="<%=path%>"/language.action?request_local=en_US">英文</a>
<s.property value="getText('label.username)" />
//Validation.xml
<message>
${getText("login.field.isnull",{getText("label.username")})}
</message>
第七節、OGNL(一)
-
OGNL簡介
OGNL 是 Object-Graph Navigation Language 的縮寫,它是一種功能強大的表達式語言(Expression Language,簡稱EL),通過它簡單一致的表達式語法,可以存儲對象的任意屬性,調用對象的方法,遍歷整個對象的結構圖,實現字段類型轉化等功能。它使用相同的表達式去存取對象的屬性。
-
對象導航圖
-
方法調用
普通方法
//java
public String method(){
return "aaaaa";
}
//jsp
<s:property value="obj.method()" />
Action普通方法
//jsp <s:property value="method()" />
靜態方法
//struts.xml <constant name="struts.ognl.allowStaticMethodAcces" value="true"></constant> //jsp <s:property value="@package.ActionName@method()" />
靜態屬性(注意,必須是public)
//java public static Int num = 123; //jsp <s:property value="@package.ActionName@num" />
構造方法
<s:property value="new package.construct() " />
系統Math方法
<s:property value="@@random() " />
系統其他類方法
<s:property value="@java.util.Calendar@getInstance() " />
-
集合對象
List(有序,可重復)
Set(無序,不可重復)
Map(鍵值對)
獲取集合長度 list.size();
//java
private List<String> aaa = new ArrayList<String>();
private Set<String> bbb = new HashSet<String>();
private Map<Interget,String> ccc= new HashMap<interger String>();
public construct()
{
aaa.add("aaaaaa");
bbb.add("bbbbbb");
ccc.put("1","ccc");
}
//jsp
<s:property value="aaa" /> <!---List 集合 ->
<s:property value="aaa[0]" /> <!---List 集合對象 ->
<s:property value="aaa.{attr}" /> <!---List 集合屬性 ->
<s:property value="aaa.{attr}.[0]" /> <!---List 集合屬性 ->
<s:property value="bbb" /> <!---Set 集合 ->
<s:property value="bbb[0]" /> <!---Set 集合對象 ->
<s:property value="ccc" /> <!---Map 集合 ->
<s:property value="ccc[1]" /> <!---Map 集合對象 ->
<s:property value="ccc.keys" /> <!---Map 集合中key對象 ->
<s:property value="ccc.values" /> <!---Map 集合中values對象 ->
<s:property value="ccc.size()" /> <!---Map 集合中的長度 ->
第八節、OGNL(二)
-
投影和選擇
#this 當前
? 所有
^ 第一個
$ 最后一個
//java
private List<Students> stus = new ArrayList<Students>();
public construct()
{
stus.add(new Students("張三",18));
stus.add(new Students("李四",28));
stus.add(new Students("王五",38));
}
//jsp
<s:property value="stus.{?#this.age>=30}.{name}" />
<s:property value="stus.{^#this.age>=30}.{name}" />
<s:property value="stus.{$#this.age>=30}.{name}" />
-
#符號的使用
訪問根對象
Struts2 中值棧為根對象,如ODNL上下文和Action上下文,#相當於ActionContext.getContext();
下面是幾個ActionContext中有用的屬性:
#parameters URL地址參數
#request 請求參數
#session SESSION參數
#application
#attr 用於按request > session > application 順序訪問其屬性(attribute)
用於選擇和投影
構造Map
#{'foo1':'bar1','foo2':'bar2'}
-
$符號的使用
用於在國際化資源文件中,引用OGNL表達式
在Struts 2 配置文件中,引用OGNL表達式(不推薦)
-
值棧
Struts2 為每一次請求生成一個值棧,不同的請求對應不同的值棧
Struts2 接收到一個action請求,首先創建Action類的實例對象,把該對象壓進值棧。此時action中的所有屬性都是默認值。然后執行定義該action上的所有攔截器,最后執行action動作。
Action構造方法->攔截器->動作方法
注意:攔截器可以改變屬性的值,當改變某個屬性值后,Action類的相應屬性值就會變成在攔截器中最后改變該屬性的這個值。
兩個action之間采用的是服務器跳轉,如果兩個action有名字相同的屬性,則對后一個屬性的修改是否會覆蓋前一個action的屬性。分以下兩種情況:
如果具體相同名字的屬性是引用類型,則會覆蓋。
如果具體相同名字的屬性是基本類型,則不會覆蓋。
將對象壓入值棧
ActionContext.getContext().getValueStack().push(obj);
訪問值棧中的對象
[0].attr //從值棧第一個對象開始尋找 [1].method() //從值棧第二個對象開始尋找 <s:property value="[0]" /> <s:property value="[1]" /> <s:property value="[2]" />
第九節、Interceptor攔截器
-
攔截器原理
攔截器(Interceptor) 是Struts2框架的核心,Struts2中包括解析請求參數、將請求參數賦值給Action屬性、執行數據校驗、文件上傳等工作都是通過攔截器實現的,Struts2設計的靈巧性,更大程度地得益於攔截器設計,當需要擴展Struts2功能時,只需要提供對應攔截器,並將它配置在Struts2容器中即可;如果不需要該功能時,也只需要取消該攔截器的配置即可。
Struts2 內建了大量的攔截器,這些攔截器以name-class對的形式配置在struts-default.xml文件中,其中name是攔截器的名字,就是以后使用該攔截器的唯一標識;class則指定了該攔截器的實現類,如果我們定義的package繼承了Struts2的默認struts-default包,則可以自由使用下面定義的攔截器,否則必須自己定義這些攔截器。
-
常見的內置攔截器
chain:服務器內部跳轉
execAndWait:等待執行攔截器
fileUpload:文件上傳攔截器
timer:統計動作執行時間
token:表單令牌
token-session:表單令牌會話
-
攔截器與過濾器的區別
攔截器攔截的是動作(action),過濾器過濾的是請求(request),過濾器一般映射為 /* ,過濾所有請求。
攔截器是基於java反射機制的,而過濾器是基於函數回調的。
過濾器依賴於servlet容器,而攔截器不依賴於servlet容器。
攔截器可以訪問Action上下文、值棧里的對象,而過濾器不能。
在Action的生命周期中,攔截器可以多次調用,而過濾器只能在容器初始化時被調用一次。
自定義攔截器
實現Interceptor接口(不推薦)
繼承AbstractInterceptor抽象類,對所有方法進行攔截
//java
class demoInterceptor extents AbstractInterceptor{
@Override
public String intercept(ActionInvocation invocation) throws Exception{
//攔截之前
String result = invocation.invokde();
//攔截之后
return result;
}
}
//struts.xml
<package name="default" namespace="/" extends="struts-default">
<interoeptors>
<interceptor name="demoInterceptor" class="package.demoInterceptor" />
<intorceptor-stack name="mydefaultStack">
<interceptor-rel name="demoInterceptor" ></interceptor-rel>
<interceptor-rel name="defaultStack" ></interceptor-rel>
</intorceptor-stack>
</interoeptors>
</package>
<package name="user" namespace="/user" extends="default">
<action name="login" class="package.UserAction">
<interceptor-rel name="mydefaultStack" ></interceptor-rel>
</action>
</package>
MethodFilterInterceptor,對指定方法進行攔截
//java
class demoInterceptor extents MethodFilterInterceptor{
@Override
public String doIntercept(ActionInvocation invocation) throws Exception{
//攔截之前
String result = invocation.invokde();
//攔截之后
return result;
}
}
//struts.xml
<package name="default" namespace="/" extends="struts-default">
<interoeptors>
<interceptor name="demoInterceptor" class="package.demoInterceptor" />
<intorceptor-stack name="mydefaultStack">
<interceptor-rel name="demoInterceptor" >
<param name="excludeMethods">excludeFun</param>
</interceptor-rel>
<interceptor-rel name="defaultStack" ></interceptor-rel>
</intorceptor-stack>
</interoeptors>
</package>
<!--另一種方式-->
<package name="user" namespace="/user" extends="default">
<action name="login" class="package.UserAction">
<interceptor-rel name="mydefaultStack" >
<param name="demoInterceptor.excludeMethods">excludeFun</param>
<param name="demoInterceptor.includeMethods">includeFun</param>
</interceptor-rel>
</action>
</package>
PreResultListener 監聽器 在返回結果集之前執行的方法
//java
class BeforeResultInterceptor extents PreResultListener{
public void beforeResult(ActionInvocation invocation,String str){
//返回結果集之前執行
}
}
class demoInterceptor extents MethodFilterInterceptor{
@Override
public String doIntercept(ActionInvocation invocation) throws Exception{
invocation.addPreResultListener(new BeforeResultInterceptor());
//攔截之前
String result = invocation.invokde();
//攔截之后
return result;
}
}
使用攔截器解決表單重復提交
//struts.xml
<interceptor-ref name="token">
<!-- 顯示重復提交出錯頁面-->
</interceptor-ref>
<interceptor-ref name="tokenSession">
<!-- 顯示重復提交成功頁面,但不執行重復提交動作-->
</interceptor-ref>
<result name="invalid.token">/tokenerror.jsp</result>
//jsp
<s:token></s:token>
第十節、UI表單標簽
