(一)
webWork
Framework:基於請求響應(Request-Response)模式的應用。
表現邏輯結構:
1 控制器(Controll)-控制整個Framework中各個組件的協調工作。
2 業務邏輯層(Business Logic)-概念與幾個能夠提供服務的基礎組件(真正的實現需要在Framework之上進行再次擴展)。
3 數據邏輯層(Data Logic)-包括數據邏輯與數據訪問接口。
意義:可重用 模塊化設計
靈活性與可配置性
ognl--表達式語言
(二)
開發步驟:詳見-點擊打開鏈接
1 新建工程
2 導入包
3 新建jsp文件
4 配置web.xml文件
5 src下新建struts.xml文件並配置
6 新建action文件(bean)
根據tomcat啓動報錯加入需要需要加入jar包
javassit.jar在struts2.2之後需要加入(jboss除外,已內置)
如下語句獲取request域內容(與request.getAttribute類似):
username:${requestScope.username}<br/>
password:${requestScope.password}
struts基本執行原理(找到匹配信息進行處理-*邏輯)
反射
struts.xml->extends:struts-default(自帶包)繼承
過濾器接管請求
每次請求都會生成一個action對象
(三)
struts2的類型轉換(8種原生數據類型等常見數據類型會使用內建的類型轉換器實現自動轉換,但對於自定義數據則需要手動轉換)
action繼承自ActionSupport(提供了對struts的各種支持)
內置類型轉換:點擊打開鏈接
轉換器轉換(Converter):點擊打開鏈接
類型轉換
1 {類型轉換器converter(繼承於DefaultTypeConverter->內置於ognl)->converterValue方法
StringTokenizer(分割提取字符串)->nextToken(獲取分割後字符串)
return SUCCESS;
轉換處理代碼(hello;word轉換爲兩個字符串):
//使用object泛指
if(User.class==toType){
//轉換(從頁面向後臺對象轉換)
String[] str=(String[])value;//將value轉換爲String數組
String firstValue=str[0];//取出字符串
//對字符串數組進行分割
StringTokenizer st=new StringTokenizer(firstValue,";");//第一個參數爲待轉換的字符串 第二個參數爲分隔符
//獲取分割後字符串
String username=st.nextToken();//取出第一個
String password=st.nextToken();//取出第二個
//生成user對象
User user=new User();
user.setUsername(username);//將轉換後的字符串放入usre對象中
user.setPassword(password);;
return user;
在action包中新建UserAction-conversion.properties配置文件指定轉換器
自定義的類型轉換需要提供3個信息:action的名字、action中待轉換的屬性名以及該和屬性對應的類型轉換器(properties文件 converter文件)action名字通過屬性文件名獲得、action中待轉換的屬性名通過屬性文件中的key;來獲得,該屬性的類型轉換器通過key對應的類型轉換器名字value獲得->properties
}
jsp應用標籤庫:<%@ taglib prefix="s" uri="/struts-tags"%>
2 Struts2自帶的類型轉換(TypeConverter->繼承defaultTypeConverter):
public class UserConverter2 extends StrutsTypeConverter {
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
// TODO Auto-generated method stub
//從頁面向後臺轉換
User user=new User();
String value=values[0];//提取字符串
StringTokenizer st=new StringTokenizer(";");//分割
user.setUsername(st.nextToken());
user.setPassword(st.nextToken());
return user;
}
@Override
public String convertToString(Map context, Object o) {
// TODO Auto-generated method stub
User user=(User)o;
String username=user.getUsername();
String password=user.getPassword();
String userInfo="username:"+username+"-password:"+password;
return userInfo;
}
}
/struts2-1/src/com/sw/struts2/UserAction-conversion.properties(配置文件-指定轉換文件):
#user=com.sw.converter.UserConverter(#爲註釋)
3 批量轉換數據類型(採用集合)->集合轉換
代碼:
(1)從頁面到後臺
@Override
public Object convertFromString(Map context, String[] values, Class toClass) {
// TODO Auto-generated method stub
//批處理
List<User> list=new ArrayList<User>();
for(String value:values){//遍歷
StringTokenizer st=new StringTokenizer(value,";");
User user=new User();
user.setUsername(st.nextToken());
user.setPassword(st.nextToken());//裝載
list.add(user);
}
return list;
}
(2)從後臺到頁面
@Override
public String convertToString(Map context, Object o) {
// TODO Auto-generated method stub
List<User> list=(List<User>)o;//強制轉換
StringBuffer buffer=new StringBuffer();//拼接字符串(集合內所有字符串)
for(User user:list){//遍歷
String username=user.getUsername();
String password=user.getPassword();
//拼接
buffer.append("username:").append(username).append("-passwprd:").append(password);
}
return buffer.toString();
}
4 開發時類型轉換(全局轉換)
xwork-conversion.properties文件:
待轉換的類=轉換器的名字
例如:
com.sw.bean.User=com.sw.converter.UserConverter3
excute類似於doget()與dopost()
自定義execute(除方法名外其他需一致)->不建議重寫->會使代碼混亂
(四)
輸入校驗->(客戶端檢驗、服務器校驗)
1 客戶端驗證
標籤庫:property(指定顯示某個屬性)
(1)validate()->驗證->重寫方法->在execute之前執行
<s:actionerror/>---顯示action錯誤
Calendar->比較時間
錯誤提示:
this.addActionError("username size:4-6!");//放置action級別錯誤信息
this.addFieldError(username, "username size:4-6");//屬性級別的錯誤消息
struts2自帶標籤(少用)
theme->自定義form主題
流程:
(1)首先進行類型轉換(可內部轉換)
(2)輸入校驗(執行validate方法)
(3)如上述過程中出現任何錯誤(類型轉化錯誤、輸入校驗錯誤)都不會再去執行execute方法,頁面轉向struts.xml中該action的名爲input所對應的頁面
this.getFieldErrors().clear();//清空錯誤信息
this.getActionErrors().clear();
a 當調用getAction()方法返回Action級別的錯誤信息列表時,返回的實際上是集合的一個副本而不是集合本身,因此對集合副本調用clear()方法清除的依舊是副本中的元素,而並不是原集合中的元素,此時集合中的內容沒有受到任何的影響。即Action級別的錯誤列表對於開發者來說是隻讀的。
b FiledError級別的錯誤信息底層是用LinkedHashMap實現的,該Map的key是String類型,value是List<String>類型,這就是表示一個Filed Name可以對應多條錯誤信息,這些錯誤信息都放置在List<String>集合當中。
hasActionErrors()->bool類型,檢測是否有錯誤信息
hasFilederrors()->
ActionSupport類的addActionError()方法:
首先創建一個ArrayList對象,然後將ArrayList放到對象中
Action中自定義方法的輸入校驗:對於通過action的method屬性所指定的自定義方法,其對應的自定義輸入檢驗方法名爲validateMyexcute(假設自定義方法名爲MyExecute)->validateMyexecute優於validate
MyExecute優於execute
自定義方法先於execute方法執行。
自定義錯誤提示信息(對應包下action同級目錄):
新建配置文件:Action名字.properties:invalid.fieldvalue.出錯變量=age invalid!
struts校驗框架(有效的xml文件->action同級目錄下)
RegisterAction-validation.xml
可分爲字段優先校驗器與校驗器優先校驗器
(1)字段優先校驗器(包含Filed)
<validators>根元素
.xml文件:
<validators>
<field name="username">
<field-validator type="requiredstring">
<message>UserName cant't be blank!</message>
</field-validator>
</field>
</validators>
中英文錯誤提示信息配置文件(key屬性):
package_en_US.properties->英文
package_zh_CN.properties
i18n->Locale
國際化資源文件命名規則:package_語言名_國家名
例:package_zh_CN
package_en_US
(2)檢驗器優先校驗器
.xml文件:
<!-- 校驗器優先校驗 -->
<validator>
<validator type="requiredstring">
<param name="fieldName">username</param>
<message>UaerName cant't be blank!</message>
</validator>
<validator type="stringlength">
<param name="fieldName">username</param>
<param name="minLength">4</param>
<param name="maxLength">6</param>
<message>UserName Size:${minLength}-${maxLength}</message>
</validator>
<validator>
兩者可共同使用
struts校驗框架執行的順序:
(1)首先執行校驗框架(xml文件)
(2)執行自定義的校驗方法(validateMyExecute)
(3)執行validate方法
任何一個步驟出現錯誤就不會再向下執行
(五)
異常的處理(亦可處理校驗)
處理:struts.xml文件中action下<exception-mapping>
全局的結果集:<global-results></global-results>
全局異常:<global-exception-mappings></global-exception-mappings>
局部總是優先於全局的。
局部:獨有action共享
全局:所有action共享
(六)
業務邏輯處理
(1)創建service(interface)
(2)實現service(impelment)
(3)創建dao(有implement調用dao實現類)-可省略
(4)action中實現service對象
(七)
struts2底層應用的分層體系架構
action->service(interface與impelment)->dao(與數據庫交互)
struts2的模型驅動(Model Driver)->將單個屬性裝爲模型,調用模型,再去尋找單個屬性?
屬性驅動(action裏邊調用單個屬性)
屬性驅動與模型驅動的區別:
(1)屬性驅動靈活,準確;模型驅動不靈活,因爲很多時候,頁面所提交過來的參數並不屬於模型中的屬性,也就是說頁面所提交過來的參數與模型並不一致。
(2)模型驅動更加符合面向對象編程風格,使得我們獲得的是對象而不是一個個離散的值。
小結:儘量使用屬性驅動編寫Action
(八)
服務器端代碼的單元測試有兩種模式:
(1)容器內測試(Jetty)->服務器
(2)Mock測試(模擬測試)->繼承httpServletRequest、HttpSession、HttpServletResponse等servlet API
JMock、easyMock(代理機制->java動態代理)
Preparable(xwork下)接口:
讓Action完成一些初始化工作,這些初始化工作是放在Preparable接口的prepare方法中完成的,該方法會在execute方法執行之前得到調用。
(九)
實際開發:
採取請求轉發的方式完成表單內容的添加會造成內容的重複插入。
重定向:redirect
diapatcher
redirectAction->重定向到某個action
<result name="SUCCESS" type="redirectAction">action2</result>->重定向到action2
重定向並且傳值(開發常用):
<action name="action1" class="com.sw.struts2.Action1">
<result name="SUCCESS" type="redirectAction">
<param name="actionName">action2</param>
<param name="username">${username}</param>
<param name="password">${password}</param>
<param name="usernameAndPassword">${usernameAndPassword}</param>
</result>
</action>
請求轉發:type=chain
防止表單重複提交:
(1)通過重定向(redirect)
(2)通過Session Token(session令牌)->檢驗是否爲第一次提交(與字符串匹配則是重複提交)
Token->struts.xml配置:
<action name="token" class="com.sw.struts2.TokenAction">
<result name="SUCCESS">/tokenSuccess.jsp</result>
<result name="invalid.token">/tokenErr.jsp</result>
<!-- 攔截器 -->
<interceptor-ref name="token"></interceptor-ref>
<interceptor-ref name="defaultStack"></interceptor-ref>
</action>
jsp配置:
<s:form action="token.action" theme="simple">
username:<s:textfield name="username"></s:textfield><br/>
password:<s:password name="password"></s:password><br/>
<s:token></s:token>
<s:submit value="submit"></s:submit>
</s:form>
當客戶端請求頁面時,服務器通過token標籤生成一個隨機數,並且將該隨機數放置到session中,然後改隨機數向客戶端;如果客戶第一次提交,那麼會將該隨機數發往服務器端,服務器會接收到該隨機數並且與session中所保存的的隨機數進行比較,這時兩者的值是相同的,服務器認爲是第一次提交,並且將更新服務器的這個隨機數值;如果此次重複提交,那麼客戶端發向服務器端的隨機數還是之前那個,而服務器端的隨機數已經發生變化,兩者不同,服務器就認爲這是重複提交,進而轉向invalid.token所指向的結果頁面。
(十)
攔截器(interceptor)
1 攔截器是struts2的核心,struts2的衆多功能都是通過攔截器來實現的。
攔截器可攔截action
servlet過濾器?
攔截器必須是無狀態的
步驟:
(1)新建包
(2)新建interceptor類,繼承於interceptor
(3)寫intercept方法
(4)配置struts.xml(定義攔截器):
<!-- 攔截器 -->
<interceptors>
<interceptor name="theinterceptor" class="com.sw.TheInterceptor1">
<param name="test">swxctx</param>
</interceptor>
</interceptors>
與action配置(使用攔截器):
</result>
<interceptor-ref name="theinterceptor1"></interceptor-ref>
</action>
深入分析struts-default.xml ***
自定義攔截器以後,defaultStack將不再有用,需要自己定義
2 定義攔截器時可繼承abstractInterceptor(該類實現了interceptor接口,並且對init和destory方法進行了實現),然後實現其抽象方法interceptor即可。
3 方法過濾攔截器(可以對指定方法進行攔截的攔截器)->MethodFilterInterceptor(abstract class)->可指定
includeMethods->表示需要攔截的方法:
<interceptor-ref name="theinterceptor3"> <param name="includeMethods">execute</param>
</interceptor-ref>
如上表示對execute進行攔截.
<param name="excludeMethods">myExecute</param>
表示不對myExecute攔截(攔截器不執行,並非myExecute不執行)
如果沒有指定includeMethods參數,也沒有指定exincludeMethods參數,那麼所有的方法都會被攔截,也就是說所有的方法都被認爲是includeMethods類型的。
如果僅僅指定includeMethods,那麼只會攔截includeMethods中的方法,其讓他的並不會受到干擾。
(十一)
PreResultlistener(繼承於ActionInvocation)
進行登錄處理
攔截器棧:將多個攔截器定義在一起
struts.xml可放置多個包。
可分爲多個配置子文件。
(十二)
struts.xml
abstract->表示當前包爲抽象的包。
abstract="true";
struts-default的包是abstract的,所以需要繼承。
namespace:
路徑分割、模塊劃分
(十三)
文件上傳
1 採用servlet
遵循原則:
基本form->
<form action="fileUploadResult.jsp" method="post" enctype="multipart/form-data">
username:<input type="text" name="useranme">
file:<input type="file" name="file">
<input type="submit" value="上傳">
</form>
讀取:
<%
InputStream is=request.getInputStream();
BufferedReader br=new BufferedReader(new InputStreamReader(is));
String buffer=null;
//讀取
while(null!=(buffer=br.readLine())){
out.print(buffer+"<br/>");
}
br.close();
is.close();
%>
進行文件上傳是,必須將method屬性設置爲post,enctype屬性必須設置爲multipart/form-data
使用servlet需要使用apache組件,commons->FileUpload
選擇多個文件:
file:<input type="file" name="file" multiple size="80"><br/>
選擇文件上傳界面:
<form action="UploadServlet" method="post" enctype="multipart/form-data">
username:<input type="text" name="useranme"><br/>
file:<input type="file" name="file" multiple size="80"><br/>
file2:<input type="file" name="file2">
<input type="submit" value="上傳">
</form>
使用action處理:
public String execute() throws Exception {
// TODO Auto-generated method stub
//用於文件上傳處理
String root=ServletActionContext.getRequest().getRealPath("/upload");//文件存儲路徑
InputStream is=new FileInputStream(file);//輸入流
File destFile=new File(root,fileFileName);//文件
OutputStream os=new FileOutputStream(destFile);//輸出流
byte[] buffer=new byte[400];
int length=0;
while((length=is.read(buffer))!=-1){
//寫入
os.write(buffer, 0, length);
}
is.close();
os.close();
return "SUCCESS";
}
struts2在進行文件上傳時,實際是通過兩個步驟實現的:
(1)首先將客戶端上傳的文件保存到struts.multipart.saveDir(struts.properties)鍵所指定的目錄中,如果該鍵所對應的目錄不存在,那麼就是保存到javax.servlet.context,tempdir環境變量所指定的目錄中。
(2)Action中所?定義的File類型的成員變量file實際上指向的是臨時目錄中的臨時文件,然後在服務器端通過IO的方式將臨時文件寫入到指定的服務器端目錄中。
上傳多個文件:
file1:<input type="file" name="file"><br/>
file2:<input type="file" name="file"><br/>
name相同。
OGNL(Object Graph Navigation Language):對象圖導航語言
控制上傳大小:
struts.properties:
struts.multipart.maxSize=1048576000
或者struts.xml:
<!-- 指定上傳文件大小 -->
<constant name="struts.multipart.maxSize" value="1048576000"></constant>
優先級:
struts.properties>struts.xml
文件下載:
Action:
public class DownloadAction extends ActionSupport {
//文件下載
public InputStream getDownloadFile(){
return ServletActionContext.getServletContext().getResourceAsStream("/upload/Upload.txt");
}
@Override
public String execute() throws Exception {
// TODO Auto-generated method stub
return "SUCCESS";
}
}
struts.xml配置:
<!-- 10 Download -->
<action name="downloadFile" class="com.sw.struts2.DownloadAction">
<result type="stream">
<param name="contentDisposition">attachment;filename="Upload.txt"</param>
<param name="inputName">downloadFile</param>
</result>
</action>\
解決文件名亂碼問題:
//中文亂碼處理(文件名爲中文) this.filename=new String(this.filename.getBytes("gbk"),"8859_1");
(十四)
註解
stryts2可以使用struts2-convention-plugin-2.3.30.jar插件實現基於註解的配置。
Action頭部:
@ParentPackage("struts-default")
@Action(value="login",result={@Result(name="SUCCESS",location="result.jsp",type="",param="")),@Result...}
@InterceptorRef(value="攔截名字")
@InterceptorRefs({@Interceptor(""),@Interceptor("")})
@ExceptionMapping(exception)
@ExceptionMappings{@ExceptionMapping(),@ExceptionMapping()}
自定義攔截器:可在struts.xml定義,在action引用
(十五)
xml與Json方式解析
ajax異步通信
json->
(1)自定義json字符串
(2)使用插件
(十六)
(1)Action(重要)->exxcute
(2)過濾器(Filter)
(3)ValueStack
(4)ActionProxy(action代理對象)
ActionInvocation
源碼與幫助文檔分析