Struts2入門這一篇就夠了

前言

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

為什么要引入struts易稠?

既然Servlet能夠完成的事驶社,我們?yōu)樯兑每蚣苣兀浚?/p>

  • 框架幫我們封裝了很多常用的功能
    • 把Web帶過來的參數(shù)自動封裝到JavaBean中[以前,我們剛開始學的時候是單個單個來獲取參數(shù)的或辖,后來我們又使用了BeanUtils寫工具方法來幫我們封裝]。現(xiàn)在,我們使用了Struts2的話,那么框架內(nèi)部就能幫我們封裝了妓肢。
  • 更加靈活[不用把路徑等信息寫死在程序上]纲缓,對于路徑我們使用配置文件來進行管理,如果目錄發(fā)生了變化,也不用一個一個去修改每個程序的路徑陆蟆。
  • 每個Servlet中都有doGet和doPost這樣的方法惋增,沒必要的叠殷。我們抽取出來,通過配置文件來把這兩個方法替換掉诈皿,那么我們的程序就會更加優(yōu)雅了林束。

于是乎,struts2就應(yīng)運而生了纫塌。


自定義struts

在正式講解struts之前,我們來看一下怎披,以我們現(xiàn)在的水平毫胜,能夠怎么優(yōu)化它口渔。。

以用戶的登陸注冊案例來進行說明

