SSH框架-Struts2基礎-Action

Struts2的目錄結構:

  解壓apps目錄下的struts2-blank.war:javascript

  仿照這個最基本的項目,拷貝相關文件:html

1.拷貝apps/struts2-blank/WEB-INF/classes/struts.xml到咱們的項目中的src目錄(由於src編譯完成後會自動放在classes目錄);

2.拷貝類庫apps/struts2-blank/WEB-INF/lib/*.jar到本身項目的WebRoot/WEB-INF/lib下。

  

  3.拷貝apps/struts2-blank/WEB-INF/web.xml中關於過濾器的配置到咱們的項目:java

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
 3     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
 5     http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
 6     <display-name></display-name>
 7 
 8 <!-- 從struts2實例項目struts2-blank中拷貝的關於過濾器的配置 -->
 9     <filter>
10         <filter-name>struts2</filter-name>
11         <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
12     </filter>
13     <filter-mapping>
14         <filter-name>struts2</filter-name>
15         <url-pattern>/*</url-pattern>
16     </filter-mapping>
17 
18     <welcome-file-list>
19         <welcome-file>index.jsp</welcome-file>
20     </welcome-file-list>
21 </web-app>

  4.修改咱們本身項目下的src/struts.xml,先將struts標記下的全部內容所有註釋(方便之後參考),並配置咱們本身的package:web

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 
 6 <struts>
 7 
 8 <!--     註釋原來的配置
 9     <constant name="struts.enable.DynamicMethodInvocation" value="false" />
10     <constant name="struts.devMode" value="true" />
11 
12     <package name="default" namespace="/" extends="struts-default">
13 
14         <default-action-ref name="index" />
15 
16         <global-results>
17             <result name="error">/WEB-INF/jsp/error.jsp</result>
18         </global-results>
19 
20         <global-exception-mappings>
21             <exception-mapping exception="java.lang.Exception" result="error"/>
22         </global-exception-mappings>
23 
24         <action name="index">
25             <result type="redirectAction">
26                 <param name="actionName">HelloWorld</param>
27                 <param name="namespace">/example</param>
28             </result>
29         </action>
30     </package>
31 
32     <include file="example.xml"/>
33  -->
34     <!-- Add packages here -->
35     
36     <!-- 配置咱們本身的package -->
37     <package name="default" namespace="/" extends="struts-default">
38         <action name="hello">
39             <result>/Hello.jsp</result>
40         </action>
41        </package>
42 
43 </struts>

  5.在WebRoot目錄下新建一個Hello.jsp。apache

  將項目部署到Tomcat進行訪問。若是直接輸入項目名稱回車會出現如下錯誤:小程序

HTTP Status 404 - There is no Action mapped for namespace [/] and action name [] associated with context path [/Struts2].服務器

  應該使用使用hello.action或者hello進行訪問:session

基本配置

  1.更改Struts的模式爲開發模式

  在上面的那個項目中若是咱們在struts.xml中修改了action的名字:app

1 <package name="default" namespace="/" extends="struts-default">
2     <!-- 咱們將action的名字由hello改爲hello_struts因爲不能當即生效,將出現404錯誤 -->
3     <action name="hello_struts">
4         <result>/Hello.jsp</result>
5     </action>
6 </package>    

  在沒有重啓服務器的狀況下將出現如下錯誤:jsp

HTTP Status 404 - There is no Action mapped for namespace [/] and action name [hello_struts] associated with context path [/Struts2].

  若是每次更改完struts.xml都要重啓服務器就會比較麻煩。在struts.xml中配置一個開發模式的常量:

1 <constant name="struts.devMode" value="true" />    <!-- 開發模式,更改就有反饋 -->

  2.爲jar包配置源代碼和javadoc文檔:

  

  這樣就能夠在MyEclipse中查看其源代碼和使用幫助文檔了。

  3.配置struts中的DTD,使它在離線的條件下有在xml中有自動提示:

  

Struts的運行機制:

  

  Struts2把用戶的請求和視圖(展示給用戶的頁面)進行了分離。

namespace

  namespace決定了action的訪問路徑,默認爲空(""),能夠接收全部的action,namespace能夠寫成/或者/xxx/yyy(namespace必須以斜槓開頭),對應的action的訪問路徑爲/index.action,或者/xxx/yyy/index.action。namespace最好也使用模塊來進行命名(例如package的名字是user,那麼namespace的名字也是/user)。result的名字若是是"success"則能夠省略。

1 <!-- package用來解決重名的問題 -->
2 <package name="front" namespace="/front" extends="struts-default">
3 <action name="index">
4     <!-- result若是名字是success則能夠省略 -->
5     <result name="success">/Namespace.jsp</result>
6 </action>
7 </package>

  

  若是namespace爲空,只要是以/index結尾的請求均可以訪問:

1 <!-- 不寫namespace與 namespace=""等價 -->
2 <package name="main" extends="struts-default">
3 <action name="index">
4     <result>/Namespace.jsp</result>
5 </action>
6 </package>

  不一樣的package裏面能夠有相同的action,訪問的時候是經過namespace進行查找,若是在對應的namespace下找到了action,就使用該action下的result配置;若是在指定的namespace下沒有找到該action則找namespace爲空的那個package的action,若是仍是沒有找到就直接報錯。

  

  例若有如下的的struts.xml:

 1 <!-- 不一樣的package下有同名的action,一個package的namespace爲/front,另外一個爲空 -->
 2 <package name="front" namespace="/front" extends="struts-default">
 3     <action name="index">
 4         <result name="success">/Namespace.jsp</result>
 5     </action>
 6     </package>
 7 
 8 <package name="main" extends="struts-default">
 9     <action name="index">
10         <result>/Namespace1.jsp</result>
11     </action>
12 </package>

  

 Action

  具體視圖的返回能夠由用戶自定義的Action來決定。具體的手段是根據返回的字符串找到對應的設置項來決定視圖的內容。具體Action的實現是一個普通的Java類,裏面有public String execute()方法便可。繼承ActionSupport,也能夠實現Action接口。通常經常使用的是繼承ActionSupport,好處是能夠直接使用Struts2封裝好的方法。

  例如struts.xml中有如下配置:

1 <package name="front" namespace="/" extends="struts-default">
2     <action name="index" class="org.gpf.struts2.front.action.IndexAction1">
3         <result>/ActionIntroduction.jsp</result>
4     </action>
5 </package>

  org.gpf.struts2.front.action.IndexAction1以下:

1 package org.gpf.struts2.front.action;
2 
3 public class IndexAction1 {
4     
5     public String execute(){
6         
7         return "success";
8     }
9 }

  Struts2和Struts1的區別在於Struts1每次訪問的是同一個Action對象;Struts2每次new一個新的Action,不須要擔憂線程的同步問題。

  上面的小程序的序列圖以下:

  當咱們本身沒有Action類的時候默認調用的是ActionSupport類中的execute()方法。查看ActionSupport類,發現它實現了Action接口,而Action接口中定義了一系列的常量和一個execute方法:

 1 public class ActionSupport implements Action....{
 2 
 3     public String execute() throws Exception {
 4         return SUCCESS;
 5     }
 6 
 7 }
 8 
 9 public interface Action {
10 
11     public static final String SUCCESS = "success";
12    
13     public static final String NONE = "none";
14 
15     public static final String ERROR = "error";
16 
17     public static final String INPUT = "input";
18    
19     public static final String LOGIN = "login";
20 
21     public String execute() throws Exception;
22 
23 }

  編寫Action的3種方式(在實際開發中通常使用繼承自ActionSupport):

 1 package org.gpf.struts2.front.action;
 2 
 3 /**
 4  * 自定義一個類,有一個public String execute()方法
 5  */
 6 public class IndexAction1 {
 7     
 8     public String execute(){
 9         
10         return "success";
11     }
12 }
13 
14 package org.gpf.struts2.front.action;
15 
16 import com.opensymphony.xwork2.Action;
17 /**
18  * 實現Action接口
19  * @author gaopengfei
20  * @date 2015-5-9 下午5:47:00
21  */
22 public class IndexAction2 implements Action {
23 
24     @Override
25     public String execute() throws Exception {
26         
27         return SUCCESS;
28     }
29 
30 }
31 
32 package org.gpf.struts2.front.action;
33 
34 import com.opensymphony.xwork2.ActionSupport;
35 /**
36  * 繼承ActionSupport
37  * @author gaopengfei
38  * @date 2015-5-9 下午5:46:48
39  */
40 public class IndexAction3 extends ActionSupport {
41 
42     @Override
43     public String execute() throws Exception {
44         
45         return super.execute();
46     }
47 }

  路徑問題說明

  有如下的struts配置:

