1. Action開發、通配符、路徑匹配
1) Struts2配置
a) Struts2的Action的幾種開發方式
方式一:繼承ActionSupport
package com.xp.a_config;import com.opensymphony.xwork2.ActionSupport;public class UserAction extends ActionSupport{ PRivate static final long serialVersionUID = 1L; //action中業務處理方法 public String login() { System.out.println("UserAction.login()"); return "success"; }}如果使用struts2數據校驗功能必須繼承ActionSupport
方式二:實現Action接口

public class UserAction2 implements Action{ public String login() { System.out.println("UserAction.login()"); return "success"; } @Override public String execute() throws Exception { return null; }}方式三:不繼承任何類,不實現任何接口public class UserAction3 { private String userName; public void setUserName(String userName) { this.userName = userName; } public String login() { System.out.println("UserAction3.login"+userName); return "success"; }}1) struts2通配符映射機制
A. 一個Web 應用可能有成百上千個 action 聲明. 可以利用 struts 提供的通配符映射機制把多個彼此相似的映射關系簡化為一個映射關系
B. 通配符映射規則
a) 若找到多個匹配, 沒有通配符的那個將勝出
b) 若指定的動作不存在, Struts 將會嘗試把這個 URI 與任何一個包含著通配符* 的動作名及進行匹配
c) 若 Struts 找到的帶有通配符的匹配不止一個,最后一個匹配將勝出
d) 被通配符匹配到的 URI 字符串的子串可以用 {1}, {2} 來引用. {1} 匹配第一個子串, {2} 匹配第二個子串…
e) {0} 匹配整個 URI
l 可以匹配零個或多個字符, 但不包括/ 字符. 如果想把 / 字符包括在內, 需要使用 **. 如果需要對某個字符進行轉義, 需要使用 /.
2) Struts2路徑匹配原則
<struts> <package name="config" namespace="/user" extends="struts-default" abstract="false"> <action name="user_*" class="com.xp.a_config.UserAction" method="{1}"> <result name="{1}">/{1}.jsp</result> </action> </package></struts>訪問路徑:http://localhost:8080/day29/user/user_loginok
訪問路徑:http://localhost:8080/day29/user/a/b/user_loginok
訪問路徑:http://localhost:8080/day29/a/b/user/user_loginno ok
訪問路徑:http://localhost:8080/day29/user/a/b/user_login
Struts2的Action名稱搜索機制
1、獲得請求路徑的URI,例如url是:
/Struts2_01/hello_a/a/b/helloWorld.action
2、首先查詢namespace為/hello_a/a/b的package,
如果存在這個package,則在這個package中查詢名字為helloWorld的
action,如果不存在這個package則轉步驟3
3、查詢namespace為/hello_a/a的package,
如果存在這個package,則在這個package中尋找名字為helloWorld的
action,如果不存在這個package,則轉步驟4
4、查詢namespace為/hello_a的package,
如果存在這個package,則在這個package中尋找名字為helloWorld的
action,如果仍然不存在這個package,則轉步驟5
5、查詢默認的namaspace的package
查詢名字為helloWorld的action(默認的命名空間為空字符串“/” )
如果還是找不到,頁面提示404找不到action的異常。
Tomcat
Localhost: 找到訪問哪一臺機器
8080: 找到Tomcat
day29: web項目名稱
/user/a/b:先看有沒有這個名稱空間,沒找到繼續向下
/user/a: 先看有沒有這個名稱空間,沒找到繼續向下
/user: 先看有沒有這個名稱空間,沒找到繼續向下
/: 默認命名空間,還沒找到,報錯
1) Struts2路徑匹配原則
Struts中默認訪問后綴:
Struts1中默認訪問后綴是*.doc
Struts1中默認訪問后綴是*.action
如何修改默認訪問后綴
Struts2的.action訪問后綴在哪里定義
Struts-core-2.3.4-1/org.apache.struts/default.properties
自定義后綴修改常量
<constantname="struts.action.extension" value="do"/>
2.struts常量用法
指定默認編碼集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker 、velocity的輸出
<constantname="struts.i18n.encoding" value="UTF-8"/>
設置瀏覽器是否緩存靜態內容,默認值為true(生產環境下使用),開發階段最好關閉
<constantname="struts.serve.static.browserCache" value="false"/>
當struts的配置文件修改后,系統是否自動重新加載該文件,默認值為false(生產環境下使用),開發階段最好打開
<constantname="struts.configuration.xml.reload" value="true"/>
開發模式下使用,這樣可以打印出更詳細的錯誤信息
<constantname="struts.devMode" value="true" />
默認的視圖主題
<constantname="struts.ui.theme" value="simple" />
與spring集成時,指定由spring負責action對象的創建
<constantname="struts.objectFactory" value="spring" />
該屬性設置Struts 2是否支持動態方法調用,該屬性的默認值是true。如果需要關閉動態方法調用,則可設置該屬性
為 false
<constantname="struts.enable.DynamicMethodInvocation"value="false"/>
上傳文件的大小限制
<constant name="struts.multipart.maxSize"value=“10701096"/>
3.struts2指定多個配置文件


