Struts2初學習記錄

来源:http://www.cnblogs.com/Locked-J/archive/2016/11/05/6032933.html
-Advertisement-
Play Games

以下筆記內容來自尚矽谷_Struts2_佟剛老師的視頻教程+自己一點點整理 一、 1. VS 自實現: 1). 搭建 Struts2 的開發環境 2). 不需要顯式的定義 Filter, 而使用的是 struts2 的配置文件. 3). details.jsp 比先前變得簡單了。 屬性引用:${re ...


以下筆記內容來自尚矽谷_Struts2_佟剛老師的視頻教程+自己一點點整理
來源免責聲明

一、

1. VS 自實現:

1). 搭建 Struts2 的開發環境

2). 不需要顯式的定義 Filter, 而使用的是 struts2 的配置文件.

3). details.jsp 比先前變得簡單了。

  屬性引用:${requestScope.product.productName} -> ${productName}

4). 步驟:

I.  由 product-input.action 轉到 /WEB-INF/pages/input.jsp

  在 struts2 中配置一個 action

1 <action name="product-input">
2     <result>/WEB-INF/pages/input.jsp</result>
3 </action>

  II. 由 input.jsp 頁面的 action: product-save.action 到 Product's save, 再到  /WEB-INF/pages/details.jsp

1 <action name="product-save"
2         class="com.atguigu.struts2.helloworld.Product"   method="save">
3     <result name="details">/WEB-INF/pages/details.jsp</result>
4 </action>

    *在 Prodcut 中定義一個 save 方法, 且返回值為 details,與method=“save”對應

 

二、

1. action VS Action 類

1). action: 代表一個  Struts2 的請求.

2). Action 類: 能夠處理 Struts2 請求的類.

 > 屬性的名字必須遵守與 JavaBeans 屬性名相同的命名規則.      屬性的類型可以是任意類型. 從字元串到非字元串(基本資料庫類型)之

  間的數據轉換可以自動發生

 > 必須有一個不帶參的構造器: 通過反射創建實例

 > 至少有一個供 struts 在執行這個 action 時調用的方法

 > 同一個 Action 類可以包含多個 action 方法.

 > Struts2 會為每一個 HTTP 請求創建一個新的 Action 實例, 即 Action 不是單例, 是線程安全的.

 

2. 在 Action 中訪問 WEB 資源:

1). 什麼是 WEB 資源 ?

 HttpServletRequest, HttpSession, ServletContext 等原生的 Servlet API

2). 為什麼訪問 WEB 資源?

 B\S 的應用的 Controller 中必然需要訪問 WEB 資源: 向域對象中讀寫屬性, 讀寫 Cookie, 獲取 realPath ……

3). 如何訪問 ?

I. 和 Servlet API 解耦的方式: 只能訪問有限的 Servlet API 對象, 且只能訪問其有限的方法(讀取請求參數, 讀寫域對象的屬性, 使 session 失效……)

> 使用 ActionContext  > 實現 XxxAware 介面

> 選用的建議: 若一個 Action 類中有多個 action 方法, 且多個方法都需要使用域對象的 Map 或 parameters,則建議使用  Aware 介面的方式

> session 對應的 Map 實際上是 SessionMap 類型的! 強轉後若調用其 invalidate() 方法, 可以使其 session 失效!

II. 和 Servlet API 耦合的方式: 可以訪問更多的 Servlet API 對象, 且可以調用其原生的方法. 

  > 使用 ServletActionContext    > 實現 ServletXxxAware 介面.

 

3. 關於 Struts2 請求的擴展名問題

1). org.apache.struts2 包下的 default.properties 中配置了 Struts2 應用個的一些常量

2). struts.action.extension 定義了當前 Struts2 應用可以接受的請求的擴展名.

3). 可以在 struts.xml 文件中以常量配置的方式修改 default.properties 所配置的常量.

<constant name="struts.action.extension" value="action,do,"></constant>

 

4. ActionSupport

1). ActionSupport 是預設的 Action 類: 若某個 action 節點沒有配置 class 屬性, 則 ActionSupport 即為 待執行的 Action 類. 而 execute 方法即為要預設執行的 action 方法

1 <action name="testActionSupport">
2     <result>/testActionSupport.jsp</result>
3 </action>

      等同於