1 <package name="path" namespace="/path" extends="struts-default">
2     <action name="path" class="org.gpf.struts2.front.action.PathAction">
3         <result name="path">/path.jsp</result>
4     </action>
5 </package>

  有如下的PathAction:

1 package org.gpf.struts2.front.action;
2 
3 public class PathAction {
4     
5     public String execute(){
6         
7         return "path";
8     }
9 }

咱們經過如下的方式訪問:

  因爲咱們訪問的時候沒有指定namespace,因此會在web.xml中找到項目的默認歡迎頁index.jsp。在index.jsp中有一個超連接:

<a href="path/path.action">路徑問題說明</a>

  下面的path.jsp與index.jsp都在網站的根目錄:

 1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
 2 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 3 <html>
 4   <head>
 5     <title>path.jsp</title>
 6   </head>
 7   
 8   <body>
 9     <h1>path.jsp</h1>
10     <a href="index.jsp">訪問index.jsp將會出現404錯誤</a>
11   </body>
12 </html>

  接下來咱們進行如下的訪問:

  採用../的形式解決上述問題會很是麻煩。最好的方法是獲取項目的絕對路徑,全部的連接都使用絕對路徑,在path.jsp的連接中進行以下修改:

1 <%
2     String path = request.getContextPath();
3     String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
4 %>
5 
6 <a href="<%=path %>/index.jsp">使用request.getContextPath()解決路徑問題</a>

  或者在html的head標籤中中增長一條base標籤語句:

 1 <%@ page language="java" import="java.util.*" contentType="text/html; charset=utf-8"%>
 2 <%
 3     String path = request.getContextPath();
 4     String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
 5 %>
 6 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
 7 <html>
 8   <head>
 9     <title>path.jsp</title>