4.struts2動態方法調用
package com.xp.b_config2;public class UserAction { private String userName; public void setUserName(String userName) { this.userName = userName; } // Action中業務處理方法 public String login() { System.out.println("UserAction.login()"); return "success"; } public String register() { System.out.println("register()"); return "success"; }}package com.xp.b_config2;import com.opensymphony.xwork2.ActionSupport;public class TestAction extends ActionSupport { @Override public String execute() throws Exception { System.out.println("TestAction.execute()"); return SUCCESS; }}<?xml version="1.0" encoding="utf-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="config2" namespace="/" extends="struts-default"> <!-- 動態方法調用: http://locahost:8080/struts02/user!login <action name="user" class="com.xp.b_config2.UserAction"> <result name="success">/index.jsp</result> </action> --> <!-- 配置全局跳轉視圖 --> <global-results> <result name="success">/index.jsp</result> </global-results> <!-- 通配符: http://locahost:8080/struts02/user_login --> <action name="user_*" class="com.xp.b_config2.UserAction" method="{1}"></action> <!-- <action name="test" class="com.xp.b_config2.TestAction" method="execute"> 返回結果標記success對應的頁面再當前action中沒有配置, 所以會去找全局配置有是否有success標記對應的頁面 </action> --> <!-- 配置各項默認值 --> <!-- name 只配置了訪問路徑名稱 class 默認執行的action在struts-default有配置 <default-class-ref class="com.opensymphony.xwork2.ActionSupport" /> method 默認為execute 默認的方法execute返回值為success,對應的頁面去全局視圖找。 --> <action name="test"></action> <!-- 什么情況不配置class? 即處理的aciton --> <!-- 答案: 當只是需要跳轉到WEB-INF下資源的時候。 --> <action name="test2"> <result name="success" type="redirect">/WEB-INF/index.jsp</result> </action> </package></struts>Strust2中Action配置項的默認值


4.數據處理的幾種方式

package com.xp.c_data;import java.util.Map;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 數據處理 */public class DataAction_bak extends ActionSupport { @Override public String execute() throws Exception { /* 1. 請求數據封裝; 2. 調用Service處理業務邏輯,拿到結果數據 */ /* 3. 數據保存到域中 */ /* * * // Struts中對數據操作,方式1: 直接拿到ServletApi, 執行操作 * HttpServletRequest request = ServletActionContext.getRequest(); * Httpsession session = request.getSession(); * ServletContext application = ServletActionContext.getServletContext(); * // 操作 * request.setAttribute("request_data", "request_data1"); * session.setAttribute("session_data", "session_data1"); * application.setAttribute("application_data", "application_data1"); */ /* * 【推薦:解耦的方式實現對數據的操作】 * Struts中對數據操作,方式2: 通過ActionContext類 */ ActionContext ac = ActionContext.getContext(); /* * 得到Struts對HttpServletRequest對象進行了封裝,封裝為一個map * 拿到表示request對象的map */ Map<String, Object> request = ac.getContextMap(); /* 拿到表示session對象的map */ Map<String, Object> session = ac.getSession(); /* 拿到表示servletContext對象的map */ Map<String, Object> application = ac.getApplication(); /* 數據 */ request.put( "request_data", "request_data1_actionContext" ); session.put( "session_data", "session_data1_actionContext" ); application.put( "application_data", "application_data1_actionContext" ); return(SUCCESS); }}package com.xp.c_data;import java.util.Map;import org.apache.struts2.interceptor.ApplicationAware;import org.apache.struts2.interceptor.RequestAware;import org.apache.struts2.interceptor.SessionAware;import com.opensymphony.xwork2.ActionSupport;/** * 數據處理, 方式3: 實現接口的方法 */public class DataAction extends ActionSupport implements RequestAware, SessionAware, ApplicationAware { private Map<String, Object> request; private Map<String, Object> session; private Map<String, Object> application; /* struts運行時候,會把代表request的map對象注入 */ @Override public void setRequest( Map<String, Object> request ) { this.request = request; } /* 注入session */ @Override public void setSession( Map<String, Object> session ) { this.session = session; } /* 注入application */ @Override public void setApplication( Map<String, Object> application ) { this.application = application; } @Override public String execute() throws Exception { /* 數據 */ request.put( "request_data", "request_data1_actionAware" ); session.put( "session_data", "session_data1_actionAware" ); application.put( "application_data", "application_data1_actionAware" );/* */ return(SUCCESS); }}<?xml version="1.0" encoding="utf-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="data" namespace="/" extends="struts-default"> <!-- 全局配置 --> <global-results> <result name="success">/data.jsp</result> </global-results> <action name="data" class="com.xp.c_data.DataAction"></action> </package></struts>5.日期類型轉換器 Struts2中為什么要類型轉換? HTML表單采集數據 提交表單 Action 底層依賴HTTP傳遞數據,而HTTP協議中 沒有 “類型” 的概念. 每一項 表單輸入只可能是一個字符串或一個字符串數組。因此在服務器端Action 中 必須把 String 轉換為業務需要的特定的數據類型 Struts2中如何傳遞請求參數給Action? Struts2框架會將表單的參數以同名的方式設置給對應Action的屬性中。 該工作主要是由Parameters攔截器做的。而該攔截器中已經自動的實現了 String到基本數據類型之間的轉換工作。類似于: Beanutils工具。 案例 1、注冊表單(ServletActionContext先獲取參數后自動同名設置獲取) 2、Action中定義同名屬性并提供get和set方法 3、檢測是否轉換請求數據自動封裝實現原理:請求參數攔截器方式一:jsp表單數據填充到action中的屬性<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%><%String path = request.getContextPath();String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";%><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"><html> <head> <base href="<%=basePath%>"> <title>My JSP 'index.jsp' starting page</title> <meta http-equiv="pragma" content="no-cache"> <meta http-equiv="cache-control" content="no-cache"> <meta http-equiv="expires" content="0"> <meta http-equiv="keyWords" content="keyword1,keyword2,keyword3"> <meta http-equiv="description" content="This is my page"> </head> <body> <form action="${pageContext.request.contextPath }/user_register.action" method="post"> 用戶名:<input type="text" name="user.name"><br/> 密碼:<input type="text" name="user.pwd"><br/> 年齡:<input type="text" name="user.age"><br/> 生日:<input type="text" name="user.birth"><br/> <input type="submit" value="注冊"> </form> </body></html>方式二:Jsp表單數據填充到action對象中的屬性package com.xp.d_type;import java.util.Date;public class User { // 封裝請求數據 private String name; // 必須給set / get可以不用給 private String pwd; private int age; private Date birth; public void setName(String name) { this.name = name; } public void setPwd(String pwd) { this.pwd = pwd; } public void setAge(int age) { this.age = age; } public void setBirth(Date birth) { this.birth = birth; } public String getName() { return name; } public String getPwd() { return pwd; } public int getAge() { return age; } public Date getBirth() { return birth; } }package com.xp.d_type;/** * Struts核心業務: 請求數據自動封裝以及類型轉換 */public class UserAction { // 對象類型,一定給get方法 private User user; public void setUser(User user) { this.user = user; } public User getUser() { return user; } // 處理注冊請求 public String register() { System.out.println(user.getName()); System.out.println(user.getPwd()); System.out.println(user.getAge()); System.out.println(user.getBirth()); return "success"; }}Struts2自定義轉換器
將格式為yyyy/MM/dd的字符串轉換為日期?
Struts2自定義全局類型轉換器
l Struts2中如何自定義全局類型轉換器?
實現的接口和繼承的類都是相同的,本質上就是配置的方式不同。
l 實現
1、自定義轉換器繼承StrutsTypeConverter
2、重寫convertFromString和convertToString方法
3、注冊轉換器
3.1 在項目src目錄下建立以下固定文件
xwork-conversion.properties
3.2 在3.1文件中添加以下數據
需要轉換的類類型=轉換器類的權限定名
如: java.util.Date= cn.itcast.converter.DateConverter
l 總結
該攔截器負責對錯誤信息進行攔截器<interceptor name="conversionError“ class="org.apache.struts2.interceptor.StrutsConversionErrorInterceptor"/>package com.xp.d_type;import java.text.DateFormat;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Map;import org.apache.struts2.util.StrutsTypeConverter;/** * 自定義類型轉換器類 */public class MyConverter extends StrutsTypeConverter { /* 新需求: 要求項目中要支持的格式,如: yyyy-MM-dd/yyyyMMdd/yyyy年MM月dd日.. */ /* 先定義項目中支持的轉換的格式 */ DateFormat[] df = { new SimpleDateFormat( "yyyy-MM-dd" ), new SimpleDateFormat( "yyyyMMdd" ), new SimpleDateFormat( "yyyy年MM月dd日" ) }; /** * 把String轉換為指定的類型 【String To Date】 * @param context * 當前上下文環境 * @param values * jsp表單提交的字符串的值 * @param toClass * 要轉換為的目標類型 */ @Override public Object convertFromString( Map context, String[] values, Class toClass ) { /* 判斷: 內容不能為空 */ if ( values == null || values.length == 0 ) { return(null); } /* 判斷類型必須為Date */ if ( Date.class != toClass ) { return(null); } /* 迭代:轉換失敗繼續下一個格式的轉換; 轉換成功就直接返回 */ for ( int i = 0; i < df.length; i++ ) { try { return(df[i].parse( values[0] ) ); } catch ( ParseException e ) { continue; } } return(null); } @Override public String convertToString( Map context, Object o ) { return(null); }}<?xml version="1.0" encoding="utf-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="type" namespace="/" extends="struts-default"> <action name="user_*" class="com.xp.d_type.UserAction" method="{1}"> <result name="success">/index.jsp</result> <!-- 當日期類型轉換錯誤的時候,會跳到input視圖(struts內部返回) --> <result name="input">/error.jsp</result> </action> </package> </struts>Struts中jsp提交的數據,struts會自動轉換為action中屬性的類型對于基本數據類型以及日期類型會自動轉換日期類型只支持yyyy-MM-dd格式轉換器開發步驟
Struts2類型轉換器(源碼分析)

6.文件上傳下載
Struts2文件支持
l Struts2直接支持文件上傳嗎?
支持、默認使用的是fileupload工具。導入struts2包的時候可見。
l 上傳表單?
表單屬性 enctype = multipart/form-data
表單屬性 method =post
輸入屬性 type = file
l 文件上傳攔截器上傳文件
<interceptorname="fileUpload" class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
l Struts2默認可以上傳的文件大小是2M
Struts2上傳方法實現

Struts2文件失敗配置

Struts2上傳文件大小配置
l 如果上傳的文件大于2M,查看控制臺錯誤信息如下org.apache.commons.fileupload.FileUploadBase$SizeLimitExceededException:the request was rejected because its size (77817949) exceeds the configuredmaximum (2097152)
l 異常分析
該異常信息是common-fileupload組件輸出的,而非是Struts2框架。
l 設置上傳組件的文件大小限制
<!-- 設置最大上傳的大小是80M -->
<constantname="struts.multipart.maxSize"value="83886080"></constant>
l Struts2中是使用FileUpload攔截器進行文件上傳的
<interceptor name="fileUpload"class="org.apache.struts2.interceptor.FileUploadInterceptor"/>
<interceptor-stack name="defaultStack">
<interceptor-ref name="fileUpload"/> ….
</interceptor-stack>
l FileUploadInterceptor攔截器API


Struts2上傳文件錯誤處理
l FileUploadInterceptor 源碼分析
intercept()方法中
StringcontentTypeName = inputName + "ContentType";
StringfileNameName = inputName + "FileName";
而且配置的參數該攔截器調用了相應的set方法
setAllowedExtensions(String)、setAllowedTypes(String)、setMaximumSize(Long)
l 上傳錯誤信息顯示
l 上傳錯誤信息分析
錯誤信息File too large如果顯示中文的話會更加的友好!

Struts2多文件上傳

package com.xp.e_fileupload;import java.io.File;import org.apache.commons.io.FileUtils;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionSupport;public class FileUpload extends ActionSupport { // 對應表單:<input type="file" name="file1"> private File file1; // 文件名 private String file1FileName; // 文件的類型(MIME) private String file1ContentType; public void setFile1(File file1) { this.file1 = file1; } public void setFile1FileName(String file1FileName) { this.file1FileName = file1FileName; } public void setFile1ContentType(String file1ContentType) { this.file1ContentType = file1ContentType; } @Override public String execute() throws Exception { /******拿到上傳的文件,進行處理******/ // 把文件上傳到upload目錄 // 獲取上傳的目錄路徑 String path = ServletActionContext.getServletContext().getRealPath("/upload"); // 創建目標文件對象 File destFile = new File(path,file1FileName); // 把上傳的文件,拷貝到目標文件中 FileUtils.copyFile(file1, destFile); return SUCCESS; }}package com.xp.e_fileupload;import java.io.File;import java.io.InputStream;import java.io.UnsupportedEncodingException;import java.net.URLEncoder;import java.util.Map;import org.apache.struts2.ServletActionContext;import com.opensymphony.xwork2.ActionContext;import com.opensymphony.xwork2.ActionSupport;/** * 文件下載 * 1. 顯示所有要下載文件的列表 * 2. 文件下載 */public class DownAction extends ActionSupport { /*************1. 顯示所有要下載文件的列表*********************/ public String list() throws Exception { //得到upload目錄路徑 String path = ServletActionContext.getServletContext().getRealPath("/upload"); // 目錄對象 File file = new File(path); // 得到所有要下載的文件的文件名 String[] fileNames = file.list(); // 保存 ActionContext ac = ActionContext.getContext(); // 得到代表request的map (第二種方式) Map<String,Object> request= (Map<String, Object>) ac.get("request"); request.put("fileNames", fileNames); return "list"; } /*************2. 文件下載*********************/ // 1. 獲取要下載的文件的文件名 private String fileName; public void setFileName(String fileName) { // 處理傳入的參數中問題(get提交) try { fileName = new String(fileName.getBytes("ISO8859-1"),"UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } // 把處理好的文件名,賦值 this.fileName = fileName; } //2. 下載提交的業務方法 (在struts.xml中配置返回stream) public String down() throws Exception { return "download"; } // 3. 返回文件流的方法 public InputStream getAttrInputStream(){ return ServletActionContext.getServletContext().getResourceAsStream("/upload/" + fileName); } // 4. 下載顯示的文件名(瀏覽器顯示的文件名) public String getDownFileName() { // 需要進行中文編碼 try { fileName = URLEncoder.encode(fileName, "UTF-8"); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } return fileName; }}<?xml version="1.0" encoding="utf-8"?><!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN""http://struts.apache.org/dtds/struts-2.3.dtd"><struts> <package name="upload_" extends="struts-default"> <!-- 注意: action 的名稱不能用關鍵字"fileUpload" --> <action name="fileUploadAction" class="com.xp.e_fileupload.FileUpload"> <!-- 限制運行上傳的文件的類型 --> <interceptor-ref name="defaultStack"> <!-- 限制運行的文件的擴展名 --> <param name="fileUpload.allowedExtensions">txt,jpg,jar</param> <!-- 限制運行的類型 【與上面同時使用,取交集】 <param name="fileUpload.allowedTypes">text/plain</param> --> </interceptor-ref> <result name="success">/e/success.jsp</result> <!-- 配置錯誤視圖 --> <result name="input">/e/error.jsp</result> </action> <action name="down_*" class="com.xp.e_fileupload.DownAction" method="{1}"> <!-- 列表展示 --> <result name="list">/e/list.jsp</result> <!-- 下載操作 --> <result name="download" type="stream"> <!-- 運行下載的文件的類型:指定為所有的二進制文件類型 --> <param name="contentType">application/octet-stream</param> <!-- 對應的是Action中屬性: 返回流的屬性【其實就是getAttrInputStream()】 --> <param name="inputName">attrInputStream</param> <!-- 下載頭,包括:瀏覽器顯示的文件名 --> <param name="contentDisposition">attachment;filename=${downFileName}</param> <!-- 緩沖區大小設置 --> <param name="bufferSize">1024</param> </result> </action> </package></struts>
新聞熱點
疑難解答