1 <action name="testActionSupport" 
2         class="com.opensymphony.xwork2.ActionSupport"  method="execute">
3     <result>/testActionSupport.jsp</result>
4 </action>


    2). 在手工完成欄位驗證, 顯示錯誤消息, 國際化等情況下, 推薦繼承 ActionSupport.

 

 

5. result:

1). result 是 action 節點的子節點

2). result 代表 action 方法執行後, 可能去的一個目的地

3). 一個 action 節點可以配置多個 result 子節點.

4). result 的 name 屬性值對應著 action 方法可能有的一個返回值.

<result name="index">/index.jsp</result>

5). result 一共有 2 個屬性, 還有一個是 type: 表示結果的響應類型

6). result 的 type 屬性值在 struts-default 包的 result-types 節點的 name 屬性中定義. 

   常用的有:

    > dispatcher(預設的): 轉發. 同 Servlet 中的轉發.

> redirect: 重定向

> redirectAction: 重定向到一個 Action      註意: 通過 redirect 的響應類型也可以便捷的實現 redirectAction 的功能!

1 <result name="index" type="redirectAction">
2     <param name="actionName">testAction</param>
3     <param name="namespace">/atguigu</param>
4 </result>

      OR

1 <result name="index" type="redirect">/atguigu/testAction.do</result>

    > chain: 轉發到一個 Action

      註意: 不能通過 type=dispatcher 的方式轉發到一個 Action   只能是:

1 <result name="test" type="chain">
2     <param name="actionName">testAction</param>
3     <param name="namespace">/atguigu</param>
4 </result> 

         不能是:

1 <result name="test">/atguigu/testAction.do</result>

 

三、

1. 關於值棧:

1). helloWorld 時, ${productName} 讀取 productName 值, 實際上該屬性並不在 request 等域對象中, 而是從值棧中獲取的.

2). ValueStack:

I.  可以從 ActionContext 中獲取值棧對象   II. 值棧分為兩個邏輯部分

> Map 棧: 實際上是 OgnlContext 類型, 是個 Map, 也是對 ActionContext 的一個引用.

  裡邊保存著各種 Map: requestMap, sessionMap, applicationMap, parametersMap, attr

> 對象棧: 實際上是 CompoundRoot 類型, 是一個使用 ArrayList 定義的棧.

  裡邊保存各種和當前 Action 實例相關的對象.   是一個數據結構意義的棧.

 

2. Struts2 利用 s:property 標簽和 OGNL 表達式來讀取值棧中的屬性值

1). 值棧中的屬性值:

> 對於對象棧: 對象棧中某一個對象的屬性值

> Map 棧: request, session, application 的一個屬性值 或 一個請求參數的值.

2). 讀取對象棧中對象的屬性:

> 若想訪問 Object Stack 里的某個對象的屬性. 可以使用以下幾種形式之一: 

   object.propertyName ;  object['propertyName'] ;  object["propertyName"]

> ObjectStack 里的對象可以通過一個從零開始的下標來引用.

  ObjectStack 里的棧頂對象可以用 [0] 來引用, 它下麵的那個對象可以用 [1] 引用. 

  [0].message

> [n] 的含義是從棧頂往下第 n 個開始搜索, 而不是只搜索第 n 個對象

> 若從棧頂對象開始搜索, 則可以省略下標部分: message

> 結合 s:property 標簽:

<s:property value="[0].message" />  <s:property value="message" /> 


    3). 預設情況下, Action 對象會被 Struts2 自動的放到值棧的棧頂.

 

四、

1. Action 實現 ModelDriven 介面後的運行流程

1). 先會執行 ModelDrivenInterceptor 的 intercept 方法.

 1     public String intercept(ActionInvocation invocation) throws Exception {
 2         //獲取 Action 對象: EmployeeAction 對象, 此時該 Action 已經實現了ModelDriven 介面
 3         //public class EmployeeAction implements RequestAware,ModelDriven<Employee>
 4         Object action = invocation.getAction();
 5 
 6         //判斷 action 是否是 ModelDriven 的實例
 7         if (action instanceof ModelDriven) {
 8             //強制轉換為 ModelDriven 類型
 9             ModelDriven modelDriven = (ModelDriven) action;
10             //獲取值棧
11             ValueStack stack = invocation.getStack();
12             //調用 ModelDriven 介面的 getModel() 方法
13             //即調用 EmployeeAction 的 getModel() 方法
14             /*
15             public Employee getModel() {
16                 employee = new Employee();
17                 return employee;
18             }
19             */
20             Object model = modelDriven.getModel();
21             if (model !=  null) {
22                 //把 getModel() 方法的返回值壓入到值棧的棧頂. 實際壓入的是 EmployeeAction 的 employee 成員變數
23                 stack.push(model);
24             }
25             if (refreshModelBeforeResult) {
26                 invocation.addPreResultListener(new RefreshModelBeforeResult(modelDriven, model));
27             }
28         }
29         return invocation.invoke();
30     }

     