10     <base href="<%=basePath%>" />
11     <!-- 有了上面的這句話,全部的連接都會默認加上basepath -->
12   </head>
13   
14   <body>
15     <h1>path.jsp</h1>
16     <a href="index.jsp">index.jsp</a>
17   </body>
18 </html>

動態方法調用(DMI)

  Action執行的時候不必定要執行execute()方法。能夠在配置文件中配置Action的時候用method=來指定執行哪一個方法(產生太多的action),也能夠在url地址中動態指定(DMI)【推薦】。

   假設咱們有如下的Action和Struts配置:

1 public class UserAction extends ActionSupport {
2 
3     public String add() {
4         return SUCCESS;
5     }
6     
7 }
 1 <!-- 注意更改Struts2的常量值爲容許DMI -->
 2 <constant name="struts.enable.DynamicMethodInvocation" value="true" />
 3 <constant name="struts.devMode" value="true" />
 4 <package name="user" extends="struts-default" namespace="/user">
 5     <action name="user" class="org.gpf.struts2.user.action.UserAction">
 6         <result>/User_add_success.jsp</result>
 7     </action>
 8     <action name="Useradd" class="org.gpf.struts2.user.action.UserAction" method="add">
 9          <result>/User_add_success.jsp</result>
10     </action>
11 </package>

  咱們在訪問UserAction的add方法的時候就有兩種方式:①經過UserAdd這個Action的method屬性指定須要訪問的方法;二經過URL參數(!)動態指定。

  當UserAction中新增長了一個方法的時候(例如delete方法,前者須要從新定義一個Userdelete的Action,後者只須要將!後面的參數改爲delete便可)。

通配符設置

  在配置struts的時候使用通配符能夠極大地簡化配置。見如下的例子:

struts.xml

1 <package name="actions" namespace="/actions" extends="struts-default">
2     <!-- method中的{1}表示action的name屬性中的第1個星號 -->
3     <action name="Student*" class="org.gpf.struts2.user.action.StudentAction" method="{1}">
4         <result>/Student{1}_success.jsp</result>
5     </action>
6 </package>

StudentAction:

 1 public class StudentAction extends ActionSupport {
 2 
 3     public String add() {
 4         return SUCCESS;
 5     }
 6     
 7     public String delete(){
 8         return SUCCESS;
 9     }
10 }

在index.jsp中有2個連接:

1 <%
2     String path = request.getContextPath();
3 %>
4 <a href="<%=path%>/actions/Studentadd">添加學生</a>
5 <a href="<%=path%>/actions/Studentdelete">刪除學生</a>

  當咱們訪問添加學生的時候,Studentadd這個Action與action標記中定義的name屬性(Action*)相匹配,此時的*表示的就是add,從而該Action的method就是add,調用StudentAction的add方法,add方法返回"success",從而在result中顯示Student_add_success.jsp(將result中的Student{1}_success.jsp中的{1}用add進行了替換)。

  以上的通配符配置還能夠進一步簡化:

struts.xml

1 <package name="actions" namespace="/actions" extends="struts-default">
2     <action name="*_*" class="org.gpf.struts2.user.action.{1}Action" method="{2}">
3         <result>/{1}_{2}_success.jsp</result>
4     </action>
5 </package>

TeacherAction:

 1 public class TeacherAction extends ActionSupport {
 2 
 3     public String add() {
 4         return SUCCESS;
 5     }
 6     
 7     public String delete(){
 8         return SUCCESS;
 9     }
10 }

  在struts.xml中咱們再也不配置具體的類名和方法名,都使用通配符表示。在上面的配置中action的name有兩個*,action的class屬性是{1},匹配第一個*,action的method屬性匹配第二個*。這樣一來就比較方便。咱們能夠在不改變struts.xml的狀況下爲TeacherAction添加其餘的方法(例如update、query),還能夠添加其餘的Action,例如CourseAction(該Action的名字是*Action)。——採用以上這種方式能夠動態地位Action添加方法,動態添加不一樣的Action(只須要實現約定好jsp頁面、Action的命名規則,3行代碼就能夠搞定Action的配置)。

  約定JSP頁面大寫字母開頭,第一個下劃線以前的內容表示的是Action名,第一個下劃線以後是方法名(與指定的Action中的方法對應);Action的命名大寫字母開頭以Action結尾。

  只要全部的開發人員都遵照以上的規則,struts的配置就很是容易。約定優於配置。

通配符的優先級

  當action中的name能夠匹配多個的時候,優先級是先具體再模糊匹配。即:沒有通配符的先匹配。若是name中有星號則無論星號的多少(即1個星號和2個星號處於1個級別),這時他們的匹配規則取決於在struct.xml中的配置的前後次序。用如下的配置能夠檢測匹配順序:

 1 <package name="actions" namespace="/actions" extends="struts-default">
 2     
 3     <!-- 2個星號 -->
 4     <action name="*_*" class="org.gpf.struts2.user.action.{1}Action" method="{2}">
 5         <result>/Teacher_2_star.jsp</result>
 6     </action>
 7     <!-- 沒有通配符,精確匹配 -->
 8      <action name="Teacher" class="org.gpf.struts2.user.action.StudentAction">
 9          <result>/Teacher_0_star.jsp</result>
10      </action>
11     <!-- 1個星號 -->
12     <action name="Teacher*" class="org.gpf.struts2.user.action.StudentAction" method="{1}">
13         <result>/Teacher_1_star.jsp</result>
14     </action>
15 
16 </package>

  在index.jsp中咱們經過這樣的一個連接來訪問(該連接同時匹配了多個Action)

1 <%
2     String path = request.getContextPath();
3 %>
4 <a href="<%=path%>/actions/Teacher">老師</a>

  總結:匹配規則:先精確匹配,後模糊匹配(一個星號和多個星號處於同一個匹配級別按照struts.xml中的前後順序匹配)。

Action接收參數

  使用Action中與參數匹配的屬性

   例若有如下的struts配置:

1 <!-- 注意更改Struts2的常量值爲容許DMI -->
2 <constant name="struts.enable.DynamicMethodInvocation" value="true" />
3 <constant name="struts.devMode" value="true" />
4 <package name="user" extends="struts-default" namespace="/user">
5     <action name="user" class="org.gpf.struts2.user.action.UserAction">
6         <result>/info.jsp</result>
7     </action>
8 </package>

  UserAction:

 1 package org.gpf.struts2.user.action;
 2 
 3 import com.opensymphony.xwork2.ActionSupport;
 4 
 5 public class UserAction extends ActionSupport {
 6 
 7     private String name;
 8     private int age;
 9 
10     public String getName() {
11         return name;
12     }
13 
14     public void setName(String name) {
15         this.name = name;
16     }
17 
18     public int getAge() {
19         return age;
20     }
21 
22     public void setAge(int age) {
23         this.age = age;
24     }
25 
26     public String add() {
27         System.out.println("name = " + name);
28         System.out.println("age = " + age);
29         return SUCCESS;
30     }
31 
32 }

  在index.jsp中咱們經過如下的方式訪問action:

1 <%
2     String path = request.getContextPath();
3 %>
4 使用action屬性接收參數<a href="<%=path %>/user/user!add?name=張三&age=18">添加用戶</a>

  在index.jsp中咱們使用DMI,先找到/user名稱空間,而後找到名稱爲user的那個Action,並經過DMI調用其add方法。咱們經過URL傳遞參數的時候將name和age傳遞給了該Action。(須要注意的是:在咱們本身的Action中要定義和參數同名的封裝屬性,並寫好它的getter和setter)。Action自動設置屬性是經過setter,其中setXXX中的XXX就是參數的名。也就是說咱們的Action能夠寫成這樣:

 1 public class UserAction extends ActionSupport {
 2 
 3     private String username;
 4 
 5     public String getName() {
 6         return username;
 7     }
 8 
 9     /**
10      * 屬性不必定要和參數匹配,可是setXXX中的XXX必定要和參數匹配
11      */
12     public void setName(String name) {
13         this.username = name;
14     }
15 
16 
17     public String add() {
18         System.out.println("name = " + username);
19         return SUCCESS;
20     }
21 
22 }

  使用DomainModel【經常使用】

  域模型就是在問題域中真正存在的實體的概念,例如一個BBS中的域模型就有:板塊、話題、註冊用戶等。

  域模型User:

 1 package org.gpf.struts2.user.model;
 2 
 3 public class User {
 4 
 5     private String name;
 6     private int age;
 7     private String sex;
 8 
 9     public String getSex() {
10         System.out.println("getSex<--" + sex);
11         return sex;
12     }
13 
14     public void setSex(String sex) {
15         System.out.println("setSex-->" + sex);
16         this.sex = sex;
17     }
18 
19     public String getName() {
20         System.out.println("getName<--" + name);
21         return name;
22     }
23 
24     public void setName(String name) {
25         System.out.println("setName-->" + name);
26         this.name = name;
27     }
28 
29     public int getAge() {
30         System.out.println("getAge<--" + age);
31         return age;
32     }
33 
34     public void setAge(int age) {
35         System.out.println("setAge-->" + age);
36         this.age = age;
37     }
38 
39 }

  UserAction:

 1 package org.gpf.struts2.user.action;
 2 
 3 import org.gpf.struts2.user.model.User;
 4 
 5 import com.opensymphony.xwork2.ActionSupport;
 6 
 7 public class UserAction extends ActionSupport {
 8 
 9     private User user;    // 聲明一個User域模型,Struts2會自動幫咱們new
10     
11     public String getInfo() {
12         System.out.println("域模型傳遞參數name:"+user.getName());
13         System.out.println("域模型傳遞參數age:"+user.getAge());
14         System.out.println("域模型傳遞參數sex:"+user.getSex());
15         return SUCCESS;
16     }
17 
18     // 提供訪問器
19     public User getUser() {
20         System.out.println("getUser");
21         return user;
22     }
23 
24     public void setUser(User user) {
25         System.out.println("setUser");
26         this.user = user;
27     }
28     
29 }

  Struts2配置:

1 <!-- 注意更改Struts2的常量值爲容許DMI -->
2 <constant name="struts.enable.DynamicMethodInvocation" value="true" />
3 <constant name="struts.devMode" value="true" />
4 <package name="user" extends="struts-default" namespace="/user">
5     <action name="user" class="org.gpf.struts2.user.action.UserAction">
6         <result>/info.jsp</result>
7     </action>
8 </package>

  咱們經過如下的連接傳遞參數:

<a href="<%=path%>/user/user!getInfo?user.name=張三&user.age=12&sex=男">使用DomainModel接收參數</a>

  注意:Action中持有與域模型User的一個引用,並提供對該引用的getter和setter。咱們不須要對User對象進行初始化,Struts會默認new出一個對象,在進行URL傳遞參數的時候應該採用域模型對象.屬性的方式。其中域對象的名字和Action中持有的引用名一致。

  ModelDriven傳遞參數

  其餘地方無需改動,將咱們的UserAction實現一個ModelDriven<T>接口:

 1 package org.gpf.struts2.user.action;
 2 
 3 import org.gpf.struts2.user.model.User;
 4 
 5 import com.opensymphony.xwork2.ActionSupport;
 6 import com.opensymphony.xwork2.ModelDriven;
 7 
 8 public class UserAction extends ActionSupport implements ModelDriven<User> {
 9 
10     private User user = new User();  // 這裏的User必須本身new!
11 
12     public String getInfo() {
13 
14         System.out.println("name參數:" + user.getName());
15         System.out.println("age參數:" + user.getAge());
16         System.out.println("sex參數:" + user.getSex());
17         return SUCCESS;
18     }
19 
20     @Override
21     public User getModel() {
22         
23         System.out.println("getModel");
24         return user;
25     }
26 
27 }

  Struts2中的MVC。V就是jsp頁面、M是後臺的那些模型、C就是Action,C控制着V和M之間的通訊(V和M進行了解耦)。

小技巧:struts.xml中的常量配置能夠在/org/apache/struts2/default.properties中找到。

簡單數據驗證

  在UserAction中咱們定義兩個屬性來接收用戶名和密碼參數。在本程序中若是用戶名和密碼都是admin則驗證經過,跳轉到Login_success.jsp,不然跳轉到Login_failure.jsp。struts的配置:

1 <constant name="struts.enable.DynamicMethodInvocation" value="true" />
2 <constant name="struts.devMode" value="true" />
3 <package name="user" extends="struts-default" namespace="/user">
4     <action name="user" class="org.gpf.struts2.user.action.UserAction">
5         <result>/Login_success.jsp</result>                   <!-- 成功轉發至成功頁 -->
6         <result name="error">/Login_failure.jsp</result>    <!-- 失敗轉發至失敗頁 -->
7     </action>
8 </package>
 1 public class UserAction extends ActionSupport{
 2     
 3     private String username;    // 兩個屬性接收用戶名和密碼參數
 4     private String password;
 5     
 6     public String getUsername() {
 7         return username;
 8     }
 9 
10     public void setUsername(String username) {
11         this.username = username;
12     }
13 
14     public String getPassword() {
15         return password;
16     }
17 
18     public void setPassword(String password) {
19         this.password = password;
20     }
21 
22     public String check(){
23         
24         if(!"admin".equals(username) || !"admin".equals(password)){
25             this.addFieldError("errors", "錯誤的用戶名或者密碼!");
26             return ERROR;
27         }
28         return SUCCESS;
29     }
30 }

  在UserAction中咱們經過addFieldError()方法將錯誤信息保存了起來,在前臺頁面可使用struts2提供的標籤庫(<s:fielderror>)將錯誤信息顯示出來:

  PS:J2EE5以後不須要將標籤的tld文件放在本身的WEB-INF目錄,只要jar包中有會自動搜索。

1 登陸失敗!
2 <%@taglib prefix="s" uri="/struts-tags"%>
3 <s:fielderror fieldName="errors"></s:fielderror><br />

  以上的標籤給咱們強加了一個ul>li和errorMessage的CSS類,用戶定製不好,咱們可使用<s:debug>在頁面上打印Struts 的Value Stack(各類各樣的錯誤),使用<s:property>標籤能夠取出Value Stack Contents和Stack Context(其實就是Action Context)中的屬性。在Login_failure.jsp中咱們這樣寫:

1 登陸失敗!<br />
2 <%@taglib prefix="s" uri="/struts-tags"%>
3 <s:property value="errors.errors[0]"/>        <!-- OGNL表達式 -->
4 <s:debug></s:debug>

  取出了錯誤信息咱們就能夠本身進行樣式的設置了。

訪問Web元素

  其實主要就是使用Action取得Map類型的request、session、application以及真實類型HttpServletRequest、HttpSession、ServletContext。由於咱們的結果是經過result返回出去的,因此但對於response咱們能夠無論。

index.jsp

 1 取得Map類型request,session,application,真實類型 HttpServletRequest,HttpSession, ServletContext的引用:
 2 <ol>
 3     <li>前三者:依賴於容器</li>
 4     <li>前三者:IOC</li> (只用這種)
 5     <li>後三者:依賴於容器</li>
 6     <li>後三者:IOC</li>
 7 </ol>
 8 <br />
 9 <form name="f" action="" method="post">
