Struts2入門這一篇就夠了

Java3y發表於2018-03-10

前言

這是Strtus的開山篇,主要是引入struts框架...為什麼要引入struts,引入struts的好處是什麼,以及對Struts2一個簡單的入門....

為什麼要引入struts?

既然Servlet能夠完成的事,我們為啥要用框架呢??

  • 框架幫我們封裝了很多常用的功能
    • 把Web帶過來的引數自動封裝到JavaBean中[以前,我們剛開始學的時候是單個單個來獲取引數的,後來我們又使用了BeanUtils寫工具方法來幫我們封裝]。現在,我們使用了Struts2的話,那麼框架內部就能幫我們封裝了。
  • 更加靈活[不用把路徑等資訊寫死在程式上],對於路徑我們使用配置檔案來進行管理,如果目錄發生了變化,也不用一個一個去修改每個程式的路徑。
  • 每個Servlet中都有doGet和doPost這樣的方法,沒必要的。我們抽取出來,通過配置檔案來把這兩個方法替換掉,那麼我們的程式就會更加優雅了。

於是乎,struts2就應運而生了。


自定義struts

在正式講解struts之前,我們來看一下,以我們現在的水平,能夠怎麼優化它。。

以使用者的登陸註冊案例來進行說明

傳統的使用者登陸註冊

  • dao
public class UserDao {

    public User login(User user) {

        if ("aaa".equals(user.getUsername()) && "123".equals(user.getPsd())) {

            System.out.println("登陸成功!");
            return user;

        } else {
            System.out.println("登陸失敗!");
            return null;
        }
    }

    public void register(User user) {

        System.out.println("註冊成功!" + user.getUsername());
    }


}
複製程式碼
  • service

public class UserService {

    private UserDao userDao = new UserDao();

    public User longin(User user) {
        return userDao.login(user);
    }

    public void register(User user) {
        userDao.register(user);
    }

}
複製程式碼
  • loginServlet

@javax.servlet.annotation.WebServlet(name = "LoginServlet",urlPatterns = "/LoginServlet")
public class LoginServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到使用者帶過來的資料,封裝到Bean物件中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //呼叫Service方法
            UserService userService = new UserService();
            userService.longin(user);

            //登陸成功跳轉到首頁
            request.getRequestDispatcher("/index.jsp").forward(request, response);

        } catch (Exception e) {
            e.printStackTrace();

            //登陸失敗,跳轉到相關的提示頁面
            request.setAttribute("message","登陸失敗了!!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        this.doPost(request, response);

    }
}

複製程式碼
  • registerServlet

@javax.servlet.annotation.WebServlet(name = "RegisterServlet",urlPatterns = "/RegisterServlet")
public class RegisterServlet extends javax.servlet.http.HttpServlet {
    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到使用者帶過來的資料,封裝到Bean物件中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //呼叫Service方法
            UserService userService = new UserService();
            userService.register(user);

            //註冊成功跳轉到登陸介面
            request.getRequestDispatcher("/login.jsp").forward(request, response);

            //註冊成功,我也可以跳轉到首頁
            //request.getRequestDispatcher("/index.jsp").forward(request, response);

        } catch (Exception e) {
            e.printStackTrace();

            //註冊失敗,跳轉到相關的提示頁面
            request.setAttribute("message","註冊失敗了!!!");
            request.getRequestDispatcher("/message.jsp").forward(request, response);
        }

    }

    protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        this.doPost(request, response);

    }
}
複製程式碼
  • login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>


  <form action="${pageContext.request.contextPath}/LoginServlet" method="post">

    使用者名稱:<input type="text " name="username">
    密碼:<input type="password " name="psd">
    <input type="submit" value="登陸">
  </form>
  </body>
</html>

複製程式碼
  • register.jsp
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
  </head>
  <body>


  <form action="${pageContext.request.contextPath}/RegisterServlet" method="post">

    使用者名稱:<input type="text " name="username">
    密碼:<input type="password " name="psd">
    <input type="submit" value="註冊">
  </form>
  </body>
</html>
複製程式碼

上面的程式碼已經經過了測試,是可以跑起來的。


①:跳轉頁面的路徑是寫死的。我在註冊成功了以後,我可以跳轉到首頁上,也可以跳轉到登陸的介面上。如果我要選擇其中的一個,就必須修改原始碼...