2). 執行 ParametersInterceptor 的 intercept 方法:

  把請求參數的值賦給棧頂對象對應的屬性. 若棧頂對象沒有對應的屬性, 則查詢 值棧中下一個對象對應的屬性...

3). 註意: getModel 方法不能提供以下實現. 的確會返回一個 Employee 對象到值棧的棧頂. 但當前 Action 的 employee 成員變數卻是 null.

1 public Employee getModel() {
2     return new Employee(); 
3 }

 

2. 使用 paramsPrepareParamsStack 攔截器棧後的運行流程

1). paramsPrepareParamsStack 和 defaultStack 一樣都是攔截器棧. 而 struts-default 包預設使用的是 defaultStack

2). 可以在 Struts 配置文件中通過以下方式修改使用的預設的攔截器棧

   <default-interceptor-ref name="paramsPrepareParamsStack"></default-interceptor-ref> 

3). paramsPrepareParamsStack 攔截器在於

    params -> modelDriven -> params

  所以可以先把請求參數賦給 Action 對應的屬性, 再根據賦給 Action 的那個屬性值決定壓到值棧棧頂的對象, 最後再為棧頂對象的屬性賦值.

  對於Employee 的 edit 操作而言:

  I.    先為 EmployeeAction 的 employeeId 賦值

  II.   根據 employeeId 從資料庫中載入對應的對象, 並放入到值棧的棧頂

  III.  再為棧頂對象的 employeeId 賦值(實際上此時 employeeId 屬性值已經存在)

  IV.  把棧頂對象的屬性回顯在表單中.

4). 關於回顯:  Struts2 表單標簽會從值棧中獲取對應的屬性值進行回顯.

5). 存在的問題:

  getModel 方法

1 public Employee getModel() {
2     if(employeeId == null)
3         employee = new Employee();
4     else
5         employee = dao.get(employeeId);
6     
7     return employee;
8 }

      I.   在執行刪除的時候, employeeId 不為 null, 但 getModel 方法卻從資料庫載入了一個對象. 不該載入!

   II.  指向查詢全部信息時, 也 new Employee() 對象. 浪費!

6). 解決方案: 使用 PrepareInterceptorPreparable 介面.

7). 關於 PrepareInterceptor

[分析後得到的結論]

  若 Action 實現了 Preparable 介面, 則 Struts 將嘗試執行 prepare[ActionMethodName] 方法,

  若 prepare[ActionMethodName] 不存在, 則將嘗試執行 prepareDo[ActionMethodName] 方法. 若都不存在, 就都不執行.

  若 PrepareInterceptor  的 alwaysInvokePrepare 屬性為 false, 則 Struts2 將不會調用實現了 Preparable 介面的  Action 的 prepare() 方法

[能解決 5) 的問題的方案]

  可以為每一個 ActionMethod 準備 prepare[ActionMethdName] 方法, 而拋棄掉原來的 prepare() 方法 將 PrepareInterceptor  的   alwaysInvokePrepare 屬性置為 false, 以避免 Struts2 框架再調用 prepare() 方法.

如何在配置文件中為攔截器棧的屬性賦值: 參看 /struts-2.3.15.3/docs/WW/docs/interceptors.html