10     用戶名:<input type="text" name="name" /> 
11     密碼:<input type="text" name="password" /> <br />
12     <input type="button" value="submit1"
13         onclick="javascript:document.f.action='login/login1';document.f.submit();" />
14     <input type="button" value="submit2"
15         onclick="javascript:document.f.action='login/login2';document.f.submit();" />
16     <input type="button" value="submit3"
17         onclick="javascript:document.f.action='login/login3';document.f.submit();" />
18     <input type="button" value="submit4"
19         onclick="javascript:document.f.action='login/login4';document.f.submit();" />
20 </form>

  在index.jsp中咱們經過javascript代碼動態指定表單提交的Action。這樣咱們就能夠經過多個按鈕提交同一個表單。struts.xml中Action的配置以下(經過通配符動態指定):

1 <constant name="struts.enable.DynamicMethodInvocation" value="true" />
2 <constant name="struts.devMode" value="true" />
3 <package name="login" extends="struts-default" namespace="/login">
4     <action name="login*" class="org.gpf.struts2.user.action.LoginAction{1}">
5         <result>/Login_success.jsp</result>
6     </action>
7 </package>

方式一:依靠ActionContext獲取Map

LoginAction1.java

 1 public class LoginAction1 extends ActionSupport{
 2     
 3     private Map request;
 4     private Map session;
 5     private Map application;
 6     
 7     /**
 8      * 經過ActionContext.getContext()方法
 9      * 在構造器中爲request、session和application初始化
10      */
11     public LoginAction1() {
12         request = (Map) ActionContext.getContext().get("request");
13         session = ActionContext.getContext().getSession();
14         application = ActionContext.getContext().getApplication();
15     }
16     
17     public String execute(){
18         
19         // 向request、session和application的Map中設置內容
20         request.put("r1", "r1");
21         session.put("s1", "s1");
22         application.put("a1", "a1");
23         return SUCCESS;
24     }
25 }

  在Login_success.jsp中咱們將request、session、application範圍內設置的屬性取出:

 1 登陸成功!
 2 <%@taglib prefix="s" uri="/struts-tags"%>
 3 <s:debug></s:debug>
 4 <table>
 5     <tr>
 6         <th>經過ValueStack取得Web元素中的內容</th>
 7         <th>經過3種屬性範圍取得Web元素中的內容</th>
 8     </tr>
 9     <tr>
10         <td>取得request</td>
11         <td><s:property value="#request.r1"/></td>
12         <td><%=request.getAttribute("r1") %></td>
13     </tr>
14     <tr>
15         <td>取得session</td>
16         <td><s:property value="#session.s1"/></td>
17         <td><%=session.getAttribute("s1") %></td>
18     </tr>
19     <tr>
20         <td>取得application</td>
21         <td><s:property value="#application.a1"/></td>
22         <td><%=application.getAttribute("a1") %></td>
23     </tr>
24 </table>

  經過debug標記,咱們能夠發如今StackContext(也就是ActionContext)中存在request、session、application3個鍵,而咱們爲其設置的值r一、s1和a1則保存在它們的Value中(Value也是Map)。因此咱們能夠在LoginAction1中經過ActionContext.getContext().get("request")等方法獲取對應的Map集合。

  

  除了可使用#session.屬性名、#request.屬性名、#application.屬性名訪問咱們設置在這3種屬性範圍以內的屬性之外,咱們還可使用#attr.屬性名的方式自動搜索匹配屬性名的字段:

1 <s:property value="#attr.r1"/>
2  <s:property value="#attr.s1"/>
3  <s:property value="#attr.a1"/>

  可是開發中這3種屬性範圍以內的屬性應該是精肯定位的,不該該依靠自動搜索範圍是從request到application(由於可能有重名屬性)。

