[TOC]
struts2
概念:Struts2是一個基于MVC設(shè)計(jì)模式的Web應(yīng)用框架,它本質(zhì)上相當(dāng)于一個servlet矫膨,在MVC設(shè)計(jì)模式中,Struts2作為控制器(Controller)來建立模型與視圖的數(shù)據(jù)交互期奔。
1侧馅、開發(fā)環(huán)境搭建
1、拷j(luò)ar包呐萌, 在apps包下馁痴,blank>WEB-INF>lib
2、拷配置文件肺孤, 在apps包下罗晕,blank>WEB-INF>src>java>struts.xml
3济欢、拷過濾器配置, 在apps包下小渊, blank>WEB-INF>web.xml
4法褥、將自己新建的action類配置到struts.xml中
public String execute(){
return "tohello";
}
<package name="default" namespace="/" extends="struts-default">
<!-- package的namespace與action的name組成 瀏覽器訪問路徑 class是自己新建action的全類名 -->
<action name="hello" class="com.hemi.action.ActionTest">
<!-- name自己新建action類return的字符串 /hello.jsp跳轉(zhuǎn)的目標(biāo)jsp -->
<result name="tohello">/hello.jsp</result>
</action>
</package>
2、struts2 核心類:StrutsPrepareAndExecuteFilter
3酬屉、struts2 執(zhí)行順序
4半等、配置文件
-
constant 標(biāo)簽:
- name="struts.devMode" value="true" 設(shè)置配置文件更改不會自動重新加載
- name="struts.i18n.encoding" value="UTF-8" 設(shè)置框架的編碼格式,默認(rèn)UTF-8
- name="struts.action.extension" value="do,," 設(shè)置頁面訪問時后綴名 默認(rèn)action,, ,,表示加或者不加后綴都能訪問
-
package 標(biāo)簽:
- name:用來區(qū)分不同的action
- extends:必須默認(rèn)繼承 struts-default
-
action 標(biāo)簽: 配置action處理類路徑 和映射路徑
- method:指明要調(diào)用action中的哪個方法梆惯,不寫默認(rèn)執(zhí)行execute方法
-
result 標(biāo)簽: 配置結(jié)果頁面
- name:邏輯視圖名酱鸭,是action類返回的邏輯視圖名
- 文本內(nèi)容:物理視圖名(jsp文件)
include 標(biāo)簽:用來引入其他配置文件,適合團(tuán)隊(duì)分模塊開發(fā)
5垛吗、action編寫方式
1凹髓、自定義類,編寫execute方法
2怯屉、實(shí)現(xiàn)Action接口
3蔚舀、繼承ActionSupport類
6、action方法訪問方式
1锨络、傳統(tǒng)訪問赌躺,通過method屬性指明
2、通配符訪問 *
<!-- {表示第幾個*號是方法名} 根據(jù)*輸入的方法名 并根據(jù)該方法返回的字符串與resultname比對進(jìn)行相應(yīng)的跳轉(zhuǎn)-->
<action name="user_*" class="........." method="{1}">
<result name="ok"></result>
<result name="fail"></result>
</action>
3羡儿、動態(tài)方法調(diào)用 礼患! action名!方法名.后綴 放開動態(tài)調(diào)用的常量是:struts.enable.DynamicMethodInvocation 為true 開啟
7掠归、跳轉(zhuǎn)方式
- result 標(biāo)簽:type 屬性來控制頁面的跳轉(zhuǎn)方式
- jsp頁面跳轉(zhuǎn)(默認(rèn))轉(zhuǎn)發(fā) dispatcher 重定向 redirect
- Action之間跳轉(zhuǎn) : 轉(zhuǎn)發(fā) chain 重定向redirectAction
<!-- 默認(rèn)轉(zhuǎn)發(fā) dispatcher -->
<result name="login">/login.jsp</result>
<result name="register">/register.jsp</result>
<!-- jsp頁面的重定向 -->
<result name="menu" type="redirect">/menu.jsp</result>
<!-- action之間的重定向 -->
<result name="fail" type="redirectAction">user_register</result>
注意不同papackage標(biāo)簽的Action之間的跳轉(zhuǎn) 需要注入
通過兩個param標(biāo)簽(放在result標(biāo)簽內(nèi)) 注入 name="actionName" 和 name="nameSpace"
<result name="success" type="redirectAction">
<!-- 另一個package中action的name -->
<param name="actionName">hello</param>
<!-- 另一個package的namespace -->
<param name="nameSpace">/</param>
</result>
8缅叠、動態(tài)結(jié)果頁面配置
1、在action類中定義一個字符串變量虏冻,并提供get方法 在每個方法內(nèi)設(shè)置該字符串來決定物理視圖名肤粱,指定要跳轉(zhuǎn)的目標(biāo)頁面
public class MyAction {
private String view;
public String getView() {
return view;
}
public void setView(String view) {
this.view = view;
}
public String test1(){
setView("test1.jsp");
return "ok";
}
public String test2(){
setView("test2.jsp");
return "ok";
}
public String test3(){
setView("test3.jsp");
return "ok";
}
}
2、在result 的文本配置成獲取物理視圖屬性 通過${action中的字符串變量名}
<action name="test_*" class="com.hemi.action.MyAction" method="{1}">
<result name="ok">/${view}</result>
</action>
9厨相、Servlet API的操作领曼,也就是獲取參數(shù)
1、耦合方式 ServletActionContext.getRequest()
//耦合方式
HttpServletRequest req = ServletActionContext.getRequest();
String username = req.getParameter("username");
String password = req.getParameter("password");
System.out.println(username);
System.out.println(password);
if ("admin".equals(username) && "123".equals(password)) {
req.setAttribute("username", username);
req.setAttribute("password", password);
setView("success.jsp");
return "ok";
}
setView("login.jsp");
return "fail";
2蛮穿、解耦方式 ActionContext.getContext()
//解耦方式
ActionContext context = ActionContext.getContext();
Map<String, Object> map = context.getParameters();
String[] username = (String[]) map.get("username");
setView("test3.jsp");
return "ok";
3庶骄、ioc注入 實(shí)現(xiàn)ServletRequestAware接口在類里聲明HttpServletRequest
并重寫setServletRequest方法 在里面寫this.request=req;(給類中的全局變量賦值)
public class MyAction implements ServletRequestAware {
private String view;
private HttpServletRequest request;
//ioc注入
public String test2() {
String username = request.getParameter("username");
String password = request.getParameter("password");
System.out.println(username);
System.out.println(password);
if ("admin".equals(username) && "123".equals(password)) {
request.setAttribute("username", username);
request.setAttribute("password", password);
setView("success.jsp");
return "ok";
}
setView("login.jsp");
return "fail";
}
@Override
public void setServletRequest(HttpServletRequest req) {
this.request=req;
}
}
10、數(shù)據(jù)校驗(yàn)
1践磅、首先繼承ActionSupport
2瓢姻、校驗(yàn)全部方法 重寫 validate方法
3、校驗(yàn)指定方法 自定義方法 validate+校驗(yàn)的方法名(注意:方法首字母大寫)
4音诈、添加校驗(yàn)錯誤信息 addFieldError
//System.out.println("校驗(yàn)test1方法");
String username = request.getParameter("username");
if (username.length()==0) {
addFieldError("username", "用戶名不能為空");
}
5幻碱、配置文件中加一個result name為input
<result name="input" type="redirect">/login.jsp</result>
11、配置結(jié)果頁面
- 局部結(jié)果頁面
<action name="user" class="com.hemi.action.UserAction" >
<result "ok">/login.jsp</result>
</action>
- 全局結(jié)果頁面 同package標(biāo)簽內(nèi)所有action都可以訪問
- 使用global-results標(biāo)簽 注意:
- 放在package標(biāo)簽內(nèi)
- 一定要放在所有Action配置之前
- 作用范圍只有同package標(biāo)簽內(nèi)的action
- 使用global-results標(biāo)簽 注意:
<global-results>
<result name="error">/error.jsp</result>
</global-results>
12细溅、異常處理
- 局部異常處理 通過exception-mapping 在action標(biāo)簽下來捕獲異常
- result屬性: 表示要跳轉(zhuǎn)的邏輯視圖名就是下面result標(biāo)簽的name
- exception屬性:指明要捕獲的異常類型
<action name="hello" class="com.hemi.action.ActionTest">
<exception-mapping result="error" exception="java.lang.Exception"></exception-mapping>
<result name="error">/error.jsp</result>
</action>
- 全局異常處理 通過global-exception-mappings 寫在全局結(jié)果頁面下
- 子標(biāo)簽exception-mapping result屬性:表示要跳轉(zhuǎn)的邏輯視圖名
- exception屬性:指明要捕獲的異常類型
<!-- 全局結(jié)果頁面 -->
<global-results>
<result name="er">/error.jsp</result>
</global-results>
<!-- 全局異常處理 如果是hello這個action報(bào)異常 先在自己內(nèi)部結(jié)果頁面找有沒有er 沒有再找全局結(jié)果頁面有沒有er-->
<global-exception-mappings>
<exception-mapping result="er" exception="java.lang.Exception"></exception-mapping>
</global-exception-mappings>
<action name="hello" class="com.hemi.action.ActionTest">
<result name="er">/common.jsp</result>
</action>
13褥傍、參數(shù)封裝
- 屬性封裝
-在Action中定義與表單中name值相同的全局變量,并提供set方法喇聊,會自動幫我們把表單中的數(shù)據(jù)封裝到對應(yīng)變量中
private String name;
private int age;
private String sex;
public void setAge(int age) {
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setSex(String sex) {
this.sex = sex;
}
@Override
public String execute() throws Exception {
System.out.println(name + "---------" + age + "--------" + sex);
return NONE;
}
- 對象封裝(表達(dá)式封裝)
- 新建一個實(shí)體類
- 在Action中 定義一個全局的對象變量 提供get set方法恍风,表單中的name屬性值為:對象.屬性名
private User user;
public void setUser(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String execute() throws Exception {
System.out.println(user);
return NONE;
}
<form action="" method="post">
<input type="text" name="user.name">
<input type="text" name="user.sex">
<input type="text" name="user.age">
</form>
- 模型驅(qū)動封裝
-定義一個全局對象變量并實(shí)例化 實(shí)現(xiàn)一個ModelDriven<T>接口,并重寫其中的抽象方法getModel() 將全局對象變量 return出去
public class UserAction implements ModelDriven<User>{
private User user =new User();
@Override
public String execute() throws Exception {
System.out.println(user);
return NONE;
}
@Override
public User getModel() {
return user;
}
}
注:封裝集合 表單中用list[0(index)].屬性
14誓篱、如何傳遞數(shù)據(jù)到前臺界面
通過request域?qū)ο蟮膕etAttribute方法設(shè)置
值棧來存朋贬,通過ognl表達(dá)式來取 servlet和action區(qū)別? servlet是單實(shí)例 action是多實(shí)例
- 值棧的位置窜骄,位于每個action中且 一次action運(yùn)行保證唯一 同一個action 兩次運(yùn)行 值棧不同锦募。
- 值棧結(jié)構(gòu)
- CompountRoot: root值棧 底層是list集合
- OgnlContext:map棧 底層map結(jié)構(gòu)
- 如何向root值棧中存值
1...使用set方法 會向root棧中壓入一個map集合對象 然后把值存入map集合中
//通過set方法
stack.set("name", "tom");
2...使用push方法 直接值對象的引用壓入root棧中
//通過push方法
stack.push("adsfadfafa");
3...使用屬性的get方法 不會壓入新對象引用 直接存放在當(dāng)前action引用的下面 (實(shí)際開發(fā)中經(jīng)常使用)
private String msg;
public String getMsg() {
return msg;
}
private User user;
public User getUser() {
return user;
}
private List<User> list;
public List<User> getList() {
return list;
}
@Override
public String execute() throws Exception {
ActionContext context = ActionContext.getContext();
ValueStack stack = context.getValueStack();
//通過get方法 定義一個全局變量 并提供get方法 然后在這里賦值
msg="dfaaadfaf";
//通過get方法 存對象
user=new User(1,"da","man");
//通過get方法 存集合
list=new ArrayList<User>();
list.add(new User(2, "jack", "man"));
list.add(new User(3, "marry", "woman"));
return "ok";
}
頁面中查看 值棧的方法:在jsp頁面中導(dǎo)入標(biāo)簽庫<%@ taglib prefix="s" uri="/struts-tags" %>
并寫 <s:debug></s:debug>
<s:debug></s:debug>
- 取出root值棧中的數(shù)據(jù) 通過struts2標(biāo)簽庫加OGNL表達(dá)式來取
取出get方法存入的值
<!-- 取屬性:直接取 -->
<s:property value="msg"/>
<!-- 取對象:通過.屬性來取 -->
<s:property value="user.name"/>
<s:property value="user.sex"/>
<!-- 取集合 -->
<!-- 方式一list[0].屬性名 -->
<s:property value="list[0].name"/>
<s:property value="list[0].sex"/>
<!-- 方式二 -->
<s:iterator value="list">
<s:property value="name"/>
<s:property value="sex"/>
</s:iterator>
<!-- 方式三 效率比方式二高-->
<s:iterator value="list" var="user1">
<!-- 使用var 會把root棧中的值拷貝一份到map棧 取值需要特殊符號# -->
<s:property value="#user1.name"/>
<s:property value="#user1.sex"/>
</s:iterator>
通過jstl和el表達(dá)式來取
<c:forEach items="${list}" var="uu" >
${uu.name}<br>
${uu.sex}
</c:forEach>
問題: 為什么能取出來?
因?yàn)橹禇J菍τ驅(qū)ο蟮脑鰪?qiáng)邻遏,內(nèi)部會從值棧中取出數(shù)據(jù)放到域?qū)ο笾?/p>
取出set方法存入的值
<!-- 取屬性:通過set存入時的key來取 -->
<s:property value="msg"/>
<!-- 取對象:通過set存入時的key.屬性名來取 -->
<s:property value="user.name"/>
<s:property value="user.sex"/>
<!-- 取集合:與get一樣-->
取出push方法存入的值
<s:property value="[0].top"/>
15糠亩、OGNL表達(dá)式的使用 (對象導(dǎo)航語言)
獲取域?qū)ο罄锏闹?/h4>
- 通過#號+域?qū)ο笤趍ap棧中的引用.域?qū)ο笾械膋ey值
//向request域?qū)ο笾写嬷?ServletActionContext.getRequest().setAttribute("uid", "我是request域?qū)ο?);
//向application域?qū)ο笾腥≈?ServletActionContext.getServletContext().setAttribute("ap","我是application域?qū)ο?)
<!-- 向request域?qū)ο笾腥≈?-->
<s:property value="#request.uid"/><br>
<!-- 向application域?qū)ο笾腥≈?-->
<s:property value="#application.ap"/><br>
標(biāo)識ognl表達(dá)式
<!-- 加上%才能識別 ognl表達(dá)式 不然只是輸出#application.ap字符串 -->
<s:textfield value="%{#application.ap}"/>
$
主要用于國際化驗(yàn)證的配置文件中取數(shù)據(jù)(例如:動態(tài)結(jié)果頁面)
投影過濾 {}
<!-- 取出list里的所有name -->
<s:property value="list.{name}"/>
16、struts2 攔截器
//向request域?qū)ο笾写嬷?ServletActionContext.getRequest().setAttribute("uid", "我是request域?qū)ο?);
//向application域?qū)ο笾腥≈?ServletActionContext.getServletContext().setAttribute("ap","我是application域?qū)ο?)
<!-- 向request域?qū)ο笾腥≈?-->
<s:property value="#request.uid"/><br>
<!-- 向application域?qū)ο笾腥≈?-->
<s:property value="#application.ap"/><br>
<!-- 加上%才能識別 ognl表達(dá)式 不然只是輸出#application.ap字符串 -->
<s:textfield value="%{#application.ap}"/>
$
主要用于國際化驗(yàn)證的配置文件中取數(shù)據(jù)(例如:動態(tài)結(jié)果頁面)<!-- 取出list里的所有name -->
<s:property value="list.{name}"/>
攔截器與過濾器區(qū)別:准验、過濾器理論上攔截一切資源 赎线、攔截器(struts2中)只能攔截方法
1、自定義類 實(shí)現(xiàn)Interceptor接口
2糊饱、自定義類 繼承AbstractInterceptor
3垂寥、自定義類 繼承MethidFilterInterceptr 能攔截到具體方法 推薦
配置使用:
(局部攔截器)
1、聲明攔截器
<interceptors>
<interceptor name="myInter" class="自定義攔截器類全類名" />
</interceptors>
2另锋、在action標(biāo)簽中使用攔截器
<action>
<interception-ref name="myInter" />
</action>
3滞项、如何放行action中指定方法[只有繼承MethidFilterInterceptr的攔截器才能忽略指定方法(放行指定方法)]
<action>
<interception-ref name="myInter" >
<param name="excludeMethods">忽略的方法名1,忽略的方法名2.....</interception-ref>
</interception-ref>
</action>
(全局?jǐn)r截器)
1、聲明自定義攔截器
2砰蠢、定義攔截器棧
3蓖扑、引入自定義攔截器和 系統(tǒng)默認(rèn)攔截器棧![注意:必須引入 否則系統(tǒng)自帶的攔截器都不能使用]
4台舱、引入自定義攔截器棧
<interceptors>
<!-- 聲明自定義攔截器 -->
<interceptor name="myInter" class="com.hemi.interception.MyInterception"></interceptor>
<!-- 定義攔截器棧 -->
<interceptor-stack name="myStack">
<!-- 引入自定義攔截器 -->
<interceptor-ref name="myInter">
<!-- 使該攔截器忽略指定方法 -->
<param name="excludeMethods">test1</param>
</interceptor-ref>
<!-- 引入系統(tǒng)默認(rèn)的攔截器棧 -->
<interceptor-ref name="defaultStack"></interceptor-ref>
</interceptor-stack>
</interceptors>
<!-- 全局引入攔截器棧 -->
<default-interceptor-ref name="myStack"></default-interceptor-ref>
額外知識:當(dāng)編寫action時律杠,沒有指明class 默認(rèn)使用ActionSupport類 result必須是success
<!-- 訪問hello就會到hello.jsp頁面 執(zhí)行的是ActionSupport類里的excute方法 -->
<action name="hello">
<result name="success">/hello.jsp</result>
</action>
額外知識:配置默認(rèn)處理action 啟動服務(wù)器沒輸入地址或者輸入的地址不存在 會默認(rèn)調(diào)用這個action
<default-action-ref name="hello"></default-action-ref>
<action name="hello">
<result name="success">/hello.jsp</result>
</action>
17、struts2 常用標(biāo)簽的使用
1竞惋、UI標(biāo)簽
(1)表單標(biāo)簽 form
<s:form action="" method="">
<s:textfield name="username" label="user"/> <!-- 等同 user:<input type="text" name="username">-->
<s:textfield name="pwd" label="password"/> <!-- 等同 password:<input type="password" name="pwd">-->
<s:radio list="#{'0':'woman','1':'man'}" name="sex" label="gender"/>
<!-- 等同 gender:<input type="radio" value="0" name="sex">woman
<input type="radio" value="1" name="sex">man-->
<s:submit value="提交"/>
</s:form>
(2)非表單標(biāo)簽
2柜去、通用標(biāo)簽 if elseif else iterator debug property
(1)if標(biāo)簽
<s:if test="%{條件}">
</s:if>
(2)iterator 迭代標(biāo)簽 等等、拆宛、嗓奢、、浑厚、
18股耽、文件的上傳
- 編寫前端頁面根盒,上傳數(shù)據(jù)的表單
<form action="upload" method="post" enctype="multipart/form-data">
請上傳文件:<input type="file" name="temp"> <!-- 此處name為action類中 File定義的變量名 -->
<br>
<input type="submit" value="upload">
</form>
- 編寫action 定義三個全局變量 提供get方法 set也可以加上
- File src 上傳文件的臨時目錄
- String srcFileName 文件名
- String srcContentType 文件類型
private File temp;
private String tempFileName;
private String tempContentType;
public File getTemp() {
return temp;
}
public void setTemp(File temp) {
this.temp = temp;
}
public String getTempFileName() {
return tempFileName;
}
public void setTempFileName(String tempFileName) {
this.tempFileName = tempFileName;
}
public String getTempContentType() {
return tempContentType;
}
public void setTempContentType(String tempContentType) {
this.tempContentType = tempContentType;
}
- 在Action方法內(nèi)寫、物蝙、
//獲取路徑
String path =ServletActionContext.getServletContext().getRealPath("/");
File destFile=new File(path,tempFileName);
FileUtils.copyFile(temp, destFile);
return "ok";
上傳文件到自己指定路徑時
1炎滞、在web.xml中配置 絕對路徑
<context-param>
<param-name>path</param-name>
<param-value>D:\Tomcat\webapps\images</param-value>
</context-param>
2、獲取路徑通過getInetParameter
String path = ServletActionContext.getServletContext().getInitParameter("path");
File destFile=new File(path,tempFileName);
FileUtils.copyFile(temp, destFile);
return "ok";
19诬乞、日期轉(zhuǎn)換器
a册赛、自定義類繼承數(shù)據(jù)轉(zhuǎn)換類 StrutsTypeConverter
b、重寫抽象方法
c震嫉、在src下 新建并編寫配置文件 xwork-conversion.properties