1 <interceptors>
2     <interceptor-stack name="parentStack">
3         <interceptor-ref name="defaultStack">
4             <param name="params.excludeParams">token</param>
5         </interceptor-ref>
6     </interceptor-stack>
7 </interceptors>
8  
9 <default-interceptor-ref name="parentStack"/>

                   ----------------------------------源代碼解析---------------------------------

 1 public String doIntercept(ActionInvocation invocation) throws Exception {
 2     //獲取 Action 實例
 3     Object action = invocation.getAction();
 4 
 5     //判斷 Action 是否實現了 Preparable 介面
 6     if (action instanceof Preparable) {
 7         try {
 8             String[] prefixes;
 9             //根據當前攔截器的 firstCallPrepareDo(預設為 false) 屬性確定 prefixes
10             if (firstCallPrepareDo) {
11                 prefixes = new String[] {ALT_PREPARE_PREFIX, PREPARE_PREFIX};
12             } else {
13                 prefixes = new String[] {PREPARE_PREFIX, ALT_PREPARE_PREFIX};
14             }
15             //若為 false, 則 prefixes: prepare, prepareDo
16             //調用首碼方法.
17             PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes);
18         }
19         catch (InvocationTargetException e) {
20 
21             Throwable cause = e.getCause();
22             if (cause instanceof Exception) {
23                 throw (Exception) cause;
24             } else if(cause instanceof Error) {
25                 throw (Error) cause;
26             } else {
27                 throw e;
28             }
29         }
30 
31         //根據當前攔截器的 alwaysInvokePrepare(預設是 true) 決定是否調用 Action 的 prepare 方法
32         if (alwaysInvokePrepare) {
33             ((Preparable) action).prepare();
34         }
35     }
36 
37     return invocation.invoke();
38 }
39 
40 PrefixMethodInvocationUtil.invokePrefixMethod(invocation, prefixes) 方法: 
41 
42 public static void invokePrefixMethod(ActionInvocation actionInvocation, String[] prefixes) throws 
43 
44 InvocationTargetException, IllegalAccessException {
45     //獲取 Action 實例
46     Object action = actionInvocation.getAction();
47     //獲取要調用的 Action 方法的名字(update)
48     String methodName = actionInvocation.getProxy().getMethod();
49     
50     if (methodName == null) {
51         // if null returns (possible according to the docs), use the default execute 
52         methodName = DEFAULT_INVOCATION_METHODNAME;
53     }
54     
55     //獲取首碼方法
56     Method method = getPrefixedMethod(prefixes, methodName, action);
57     
58     //若方法不為 null, 則通過反射調用首碼方法
59     if (method != null) {
60         method.invoke(action, new Object[0]);
61     }
62 }
63 
64 PrefixMethodInvocationUtil.getPrefixedMethod 方法: 
65 
66 public static Method getPrefixedMethod(String[] prefixes, String methodName, Object action) {
67     assert(prefixes != null);
68     //把方法的首字母變為大寫
69     String capitalizedMethodName = capitalizeMethodName(methodName);
70     
71     //遍歷首碼數組
72     for (String prefixe : prefixes) {
73         //通過拼接的方式, 得到首碼方法名: 第一次 prepareUpdate, 第二次 prepareDoUpdate
74         String prefixedMethodName = prefixe + capitalizedMethodName;
75         try {
76             //利用反射獲從 action 中獲取對應的方法, 若有直接返回. 並結束迴圈.
77             return action.getClass().getMethod(prefixedMethodName, EMPTY_CLASS_ARRAY);
78         }
79         catch (NoSuchMethodException e) {
80             // hmm -- OK, try next prefix
81             if (LOG.isDebugEnabled()) {
82                 LOG.debug("cannot find method [#0] in action [#1]", prefixedMethodName, action.toString());
83             }
84         }
85     }
86     return null;
87 }


 

五、

1. 國際化的目標

1). 如何配置國際化資源文件

I.   Action 範圍資源文件: 在Action類文件所在的路徑建立名為 ActionName_language_country.properties 的文件

II.  包範圍資源文件: 在包的根路徑下建立文件名為 package_language_country.properties 的屬性文件, 一旦建立,處於該包下的所有 Action 都可以訪問該資源文件。註意:包範圍資源文件的 baseName 就是package,不是Action所在的包名。

III. 全局資源文件

  > 命名方式: basename_language_country.properties  

  > struts.xml   <constant name="struts.custom.i18n.resources" value="baseName"/> 

IV.  國際化資源文件載入的順序如何呢 ?

  離當前 Action 較近的將被優先載入.

假設我們在某個 ChildAction 中調用了getText("username"):

(1) 載入和 ChildAction 的類文件在同一個包下的系列資源文件 ChildAction.properties