方式二:經過IoC得到Map(常用)

  該種方式須要實現XXXaware接口。aware的意思是得知、得到。

 1 /**
 2  * LoginAction2實現了RequestAware,SessionAware,ApplicationAware接口
 3  */
 4 public class LoginAction2 extends ActionSupport implements RequestAware,SessionAware,ApplicationAware{
 5 
 6     private Map<String, Object> request;  // 依賴外界的環境把值注給咱們,而不是咱們本身主動拿
 7     private Map<String, Object> session;
 8     private Map<String, Object> application;
 9     
10     public String execute(){
11         request.put("r1", "r1");
12         session.put("s1", "s1");
13         application.put("a1", "a1");
14         return SUCCESS;
15     }
16     
17     @Override
18     public void setApplication(Map<String, Object> application) {
19         
20         this.application = application;
21     }
22 
23     @Override
24     public void setSession(Map<String, Object> session) {
25         
26         this.session = session;
27     }
28 
29     @Override
30     public void setRequest(Map<String, Object> request) {
31         
32         this.request = request;
33     }
34 
35 }

  IoC(Inverse of Control,控制反轉)也叫作DI(dependency injection,依賴注入)。

  所謂依賴注入就是咱們在LoginAction2中的3個屬性依賴Struts2將值傳給咱們而不是咱們本身主動取得值。所謂控制反轉就是原先咱們須要本身控制3個屬性的值(獲取),而如今3個屬性的值交給Struts2容器進行。以上的2個概念在Spring中大量應用——咱們本身定義的成員變量歷來不初始化而是交給Spring進行初始化,Spring是經過配置文件的方式進行的初始化。

 方式三:經過ServletActionContext獲取真實類型

  前面獲取的方式都是獲取的Map,若是想要得到HttpServletRequest、HttpSession、ServletContext可使用下面的方法:

 1 public class LoginAction3 extends ActionSupport {
 2 
 3     private HttpServletRequest request;
 4     private HttpSession session;
 5     private ServletContext application;
 6     
 7     public LoginAction3() {
 8         
 9         request = ServletActionContext.getRequest();
10         session = request.getSession();
11         application = ServletActionContext.getServletContext();
12     }
13     
14     public String execute(){
15 
16         request.setAttribute("r", "r");
17         session.setAttribute("s", "s");
18         application.setAttribute("a", "a");
19         return SUCCESS;
20     }
21     
22 }

  方式四:經過Ioc取得真實類型

 1 public class LoginAction4 extends ActionSupport implements ServletRequestAware {
 2 
 3     private HttpServletRequest request;
 4     private HttpSession session;
 5     private ServletContext application;
 6     
 7     @Override
 8     public void setServletRequest(HttpServletRequest request) {
 9 
10         this.request = request;
11         this.session = request.getSession();
12         this.application = request.getServletContext();
13     }
14 
15     public String execute(){
16         
17         request.setAttribute("r", "r");
18         session.setAttribute("s", "s");
19         application.setAttribute("a", "a");
20         return SUCCESS;
21     }
22 }

模塊包含

  通常來講struts.xml中配置的是全部struts的公共配置,將具體的業務劃分紅模塊。例如:登陸模塊、退出模塊。

struts.xml

 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 
 6 <struts>
 7     <!-- 公共配置 -->
 8     <constant name="struts.enable.DynamicMethodInvocation" value="true" />
 9     <constant name="struts.devMode" value="true" />
10 
11     <!-- 如下是模塊的劃分 -->
12     <include file="login.xml"></include>
13     <include file="logout.xml"></include>
14     
15 </struts>

login.xml

<?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="login" extends="struts-default" namespace="/login">
        <action name="login*" class="org.gpf.struts2.user.action.LoginAction{1}">
            <result>/Login_success.jsp</result>
        </action>
    </package>
</struts>

logout.xml

 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE struts PUBLIC
 3     "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
 4     "http://struts.apache.org/dtds/struts-2.3.dtd">
 5 <struts>    
 6     <package name="logout" extends="struts-default" namespace="/loginlogout">
 7         <action name="logout*" class="org.gpf.struts2.user.action.LogoutAction{1}">
 8             <result>/Logout_success.jsp</result>
 9         </action>
10     </package>
11 </struts>

  此種方式能夠進行模塊的劃分,項目組的各個成員各自開發,最後在struts.xml中進行全部模塊的整合。

默認Action

  當訪問的Action不存在的時候咱們能夠經過如下的方式交給默認的Action處理:

1 <package name="default" extends="struts-default" namespace="/">
2     <!-- 當找不到Action的時候跳到默認的Action -->
3     <default-action-ref name="index"></default-action-ref>
4     <action name="index">
5         <result>/default.jsp</result>
6     </action>
7 </package>

  例如:在瀏覽網站的時候有時候出現的404錯誤就能夠交給默認Action處理,默認Action能夠跳轉到網站的主頁提升用戶體驗。

相關文章
相關標籤/搜索