傳統(tǒng)的用戶登陸注冊

  • 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 {

        //得到用戶帶過來的數(shù)據(jù)氛濒,封裝到Bean對象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

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

        try {
            //調(diào)用Service方法
            UserService userService = new UserService();
            userService.longin(user);

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

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

            //登陸失敗执桌,跳轉(zhuǎn)到相關(guān)的提示頁面
            request.setAttribute("message","登陸失敗了!M鑫省!");
            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 {

        //得到用戶帶過來的數(shù)據(jù),封裝到Bean對象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

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

        try {
            //調(diào)用Service方法
            UserService userService = new UserService();
            userService.register(user);

            //注冊成功跳轉(zhuǎn)到登陸界面
            request.getRequestDispatcher("/login.jsp").forward(request, response);

            //注冊成功睦优,我也可以跳轉(zhuǎn)到首頁
            //request.getRequestDispatcher("/index.jsp").forward(request, response);

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

            //注冊失敗癌椿,跳轉(zhuǎn)到相關(guān)的提示頁面
            request.setAttribute("message","注冊失敗了4喽 !!");
            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>

上面的代碼已經(jīng)經(jīng)過了測試,是可以跑起來的。


①:跳轉(zhuǎn)頁面的路徑是寫死的。我在注冊成功了以后,我可以跳轉(zhuǎn)到首頁上,也可以跳轉(zhuǎn)到登陸的界面上固额。如果我要選擇其中的一個,就必須修改源代碼...

②:一個功能對應(yīng)一個Servlet,太麻煩了...寫了LoginServlet热康,還要寫RegisterServlet....


新型的用戶登陸注冊

我們會發(fā)現(xiàn)葬毫,無論什么Servlet上最終還是跳轉(zhuǎn)到相對應(yīng)的JSP頁面的...也就是說烂斋,第一和第二步驟【封裝數(shù)據(jù)、調(diào)用Service】我們可以封裝起來...只要返回uri給Servlet跳轉(zhuǎn)到JSP頁面就好了担敌。


LoginAction

返回的uri分兩種情況:

  • 如果是轉(zhuǎn)發(fā)每币,那么返回的是RequestDispatcher對象
  • 如果是重定向,那么返回的是字符串

/**
 * Created by ozc on 2017/4/26.
 * <p>
 * 一個Action對應(yīng)一個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 ;

        //得到用戶帶過來的數(shù)據(jù)揭保,封裝到Bean對象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

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

        try {
            //調(diào)用Service方法
            UserService userService = new UserService();
            userService.longin(user);

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

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

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

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

            //登陸失敗魄宏,跳轉(zhuǎn)到相關(guān)的提示頁面
            request.setAttribute("message","登陸失敗了=章隆!宠互!");
            //request.getRequestDispatcher("/message.jsp").forward(request, response);

            //如果是轉(zhuǎn)發(fā)味榛,那么返回的是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 {

            //是轉(zhuǎn)發(fā),強轉(zhuǎn)成是RequestDispatcher對象
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

RegisterAction

  • RegisterAction

/**
 * Created by ozc on 2017/4/26.
 * 
 * 一個Action對應(yīng)一個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 ;

        //得到用戶帶過來的數(shù)據(jù)搏色,封裝到Bean對象中
        String username = request.getParameter("username");
        String psd = request.getParameter("psd");

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

        try {
            //調(diào)用Service方法
            UserService userService = new UserService();
            userService.register(user);

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

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

            //注冊失敗,跳轉(zhuǎn)到相關(guān)的提示頁面
            request.setAttribute("message","注冊失敗了H帷<逃堋巾表!");
            //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 {

            //是轉(zhuǎn)發(fā),強轉(zhuǎn)成是RequestDispatcher對象
            ((RequestDispatcher) uri).forward(request, response);
        }
    }

思考

到目前為止略吨,我們搞了兩個Action類來封裝Servlet的邏輯代碼,我們再次看回Servlet的代碼集币。

這里寫圖片描述
這里寫圖片描述

可以很清楚地發(fā)現(xiàn):兩個實現(xiàn)不同功能的Servlet僅僅是調(diào)用的Action不同....如果是僅僅調(diào)用的Action不同【通過反射來調(diào)用不同的Action】,那么我們應(yīng)該想到使用一個Servlet來管理整個項目翠忠,也就是說:整個web項目只有一個核心的控制器

問題:

①:我們在之前是直接指明Servlet的映射路徑了,現(xiàn)在要ActionServlet處理所有的請求鞠苟,我們只要定一個規(guī)則:只要后綴為.action的,那么都交由核心控制器ActionServlet來控制....

②:現(xiàn)在全部的請求已經(jīng)交由ActionServlet控制秽之,那怎么知道調(diào)用的是哪個Action当娱??考榨?我們可以通過請求的uri跨细,比如:http://localhost:8080/login.action,其中l(wèi)ogin就代表的是調(diào)用LoginAction..也就是說login=LoginAction,我們可以通過properties文件來配置..

③:現(xiàn)在我們已經(jīng)知道了調(diào)用的是哪個Action了河质,但是Action可能不僅僅只有一個方法冀惭,我們還要在調(diào)用的時候,指定的方法名是什么.這很簡單掀鹅,一般我們都是職責分工明確的散休,method=login....并且,調(diào)用的Action和具體的方法也是有關(guān)系的乐尊,不可能是孤立存在的戚丸。因此,我們的配置文件是不能使用properties的扔嵌,需要使用XML

④:在調(diào)用方法的時候限府,是返回一個Object的uri的,uri的類型可能是String痢缎、也可以能是RequestDispatcher谣殊、并且返回的結(jié)果可能有幾種情況的【可能跳轉(zhuǎn)到首頁,也可能跳轉(zhuǎn)到登陸界面】

⑤:Action調(diào)用的方法和返回的uri也是是有關(guān)系的牺弄!.....不同的Action調(diào)用不同的方法姻几,返回的uri也是不同的....

⑥:要跳轉(zhuǎn)到哪個頁面上,可以通過標識量來識別....比如:success表示成功執(zhí)行势告,如果要重定向那么多加個type類型蛇捌,如果不重定向就沒有type類型..路徑使用path來表示..因此,在具體的Action中咱台,就不需要返回具體的uri络拌,只要返回一個標識量即可


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

這里寫圖片描述

XML配置

我們可以寫出這樣的XML配置,當ActionServlet初始化的時候回溺,讀取XML配置文件春贸,就知道調(diào)用的是什么Action混萝,Action中的什么方法,以及跳轉(zhuǎn)到哪個頁面上了萍恕。

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

        <action name="login" className="zhongfucheng.servlet.LoginServlet" method="login">
            <!--是否存在type屬性逸嘀,存在則是重定向,不存在則是轉(zhuǎn)發(fā)-->
            <!--result的值表示的就是跳轉(zhuǎn)的路徑-->
            <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屬性允粤,存在則是重定向崭倘,不存在則是轉(zhuǎn)發(fā)-->
            <!--result的值表示的就是跳轉(zhuǎn)的路徑-->
            <result name="success">/message.jsp</result>
            <result name="fail">/message.jsp</result>
        </action>
    </package>

</mystruts>

為了更好地管理這些信息,我們應(yīng)該使用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來得到對應(yīng)的Action的悉患,并不會獲取得到整個Manager
    public ActionMapping getActionMapping(String name) {
        return map.get(name);
    }

}
  • ActionMapping----表示單個的Action

public class ActionMapping {

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

    //關(guān)鍵字name
    private String name;

    //要調(diào)用的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---表示的是結(jié)果視圖

/**
 * Created by ozc on 2017/4/26.
 *
 * 該類表示的是結(jié)果視圖
 *
 *
 *
 */
public class Results {

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

    //要跳轉(zhuǎn)的方式
    private String type;

    //要跳轉(zhuǎn)的頁面
    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中残家,應(yīng)該讀取配置文件,然后把信息全部封裝到里邊去...


/**
 * 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節(jié)點
            List list = document.selectNodes("http://action");

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

                //把得到每個Action的節(jié)點信息封裝到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節(jié)點下的所有result節(jié)點
                List results = action.elements("result");

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

                    //把得到每個result節(jié)點的信息封裝到Results中
                    Results results1 = new Results();

                    //得到節(jié)點的信息
                    String name1 = result.attributeValue("name");
                    String type = result.attributeValue("type");
                    String page = result.getText();

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

                    //把result節(jié)點添加到ActionMapping的集合中
                    actionMapping.getResults().put(name1, results1);
                }

                //最后把得到每個ActionMapping的信息添加到ActionMappingManager中
                allAction.put(name, actionMapping);

            }

        } catch (DocumentException e) {

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

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

ActionServlet

使用init()方法只加載創(chuàng)建一個ActionManagerMapping對象晃跺,并設(shè)置在Web容器啟動了該Servlet就啟動


/**
 * Created by ozc on 2017/4/26.
 *
 *
 * Web容器一啟動的時候揩局,該類就應(yīng)該加載了,在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的關(guān)鍵部分-----截完應(yīng)該是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();

            //通過反射創(chuàng)建出Action的對象凌盯,調(diào)用對應(yīng)的方法
            Class t = Class.forName(className);
            Object o = t.newInstance();

            //注意:這里的參數(shù)是接口的class,不是單純的request的class烹玉,單純的class是實現(xiàn)類
            Method m = t.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);

            //調(diào)用方法,得到標記
            String returnFlag = (String) m.invoke(o, request, response);

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

            //判斷是重定向還是轉(zhuǎn)發(fā)驰怎,為空就是轉(zhuǎn)發(fā),反則是重定向
            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的方法只要返回一個標識量即可二打,我們通過標識量來得到具體的跳轉(zhuǎn)頁面url和跳轉(zhuǎn)的方法的县忌。。继效。


效果:

這里寫圖片描述

自定義MyStruts總結(jié):

由于傳統(tǒng)web的Controller模塊存在弊端:

  • 一些功能重復(fù)使用症杏,代碼過于重復(fù)了。
  • 跳轉(zhuǎn)的頁面寫死了瑞信。改變需求的時候需要更改源代碼

本博文主要模擬Struts的開發(fā)流程

  • 使用一個ActionServlet核心控制器來管理全部的Web請求厉颤,寫XML配置文件,讀取配置文件凡简。
  • ActionMapping封裝了Action的基本信息逼友,在XML配置文件中就是讀取Action的基本信息精肃,封裝到JavaBean上,最后使用ActionMapping類的集合統(tǒng)一管理起來帜乞。
  • 當用戶訪問的時候司抱,我們根據(jù)url也就是Action的名稱反射出對應(yīng)的類,來對其進行操作挖函。
  • 根據(jù)XML文件的配置信息來確定跳轉(zhuǎn)方法状植、跳轉(zhuǎn)的url

我們現(xiàn)在學習的是Struts2,其實Struts1和Struts2在技術(shù)上是沒有很大的關(guān)聯(lián)的怨喘。 Struts2其實基于Web Work框架的津畸,只不過它的推廣沒有Struts1好,因此就拿著Struts這個名氣推出了Struts2框架必怜。

因此肉拓,學習Struts2的時候,不了解Struts1是沒有任何關(guān)系的梳庆。

在前面暖途,已經(jīng)說明了為什么要引入Struts框架,其實就是為了提高開發(fā)效率...

Struts2框架預(yù)先實現(xiàn)了一些功能:

  • 請求數(shù)據(jù)自動封裝
  • 文件上傳的功能
  • 對國際化功能的簡化
  • 數(shù)據(jù)效驗功能.......等等

Struts2開發(fā)步驟

我們就直接來講解Struts2的開發(fā)步驟是什么吧....在了解它的細節(jié)之前膏执,先要把配置環(huán)境搭好驻售!

引入jar文件

完整的struts中的jar包有80多個,我們?nèi)粘i_發(fā)是不需要那么多個的更米。一般我們導(dǎo)入的jar包有8個:

  • commons-fileupload-1.2.2.jar 【文件上傳相關(guān)包】
  • commons-io-2.0.1.jar【文件上傳相關(guān)包】
  • 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的標簽?zāi)0鍘靔ar文件】
  • javassist-3.11.0.GA.jar 【struts對字節(jié)碼的處理相關(guān)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>

開發(fā)Action

開山篇我們已經(jīng)說了迟几,Servlet的業(yè)務(wù)代碼,我們都使用Action來代替...Action類一般繼承著ActionSupport

Action類也叫動作類栏笆,處理請求的類类腮。


public class HelloAction extends ActionSupport {

    @Override
    public String execute() throws Exception {

        System.out.println("helloworld");

        return "success";
    }
}

至于execute()方法是什么,我們先不要去管它蛉加,為啥要返回一個String蚜枢,我們也不要去管它....只要記住開發(fā)步驟,并且针饥,我們的Action類是要繼承ActionSupport類的

配置struts.xml

至于配置struts.xml祟偷,我們可以在文件中找到相對應(yīng)的模版代碼的...最終修改成下面這個樣子就行了:


<?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打厘,就跳轉(zhuǎn)到index.jsp頁面了修肠。并且,execute()中的語句被執(zhí)行了...

這里寫圖片描述

Struts2執(zhí)行流程

我們來簡單地了解一下Struts的執(zhí)行流程户盯,然后再慢慢對上面的開發(fā)步驟的部分進行講解....

服務(wù)器啟動

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

  • 加載web.xml文件
  • 找到我們配置的filter中的StrutsPrepareAndExecuteFilter
  • StrutsPrepareAndExecuteFilter在里邊執(zhí)行init()方法
  • 一直到Dispatcher dispatcher = init.initDispatcher(config);嵌施,初始化dispatcher
  • 在初始化dispatcher的時候加載struts-default.xml和我們配置的struts.xml

下面用GIF圖來看看它的執(zhí)行過程:

這里寫圖片描述

細心的朋友可能會發(fā)現(xiàn)饲化,我們在struts.xml的package節(jié)點下,extends了struts-default....那struts-default究竟是什么東西呢吗伤?

我們找到它的源碼:

這里寫圖片描述

我們發(fā)現(xiàn)了一大堆的Bean吃靠,interceptor,result-type,interceptor-stack...下邊我來講解一下它們是干嘛用的...

  • bean指定了struts在運行的時候需要創(chuàng)建的對象類型
    • 在運行struts的時候,可能需要創(chuàng)建一些對象足淆,那么就通過Bean來指定
  • interceptor是struts定義的攔截器巢块,一共有32個
    • 前邊已經(jīng)說了,Struts為我們實現(xiàn)了一些功能巧号,就是通過攔截器來實現(xiàn)的族奢。
  • result-type是跳轉(zhuǎn)結(jié)果的類型
    • Action業(yè)務(wù)方法中的返回值,我們發(fā)現(xiàn)幾個實用的:redirect【重定向】丹鸿、dispatcher【轉(zhuǎn)發(fā)】越走、redirectAction【重定向到Action資源】、stream【文件下載的時候用】...跳轉(zhuǎn)結(jié)果的類型也在這里定義了
  • interceptor-stack是攔截器的棧
    • 攔截器有32個靠欢,我們可能會使用很多的攔截器廊敌,不可能一個一個來調(diào)用,于是提供了攔截器棧...其實可以簡單看成文件夾和文件之間的關(guān)系
  • default-interceptor-ref是默認執(zhí)行的攔截器棧
  • default-class-ref class是默認的執(zhí)行Action類

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


攔截器和過濾器

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

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

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


小總結(jié)

服務(wù)器啟動的時候,其實就是加載了web.xml文件掷空,然后調(diào)用init()方法去加載struts.xml和struts-default.xml之類的文件.....

注意:此時的攔截器是還沒有被調(diào)用的肋殴。


訪問階段

服務(wù)器啟動的階段,僅僅是加載了各種的xml文件...那么當我們訪問Action的時候拣帽,它的執(zhí)行流程是怎么的呢疼电?

  • 首先嚼锄,它會創(chuàng)建我們在struts.xml中配置的Action對象
  • 接著减拭,它會按照默認的順序執(zhí)行18個攔截器【也就是調(diào)用默認攔截器棧】
  • 最后区丑,它會執(zhí)行Action的業(yè)務(wù)方法【也就是execute()拧粪,我們在struts.xml文件中配置了什么,就執(zhí)行什么業(yè)務(wù)方法】

值得注意的是:每訪問Action一次沧侥,它就會創(chuàng)建一個對象...它并不是和Servlet一樣只有一個對象...因此它是線程安全的.


深入講解struts.xml

這是我們的struts.xml的內(nèi)容可霎,相信現(xiàn)在對它也不會太陌生了...


<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

通常來說癣朗,我們都是一個業(yè)務(wù)模版對應(yīng)一個package

name

name是包的名字,值得注意的是旺罢,包的名稱是不能重復(fù)的旷余。


extends

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


abstract

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


namespace

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


actoin

action:配置請求路徑與Action類的映射關(guān)系


name

name是請求路徑的名字


class

class是處理action類的全名


method

method是調(diào)用的方法名稱


result

result代表的是Action中業(yè)務(wù)方法返回的值


name

name是action處理返回的值


type

type是跳轉(zhuǎn)的類型


文本值

文本值是跳轉(zhuǎn)的路徑


細節(jié)

前邊已經(jīng)說了签孔,一個package應(yīng)該對應(yīng)一個業(yè)務(wù)模塊..目的就是把職能細分出來...

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

這里寫圖片描述

最后在struts.xml文件中將其引入即可..


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

如果文章有錯的地方歡迎指正窘行,大家互相交流饥追。習慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學抽高,可以關(guān)注微信公眾號:Java3y

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末判耕,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子翘骂,更是在濱河造成了極大的恐慌壁熄,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件碳竟,死亡現(xiàn)場離奇詭異草丧,居然都是意外死亡,警方通過查閱死者的電腦和手機莹桅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門踩寇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來聋迎,“玉大人,你說我怎么就攤上這事〕图ぃ” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵秧饮,是天一觀的道長巧还。 經(jīng)常有香客問我,道長瓮孙,這世上最難降的妖魔是什么唐断? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮杭抠,結(jié)果婚禮上脸甘,老公的妹妹穿的比我還像新娘。我一直安慰自己偏灿,他們只是感情好丹诀,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般铆遭。 火紅的嫁衣襯著肌膚如雪扁藕。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天疚脐,我揣著相機與錄音亿柑,去河邊找鬼。 笑死棍弄,一個胖子當著我的面吹牛望薄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播呼畸,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼痕支,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蛮原?” 一聲冷哼從身側(cè)響起卧须,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎儒陨,沒想到半個月后花嘶,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡蹦漠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年椭员,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片笛园。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡隘击,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出研铆,到底是詐尸還是另有隱情埋同,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布棵红,位于F島的核電站凶赁,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏窄赋。R本人自食惡果不足惜哟冬,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一楼熄、第九天 我趴在偏房一處隱蔽的房頂上張望忆绰。 院中可真熱鬧,春花似錦可岂、人聲如沸错敢。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽稚茅。三九已至纸淮,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間亚享,已是汗流浹背咽块。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留欺税,地道東北人侈沪。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像晚凿,于是被迫代替她去往敵國和親亭罪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容