(2) 載入  ChildAction 實現的介面 IChild,且和 IChildn 在同一個包下 IChild.properties 系列資源文件。

(3) 載入 ChildAction 父類 Parent,且和 Parent 在同一個包下的 baseName 為 Parent.properties 系列資源文件。

(4) 若 ChildAction 實現 ModelDriven 介面,則對於getModel()方法返回的model 對象,重新執行第(1)步操作。

(5) 查找當前包下 package.properties 系列資源文件。

(6) 沿著當前包上溯,直到最頂層包來查找 package.properties 的系列資源文件。

(7) 查找 struts.custom.i18n.resources 常量指定 baseName 的系列資源文件。

(8) 直接輸出該key的字元串值。

 

2). 如何在頁面上 和 Action 類中訪問國際化資源文件的  value 值

I. 在 Action 類中. 若 Action 實現了 TextProvider 介面, 則可以調用其 getText() 方法獲取 value 值  > 通過繼承 ActionSupport 的方式。  

II. 頁面上可以使用 s:text 標簽; 對於表單標簽可以使用表單標簽的 key 屬性值  

> 若有占位符, 則可以使用 s:text 標簽的 s:param 子標簽來填充占位符

> 可以利用標簽和 OGNL 表達式直接訪問值棧中的屬性值(對象棧 和 Map 棧)

 time=Time:{0} 
<s:text name="time">  <s:param value="date"></s:param>  </s:text>

 ------------------------------------ 

time2=Time:${date} 
<s:text name="time2"></s:text>  

 

3). 實現通過超鏈接切換語言.

I.  關鍵之處在於知道 Struts2 框架是如何確定 Local 對象的 !  

II. 可以通過閱讀 I18N 攔截器知道.   

III. 具體確定 Locale 對象的過程:

> Struts2 使用 i18n 攔截器 處理國際化,並且將其註冊在預設的攔截器棧中

> i18n攔截器在執行Action方法前,自動查找請求中一個名為 request_locale 的參數。 如果該參數存在,攔截器就將其作為參數,轉換成Locale對象,並將其設為用戶預設的Locale(代表國家/語言環境)。    並把其設置為 session 的 WW_TRANS_I18N_LOCALE 屬性  

> 若 request 沒有名為request_locale 的參數,則 i18n 攔截器會從 Session 中獲取 WW_TRANS_I18N_LOCALE的屬性值,   若該值不為空,則將該屬性值設置為瀏覽者的預設Locale  > 若 session 中的 WW_TRANS_I18N_LOCALE 的屬性值為空,則從 ActionContext 中獲取 Locale 對象。  

IV.  具體實現: 只需要在超連接的後面附著  request_locale 的請求參數, 值是 語言國家 代碼.  

<a href="testI18n.action?request_locale=en_US">English</a>  <a href="testI18n.action?request_locale=zh_CN">中文</a>

    > 註意: 超鏈接必須是一個 Struts2 的請求, 即使 i18n 攔截器工作!  

 

六、

1. Struts2 的驗證

1). 驗證分為兩種:

  > 聲明式驗證*

    >> 對哪個 Action 或 Model 的那個欄位進行驗證   >> 使用什麼驗證規則   >> 如果驗證失敗, 轉向哪一個頁面, 顯示是什麼錯誤消息    

  > 編程式驗證  

2). 聲明式驗證的 helloworld

I.  先明確對哪一個 Action 的哪一個欄位進行驗證: age

II. 編寫配置文件:  

> 把 struts-2.3.15.3\apps\struts2-blank\WEB-INF\classes\example 下的 Login-validation.xml 文件複製到  當前 Action 所在的包下.  

> 把該配置文件改為: 把  Login 改為當前 Action 的名字.  > 編寫驗證規則: 參見 struts-2.3.15.3/docs/WW/docs/validation.html 文檔即可.  

> 在配置文件中可以定義錯誤消息:  

1 <field name="age">
2     <field-validator type="int">
3         <param name="min">20</param>
4         <param name="max">50</param>
5         <message>Age needs to be between ${min} and ${max}</message>
6     </field-validator>
7 </field>    

        再在 國際化資源文件 中加入一個鍵值對: error.int=^^^Age needs to be between ${min} and ${max}  

 

III. 若驗證失敗, 則轉向 input 的那個 result. 所以需要配置 name=input 的 result    <result name="input">/validation.jsp</result>   