②:一個功能對應一個Servlet,太麻煩了...寫了LoginServlet,還要寫RegisterServlet....


新型的使用者登陸註冊

我們會發現,無論什麼Servlet上最終還是跳轉到相對應的JSP頁面的...也就是說,第一和第二步驟【封裝資料、呼叫Service】我們可以封裝起來...只要返回uri給Servlet跳轉到JSP頁面就好了


LoginAction

返回的uri分兩種情況:

  • 如果是轉發,那麼返回的是RequestDispatcher物件
  • 如果是重定向,那麼返回的是字串

/**
 * Created by ozc on 2017/4/26.
 * <p>
 * 一個Action對應一個Servlet,Action負責處理具體的請求
 */
public class LoginAction {


    public Object login(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        Object uri ;

        //得到使用者帶過來的資料,封裝到Bean物件中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //呼叫Service方法
            UserService userService = new UserService();
            userService.longin(user);

            //登陸成功跳轉到首頁
            request.getSession().setAttribute("user", user);

            //跳轉到首頁的時候需要重定向
            //response.sendRedirect(request.getContextPath() + "/index.jsp");

            //如果是重定向,那麼返回的是字串
            uri = "/index.jsp";
            return uri;

        } catch (Exception e) {
            e.printStackTrace();

            //登陸失敗,跳轉到相關的提示頁面
            request.setAttribute("message","登陸失敗了!!!");
            //request.getRequestDispatcher("/message.jsp").forward(request, response);

            //如果是轉發,那麼返回的是RequestDispatcher物件
            uri = request.getRequestDispatcher("/message.jsp");
            return uri;
        }
    }
}