IV. 如何顯示錯誤消息呢 ?  

  > 若使用的是非 simple, 則自動顯示錯誤消息.  

  > 若使用的是 simple 主題, 則需要 s:fielderror 標簽或直接使用 EL 表達式(使用 OGNL)   ${fieldErrors.age[0]}   OR   <s:fielderror fieldName="age"></s:fielderror> *

3). 註意: 若一個 Action 類可以應答多個 action 請求, 多個 action 請求使用不同的驗證規則, 怎麼辦 ?

  > 為每一個不同的 action 請求定義其對應的驗證文件: ActionClassName-AliasName-validation.xml  

  > 不帶別名的配置文件: ActionClassName-validation.xml 中的驗證規則依然會發生作用. 可以把各個 action 公有的驗證規則  配置在其中.

     但需要註意的是, 只適用於某一個 action 的請求的驗證規則就不要這裡再配置了.   4). 聲明式驗證框架的原理:

  > Struts2 預設的攔截器棧中提供了一個 validation 攔截器    

  > 每個具體的驗證規則都會對應具體的一個驗證器. 有一個配置文件把驗證規則名稱和驗證器關聯起來了. 而實際上驗證的是那個驗證器.  

    該文件位於 com.opensymphony.xwork2.validator.validators 下的 default.xml

     <validator name="required" class="com.opensymphony.xwork2.validator.validators.RequiredFieldValidator"/> 

5). 短路驗證: 若對一個欄位使用多個驗證器, 預設情況下會執行所有的驗證. 若希望前面的驗證器驗證沒有通過, 後面的就不再驗證, 可以使用短路驗證

 1 <!-- 設置短路驗證: 若當前驗證沒有通過, 則不再進行下麵的驗證 -->
 2 <field-validator type="conversion" short-circuit="true">
 3     <message>^Conversion Error Occurred</message>
 4 </field-validator>
 5 
 6 <field-validator type="int">
 7     <param name="min">20</param>
 8     <param name="max">60</param>
 9     <message key="error.int"></message>
10 </field-validator>

 

6). 若類型轉換失敗, 預設情況下還會執行後面的攔截器, 還會進行 驗證.

可以通過修改 ConversionErrorInterceptor 源代碼的方式使 當類型轉換失敗時, 不再執行後續的驗證攔截器, 而直接返回 input 的 result

1     Object action = invocation.getAction();
2         if (action instanceof ValidationAware) {
3             ValidationAware va = (ValidationAware) action;
4 
5             if(va.hasFieldErrors() || va.hasActionErrors()){
6                 return "input";
7             }
8         }

  

7). 關於非欄位驗證: 不是針對於某一個欄位的驗證.

1 <validator type="expression">
2     <param name="expression"><![CDATA[password==password2]]></param>
3     <message>Password is not equals to password2</message>
4 </validator>

 

8). 不同的欄位使用同樣的驗證規則, 而且使用同樣的響應消息 ?

1 error.int=${getText(fieldName)} needs to be between ${min} and ${max}
2 age=\u5E74\u9F84 count=\u6570\u91CF   

    詳細分析參見  PPT 159. 

9). 自定義驗證器:

I.   定義一個驗證器的類

> 自定義的驗證器都需要實現 Validator.  

> 可以選擇繼承 ValidatorSupport 或 FieldValidatorSupport 類  

> 若希望實現一個一般的驗證器, 則可以繼承 ValidatorSupport  

> 若希望實現一個欄位驗證器, 則可以繼承 FieldValidatorSupport    

> 具體實現可以參考目前已經有的驗證器.    > 若驗證程式需要接受一個輸入參數, 需要為這個參數增加一個相應的屬性

II.  在配置文件中配置驗證器

  > 預設情況下下, Struts2 會在 類路徑的根目錄下載入 validators.xml 文件. 在該文件中載入驗證器.

    該文件的定義方式同預設的驗證器的那個配置文件: 位於 com.opensymphony.xwork2.validator.validators 下的 default.xml        

  > 若類路徑下沒有指定的驗證器, 則從 com.opensymphony.xwork2.validator.validators 下的 default.xml 中的驗證器載入    

III. 使用: 和目前的驗證器一樣.

IV. 示例代碼: 自定義一個 18 位身份證驗證器    

 

七、

1. 文件的上傳:

1). 表單需要註意的 3 點

2). Struts2 的文件上傳實際上使用的是 Commons FileUpload 組件, 所以需要導入 commons-fileupload-1.3.jar commons-io-2.0.1.jar

3). Struts2 進行文件上傳需要使用 FileUpload 攔截器

4). 基本的文件的上傳: 直接在 Action 中定義如下 3 個屬性, 並提供對應的 getter 和 setter

  //文件對應的 File 對象 private File [fileFieldName]; //文件類型 private String [fileFieldName]ContentType; //文件名 private String [fileFieldName]FileName;

5). 使用 IO 流進行文件的上傳即可.

6). 一次傳多個文件怎麼辦 ?

  若傳遞多個文件, 則上述的 3 個屬性, 可以改為 List 類型! 多個文件域的 name 屬性值需要一致.

7). 可以對上傳的文件進行限制嗎 ? 例如擴展名, 內容類型, 上傳文件的大小 ? 若可以, 則若出錯, 顯示什麼錯誤消息呢 ? 消息可以定製嗎 ?

  可以的!

  可以通過配置 FileUploadInterceptor 攔截器的參數的方式來進行限制

maximumSize (optional) - 預設的最大值為 2M. 上傳的單個文件的最大值

allowedTypes (optional) - 允許的上傳文件的類型. 多個使用 , 分割

allowedExtensions (optional) - 允許的上傳文件的擴展名. 多個使用 , 分割.

註意: 在 org.apache.struts2 下的 default.properties 中有對上傳的文件總的大

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • List Set 都是介面,都繼承了Collection介面 ArrayList LinkList 直接實現了List介面 HashSet 實現了Set介面 HashSet 實現了Set介面 TreeSet繼承父類AbstractSet 間接的實現了Set 介面 Map 是介面,沒有實現Collec ...
  • JMS是一個用於提供消息服務的技術規範,它制定了在整個消息服務提供過程中的所有數據結構和交互流程。 而activemq則是消息隊列服務,是面向消息中間件(MOM)的最終實現,是真正的服務提供者。 jms 的一個標準或者說是一個協議。 通常用於企業級應用的消息傳遞。 主要有topic 消息(1 對多) ...
  • 一、前言 在之前的隨筆之中,我們已經瞭解Java通過上傳組件來實現上傳和下載,這次我們來瞭解Struts2的上傳和下載。 註意:文件上傳時,我們需要將表單提交方式設置為"POST"方式,並且將enctype屬性設置為"multipart/form-data",該屬性的預設值為"application ...
  • iText是著名的開放項目,是用於生成PDF文檔的一個java類庫。通過iText不僅可以生成PDF或rtf的文檔,而且可以將XML、Html文件轉化為PDF文件。 官方網站:http://itextpdf.com/ 示例版本:itextpdf-5.2.1.jar 示例代碼 document.add ...
  • 一、OOP(Object-oriented Programming)面向對象程式編程 初談類和對象,所謂萬物皆對象,類和對象有什麼區別和聯繫? 類,是對某一種類型的定義,比如字元串,動物,人,飛機等等,而對象是指具體的字元串,動物,人... 如:豬是類,定義了,豬,有體重,有年齡,可以吃飯,可以睡覺 ...
  • 英文文檔: 2. 當傳入多個可迭代對象時,函數的參數必須提供足夠多的參數,保證每個可迭代對象同一索引的值均能正確傳入函數。 3. 當傳入多個可迭代對象時,且它們元素長度不一致時,生成的迭代器只到最短長度。 4. map函數是一個典型的函數式編程例子。 ...
  • 在我的上一篇博客JVM-String比較-位元組碼分析中介紹了String字元串比較的原因,藉著分析位元組碼的機會,我這篇博客將會繪圖展現方法內部位元組碼執行過程。 話不多說,貼上我們將要分析的Java方法代碼: 再貼上我們將要分析的Java方法的位元組碼: 由Code:下麵的第一行,我們得知,操作數棧深度 ...
  • org.apache.commons.lang.StringUtils中常用的方法,這裡主要列舉String中沒有,且比較有用的方法: 1. 檢查字元串是否為空: static boolean isBlank(CharSequence str) 判斷字元串是否為空或null; static bool ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...