複製程式碼
  • LoginServlet就可以寫成這樣了:

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到LoginAction物件
        LoginAction loginAction = new LoginAction();
        Object uri = loginAction.login(request, response);


        //是重定向
        if (uri instanceof String) {
            response.sendRedirect(request.getContextPath() + uri);
        } else {

            //是轉發,強轉成是RequestDispatcher物件
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

複製程式碼

RegisterAction

  • RegisterAction


/**
 * Created by ozc on 2017/4/26.
 * 
 * 一個Action對應一個Servlet,Action負責處理具體的請求
 */
public class RegisterAction {


    public Object register(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        Object uri ;

        //得到使用者帶過來的資料,封裝到Bean物件中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

        User user = new User();
        user.setPsd(psd);
        user.setUsername(username);

        try {
            //呼叫Service方法
            UserService userService = new UserService();
            userService.register(user);

            //登陸成功跳轉到登陸頁面
            uri = request.getRequestDispatcher("/login.jsp");
            return uri;

        } catch (Exception e) {
            e.printStackTrace();

            //註冊失敗,跳轉到相關的提示頁面
            request.setAttribute("message","註冊失敗了!!!");
            //request.getRequestDispatcher("/message.jsp").forward(request, response);

            uri = request.getRequestDispatcher("/message.jsp");
            return uri;
        }
    }
}

複製程式碼
  • RegisterServlet

    protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException {

        //得到RegisterAction
        RegisterAction registerAction = new RegisterAction();

        Object uri = registerAction.register(request, response);

        //是重定向
        if (uri instanceof String) {
            response.sendRedirect(request.getContextPath() + uri);
        } else {

            //是轉發,強轉成是RequestDispatcher物件
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

複製程式碼

思考

到目前為止,我們搞了兩個Action類來封裝Servlet的邏輯程式碼,我們再次看回Servlet的程式碼。

這裡寫圖片描述

這裡寫圖片描述

可以很清楚地發現:兩個實現不同功能的Servlet僅僅是呼叫的Action不同....如果是僅僅呼叫的Action不同【通過反射來呼叫不同的Action】,那麼我們應該**想到使用一個Servlet來管理整個專案,**也就是說:整個web專案只有一個核心的控制器

問題:

①:我們在之前是直接指明Servlet的對映路徑了,現在要ActionServlet處理所有的請求,我們只要定一個規則:只要字尾為.action的,那麼都交由核心控制器ActionServlet來控制....

②:現在全部的請求已經交由ActionServlet控制,那怎麼知道呼叫的是哪個Action???我們可以通過請求的uri,比如:http://localhost:8080/login.action,其中login就代表的是呼叫LoginAction..也就是說login=LoginAction,我們可以通過properties檔案來配置..

③:現在我們已經知道了呼叫的是哪個Action了,但是Action可能不僅僅只有一個方法,我們還要在呼叫的時候,指定的方法名是什麼.這很簡單,一般我們都是職責分工明確的,method=login....並且,呼叫的Action和具體的方法也是有關係的,不可能是孤立存在的。因此,我們的配置檔案是不能使用properties的,需要使用XML

④:在呼叫方法的時候,是返回一個Object的uri的,uri的型別可能是String、也可以能是RequestDispatcher、並且返回的結果可能有幾種情況的【可能跳轉到首頁,也可能跳轉到登陸介面】

⑤:Action呼叫的方法和返回的uri也是是有關係的!.....不同的Action呼叫不同的方法,返回的uri也是不同的....

⑥:要跳轉到哪個頁面上,可以通過標識量來識別....比如:success表示成功執行,如果要重定向那麼多加個type型別,如果不重定向就沒有type型別..路徑使用path來表示..因此,在具體的Action中,就不需要返回具體的uri,只要返回一個標識量即可


畫一張圖來梳理一下思路:

這裡寫圖片描述


XML配置

我們可以寫出這樣的XML配置,當ActionServlet初始化的時候,讀取XML配置檔案,就知道呼叫的是什麼Action,Action中的什麼方法,以及跳轉到哪個頁面上了

<?xml version="1.0" encoding="UTF-8" ?>
<mystruts>
    <package>

        <action name="login" className="zhongfucheng.servlet.LoginServlet" method="login">
            <!--是否存在type屬性,存在則是重定向,不存在則是轉發-->
            <!--result的值表示的就是跳轉的路徑-->
            <result name="success" type="redirect">/index.jsp</result>
            <result name="fail">/message.jsp</result>

        </action>
        <action name="register" className="zhongfucheng.servlet.RegisterServlet" method="register">
            <!--是否存在type屬性,存在則是重定向,不存在則是轉發-->
            <!--result的值表示的就是跳轉的路徑-->
            <result name="success">/message.jsp</result>
            <result name="fail">/message.jsp</result>
        </action>
    </package>

</mystruts>
複製程式碼

為了更好地管理這些資訊,我們應該使用JavaBean來對它們封裝

  • ActionMappingManager-------管理全部的Action
/**
 * Created by ozc on 2017/4/26.
 * 
 * 該類管理著全部的Action
 *
 * 要管理全部的Action,就需要用一個容器來裝載這些Action
 *
 * 選擇Map集合是最合適的,可以通過key來得到Action,key就是<action name=><action/>中的name屬性
 *
 */
public class ActionMappingManager {

    private Map<String, ActionMapping> map = new HashMap<>();
    
    //注意:外界都是通過name來得到對應的Action的,並不會獲取得到整個Manager
    public ActionMapping getActionMapping(String name) {
        return map.get(name);
    }

}

複製程式碼
  • ActionMapping----表示單個的Action

public class ActionMapping {

    //所有的results
    private Map<String, Results> results;

    //關鍵字name
    private String name;

    //要呼叫的Action路徑
    private String className;

    //Action中的方法
    private String method;

    public Map<String, Results> getResults() {
        return results;
    }

    public void setResults(Map<String, Results> results) {
        this.results = results;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethod() {
        return method;
    }

    public void setMethod(String method) {
        this.method = method;
    }
}

複製程式碼
  • Results---表示的是結果檢視


/**
 * Created by ozc on 2017/4/26.
 *
 * 該類表示的是結果檢視
 *
 *
 *
 */
public class Results {

    //方法返回的標識
    private String name;

    //要跳轉的方式
    private String type;

    //要跳轉的頁面
    private String page;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public String getPage() {
        return page;
    }

    public void setPage(String page) {
        this.page = page;
    }
}

複製程式碼

ActionMappingManager讀取配置檔案

在ActionMappingManager中,應該讀取配置檔案,然後把資訊全部封裝到裡邊去...


/**
 * Created by ozc on 2017/4/26.
 *
 * 該類管理著全部的Action
 *
 * 要管理全部的Action,就需要用一個容器來裝載這些Action
 *
 * 選擇Map集合是最合適的,可以通過key來得到Action,key就是<action name=><action/>中的name屬性
 *
 */
public class ActionMappingManager {
    private Map<String, ActionMapping> allAction ;

    public ActionMappingManager() {
        this.allAction = new HashMap<>();

        //讀取配置檔案資訊
        init();

    }


    public void init() {
        /********通過DOM4J讀取配置檔案資訊*********/

        try {
            //得到解析器
            SAXReader saxReader = new SAXReader();

            //讀取在類目錄下的mystruts.xml檔案
            InputStream stream = ActionMappingManager.class.getClassLoader().getResourceAsStream("mystruts.xml");

            //得到代表XML檔案的Document物件
            Document document = saxReader.read(stream);

            //通過XPATH直接得到所有的Action節點
            List list = document.selectNodes("//action");

            //得到每個Action節點
            for (int i = 0; i < list.size(); i++) {
                Element action = (Element) list.get(i);

                //把得到每個Action的節點資訊封裝到ActionMapping中
                ActionMapping actionMapping = new ActionMapping();

                String name = action.attributeValue("name");
                String method = action.attributeValue("method");
                String className = action.attributeValue("className");
                actionMapping.setName(name);
                actionMapping.setMethod(method);
                actionMapping.setClassName(className);

                //得到action節點下的所有result節點
                List results = action.elements("result");

                //得到每一個result節點
                for (int j = 0; j < results.size(); j++) {
                    Element result = (Element) results.get(j);

                    //把得到每個result節點的資訊封裝到Results中
                    Results results1 = new Results();

                    //得到節點的資訊
                    String name1 = result.attributeValue("name");
                    String type = result.attributeValue("type");
                    String page = result.getText();

                    results1.setName(name1);
                    results1.setType(type);
                    results1.setPage(page);

                    //把result節點新增到ActionMapping的集合中
                    actionMapping.getResults().put(name1, results1);
                }

                //最後把得到每個ActionMapping的資訊新增到ActionMappingManager中
                allAction.put(name, actionMapping);

            }



        } catch (DocumentException e) {

            new RuntimeException("初始化的時候出錯了!“" + e);
        }
    }

    //注意:外界都是通過name來得到對應的Action的,並不會獲取得到整個Manager
    public ActionMapping getActionMapping(String name) {
        return allAction.get(name);
    }
}

複製程式碼

ActionServlet

使用init()方法只載入建立一個ActionManagerMapping物件,並設定在Web容器啟動了該Servlet就啟動


/**
 * Created by ozc on 2017/4/26.
 *
 *
 * Web容器一啟動的時候,該類就應該載入了,在web.xml檔案中配置onloadStart
 */

public class ActionServlet extends HttpServlet {


    //該物件封裝了所有的XML資訊
    ActionMappingManager actionMappingManager ;
    @Override
    public void init() throws ServletException {

        //讓ActionMappingManager物件只有一個!
        actionMappingManager = new ActionMappingManager();
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        try {
            //得到使用者的uri
            String uri = request.getRequestURI();

            //擷取uri的關鍵部分-----截完應該是login
            uri = uri.substring(uri.lastIndexOf("/") + 1, uri.lastIndexOf("."));

            //通過uri得到配置檔案中的action資訊
            ActionMapping actionMapping = actionMappingManager.getActionMapping(uri);

            //得到action的類名,方法名
            String className = actionMapping.getClassName();
            String method = actionMapping.getMethod();

            //通過反射建立出Action的物件,呼叫對應的方法
            Class t = Class.forName(className);
            Object o = t.newInstance();

            //注意:這裡的引數是介面的class,不是單純的request的class,單純的class是實現類
            Method m = t.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            //呼叫方法,得到標記
            String returnFlag = (String) m.invoke(o, request, response);


            //通過標記得到result的具體資訊
            Results result = actionMapping.getResults().get(returnFlag);
            String type = result.getType();
            String page = result.getPage();

            //判斷是重定向還是轉發,為空就是轉發,反則是重定向
            if (type == null) {
                response.sendRedirect(page);
            } else {
                request.getRequestDispatcher(request.getContextPath() + page).forward(request, response);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        this.doPost(request, response);

    }
}
複製程式碼

具體的Action的方法只要返回一個標識量即可,我們通過標識量來得到具體的跳轉頁面url和跳轉的方法的。。。


效果:

這裡寫圖片描述


自定義MyStruts總結:

由於傳統web的Controller模組存在弊端:

  • 一些功能重複使用,程式碼過於重複了。
  • 跳轉的頁面寫死了。改變需求的時候需要更改原始碼

本博文主要模擬Struts的開發流程

  • 使用一個ActionServlet核心控制器來管理全部的Web請求,寫XML配置檔案,讀取配置檔案。
  • ActionMapping封裝了Action的基本資訊,在XML配置檔案中就是讀取Action的基本資訊,封裝到JavaBean上,最後使用ActionMapping類的集合統一管理起來。
  • 當使用者訪問的時候,我們根據url也就是Action的名稱反射出對應的類,來對其進行操作
  • 根據XML檔案的配置資訊來確定跳轉方法、跳轉的url

我們現在學習的是Struts2,其實Struts1和Struts2在技術上是沒有很大的關聯的。 Struts2其實基於Web Work框架的,只不過它的推廣沒有Struts1好,因此就拿著Struts這個名氣推出了Struts2框架。

因此,學習Struts2的時候,不瞭解Struts1是沒有任何關係的。

在前面,已經說明了為什麼要引入Struts框架,其實就是為了提高開發效率...

Struts2框架預先實現了一些功能:

  • 請求資料自動封裝
  • 檔案上傳的功能
  • 對國際化功能的簡化
  • 資料效驗功能.......等等

Struts2開發步驟

我們就直接來講解Struts2的開發步驟是什麼吧....在瞭解它的細節之前,先要把配置環境搭好!

引入jar檔案

完整的struts中的jar包有80多個,我們日常開發是不需要那麼多個的。一般我們匯入的jar包有8個:

  • commons-fileupload-1.2.2.jar 【檔案上傳相關包】
  • commons-io-2.0.1.jar【檔案上傳相關包】
  • struts2-core-2.3.4.1.jar 【struts2核心功能包】
  • xwork-core-2.3.4.1.jar 【Xwork核心包】
  • ognl-3.0.5.jar 【Ognl表示式功能支援表】
  • commons-lang3-3.1.jar 【struts對java.lang包的擴充套件】
  • freemarker-2.3.19.jar 【struts的標籤模板庫jar檔案】
  • javassist-3.11.0.GA.jar 【struts對位元組碼的處理相關jar】

這裡寫圖片描述


配置web.xml

在web.xml中配置的過濾器,其實就是在為struts進行初始化工作

值得注意的是:如果該web.xml配置了多個fileter,那麼struts的filter需要在最後面!


<!-- 引入struts核心過濾器 -->
	<filter>
		<filter-name>struts2</filter-name>
		<filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>struts2</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>

複製程式碼

開發Action

開山篇我們已經說了,Servlet的業務程式碼,我們都使用Action來代替...Action類一般繼承著ActionSupport

Action類也叫動作類,處理請求的類。


public class HelloAction extends ActionSupport {

    @Override
    public String execute() throws Exception {

        System.out.println("helloworld");
        
        return "success";
    }
}

複製程式碼

至於execute()方法是什麼,我們先不要去管它,為啥要返回一個String,我們也不要去管它....只要記住開發步驟,並且,我們的Action類是要繼承ActionSupport類的

配置struts.xml

至於配置struts.xml,我們可以在檔案中找到相對應的模版程式碼的...最終修改成下面這個樣子就行了:


<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE struts PUBLIC
                "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
                "http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<package name="hello" extends="struts-default">
    <action name="hello" class="action.HelloAction" method="execute">
        <result name="success">/index.jsp</result>

    </action>
</package>
</struts>

複製程式碼

看完上面的配置檔案,是非常像我們開山篇寫的struts框架的配置檔案的....

效果:

在位址列中直接輸入hello,就跳轉到index.jsp頁面了。並且,execute()中的語句被執行了...

這裡寫圖片描述


Struts2執行流程

我們來簡單地瞭解一下Struts的執行流程,然後再慢慢對上面的開發步驟的部分進行講解....

伺服器啟動

下邊我說的都是struts流程的重點:

  • 載入web.xml檔案
  • 找到我們配置的filter中的StrutsPrepareAndExecuteFilter
  • StrutsPrepareAndExecuteFilter在裡邊執行init()方法
  • 一直到Dispatcher dispatcher = init.initDispatcher(config);,初始化dispatcher
  • 在初始化dispatcher的時候載入struts-default.xml和我們配置的struts.xml

下面用GIF圖來看看它的執行過程:

這裡寫圖片描述

細心的朋友可能會發現,我們在struts.xml的package節點下,extends了struts-default....那struts-default究竟是什麼東西呢?

我們找到它的原始碼:

這裡寫圖片描述

我們發現了一大堆的Bean,interceptor,result-type,interceptor-stack...下邊我來講解一下它們是幹嘛用的...

  • bean指定了struts在執行的時候需要建立的物件型別
    • 在執行struts的時候,可能需要建立一些物件,那麼就通過Bean來指定
  • interceptor是struts定義的攔截器,一共有32個
    • 前邊已經說了,Struts為我們實現了一些功能,就是通過攔截器來實現的
  • result-type是跳轉結果的型別
    • Action業務方法中的返回值,我們發現幾個實用的:redirect【重定向】、dispatcher【轉發】、redirectAction【重定向到Action資源】、stream【檔案下載的時候用】...跳轉結果的型別也在這裡定義了
  • interceptor-stack是攔截器的棧
    • 攔截器有32個,我們可能會使用很多的攔截器,不可能一個一個來呼叫,於是提供了攔截器棧...其實可以簡單看成**資料夾和檔案之間的關係 **
  • default-interceptor-ref是預設執行的攔截器棧
  • default-class-ref class是預設的執行Action類

還要補充的就是:預設的攔截器棧有18個攔截器....


攔截器和過濾器

攔截器和過濾器都是攔截資源的

攔截器只攔截Action請求,是struts的概念...

過濾器攔截web的所有資源,是Servlet的概念...


小總結

伺服器啟動的時候,其實就是載入了web.xml檔案,然後呼叫init()方法去載入struts.xml和struts-default.xml之類的檔案.....

注意:此時的攔截器是還沒有被呼叫的


訪問階段

伺服器啟動的階段,僅僅是載入了各種的xml檔案...那麼當我們訪問Action的時候,它的執行流程是怎麼的呢?

  • 首先,它會建立我們在struts.xml中配置的Action物件
  • 接著,它會按照預設的順序執行18個攔截器【也就是呼叫預設攔截器棧】
  • 最後,它會執行Action的業務方法【也就是execute(),我們在struts.xml檔案中配置了什麼,就執行什麼業務方法】

值得注意的是:每訪問Action一次,它就會建立一個物件...它並不是和Servlet一樣只有一個物件...因此它是執行緒安全的.


深入講解struts.xml

這是我們的struts.xml的內容,相信現在對它也不會太陌生了...


<struts>
<package name="hello" extends="struts-default">
    <action name="hello" class="action.HelloAction" method="execute">
        <result name="success">/index.jsp</result>
    </action>
</package>
</struts>


複製程式碼

package

package其實就是包,那包用來幹什麼?包就是用來管理Action

通常來說,我們都是一個業務模版對應一個package

name

name是包的名字,值得注意的是,包的名稱是不能重複的。


extends

extends代表的是當前包繼承著哪個包。在struts中,包一定要繼承著struts-default


abstract

在package中還有abstract這個屬性,使用該屬性時:表明當前包被其他的包繼承...並且,在package下不能有action,否則會出錯!


namespace

在package中還有namespace這個屬性---名稱空間....它是作為路徑的一部分的,預設是"/"


actoin

action:配置請求路徑與Action類的對映關係


name

name是請求路徑的名字


class

class是處理action類的全名


method

method是呼叫的方法名稱


result

result代表的是Action中業務方法返回的值


name

name是action處理返回的值


type

type是跳轉的型別


文字值

文字值是跳轉的路徑


細節

前邊已經說了,一個package應該對應一個業務模組..目的就是把職能細分出來...

struts為了讓我們更好地管理xml檔案,它還可以這樣做:在不同的模組中用不同的xml檔案進行描述...

這裡寫圖片描述

最後在struts.xml檔案中將其引入即可..


<!--struts在執行的時候總會載入這個檔案-->
<!--總配置檔案總引入其他的檔案-->
<struts>
    <include file="privilegeaction/privilege.xml"/>
    <include file="useraction/hello.xml"/>
</struts>

複製程式碼

如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y

相關文章