2.對 Servlet 的改進--------Struts2 引入

  通過上一篇博客:Servlet 的詳解 http://www.cnblogs.com/ysocean/p/6912191.html,我們大致知道了 Servlet 的基本用法。但是稍微分析一下 Servlet 的用法,我們還是發現其存在很多缺點:

  ①、一個請求對應一個 Servlet,即每一個請求我們都需要在 web.xml 文件中配置映射。如果項目大,請求很多,那麼會造成 web.xml 很大,很難維護。

  ②、即便在好幾個請求對應一個 Servlet,即在 service() 方法中,通過 if--else 語句來判斷執行的代碼塊。那這樣就會造成 service() 方法很擁擠。

  ③、一個項目只存在一個 web.xml 文件,如果一個項目是多人開發,那麼整合代碼開發過程中會有很多問題。不適合團隊開發。

  ④、Servlet中doGet方法和doPost方法中的兩個參數reqeust,response擁有嚴重的容器依賴性。

  ⑤、如果頁面上表單中的元素比較複雜,則在Servlet的方法中獲取表單元素的數據比較繁瑣。

  ⑥、Servlet是單線程的,只要在Servlet中的聲明一個實例變量,那麼該變量在多線程訪問時就會有線程安全問題。

  ⑦、在Servlet中處理異常,如果Servlet中有N個方法,則這N個方法必須都要try--catch。因爲子類拋的異常不能大於父類。

 

那麼接下來我們用一個例子來解決上面的問題。

  1、新建一個 Web 工程,名爲 ServletIncreased。並在 web.xml 中配置一個過濾器 ServletFilter,這個過濾器會過濾所有以 .do 結尾的 URL 鏈接

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

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

<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

 xmlns="http://java.sun.com/xml/ns/javaee"

  xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

  http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"

   id="WebApp_ID" version="3.0">

    

  <filter>

    <filter-name>ServletFilter</filter-name>

    <filter-class>com.ys.filter.ServletFilter</filter-class>

  </filter>

  <filter-mapping>

    <filter-name>ServletFilter</filter-name>

    <url-pattern>*.do</url-pattern>

  </filter-mapping>

   

</web-app>

  2、創建一個 UserServlet,裏面有兩個方法,insert()和update()方法,調用 insert() 方法會跳轉到 insert.jsp 頁面,調用 update() 方法會調轉到 update.jsp 頁面

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

package com.ys.servlet;

 

import java.io.IOException;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

 

public class UserServlet {

    //用戶插入方法

    public void insert(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{

        req.getRequestDispatcher("insert.jsp").forward(req, resp);

    }

     

    //用戶更新方法

    public void update(HttpServletRequest req,HttpServletResponse resp) throws Exception, IOException{

        req.getRequestDispatcher("update.jsp").forward(req, resp);

    }

     

}

  3、創建一個配置文件類,裏面存放配置文件的關係,通過一個 Map 集合,保存 Servlet 的類名和全類名

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

package com.ys.config;

 

import java.util.HashMap;

import java.util.Map;

 

public class ServletNameConfig {

    //定義一個 Servlet 配置文件,Map<key,value>

    //key:表示 Servlet 的類名

    //value:表示 Servlet 類名的全稱

    public static Map<String, String> servletMap = new HashMap<>();

     

    static {

        servletMap.put("UserServlet""com.ys.servlet.UserServlet");

    }

 

}

  4、回頭看我們配置的過濾器,ServletFilter

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

package com.ys.filter;

 

import java.io.IOException;

import java.lang.reflect.Method;

 

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

import com.ys.config.ServletNameConfig;

 

public class ServletFilter implements Filter{

    @Override

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)

            throws IOException, ServletException {

        HttpServletRequest req = (HttpServletRequest) request;

        HttpServletResponse resp = (HttpServletResponse) response;

         

        String reqURL = req.getRequestURI(); //  /ServletIncreased/UserServlet.do

        String[] strs = reqURL.split("/");

        //定義 Servlet 的全類名

        String servletAllName = null;

        if(strs[2] != null){

            //得到 請求路徑的 servlet 類名

            String servletName = strs[2].substring(0, strs[2].indexOf("."));

            //根據獲取的 Servlet 類名,由配置文件 ServletNameConfig 裏面的map 得到 全類名

            servletAllName = ServletNameConfig.servletMap.get(servletName);

        }

        //獲取請求方法名

        String methodName = req.getParameter("method");

        System.out.println(servletAllName+"---"+methodName);

        try {

            //通過反射調用執行方法

            Class obj = Class.forName(servletAllName);

            Method method = obj.getDeclaredMethod

                    (methodName, HttpServletRequest.class,HttpServletResponse.class);

            method.invoke(obj.newInstance(), req,resp);

        catch (Exception e) {

            e.printStackTrace();

        }      

    }

 

    @Override

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override

    public void destroy() {

    }

 

}

  整體的項目結構如下:

  

然後將整個項目發佈到 tomcat 服務器運行,發佈的方法可以如下:

  http://www.cnblogs.com/ysocean/p/6893446.html

然後我們在瀏覽器輸入如下鏈接:http://localhost:8080/ServletIncreased/UserServlet.do?method=insert

  那麼就會調用 UserServlet 的 insert 方法,進而跳轉到 insert.jsp 頁面

  

如果我們在瀏覽器輸入如下鏈接:將 insert 改爲 update

   http://localhost:8080/ServletIncreased/UserServlet.do?method=update

那麼就會調用 UserServlet 的update 方法,進而調轉到 update.jsp 頁面

  

 

 

分析:這個改進主要是配置了一個過濾器,然後通過過濾器的 doFilter() 方法,我們可以通過請求路徑獲得請求URL,然後通過字符串的截取方法得到 Servlet 的名稱。通過配置文件保存的 Servlet類名和全類名的對應關係得到全類名;然後利用反射的原理,通過 invoke() 方法來動態調用方法。這裏我們並沒有解決上面所有的問題,比如嚴重的容器依賴性我們這裏還有。如果想真正解決,請看下一篇博客:Struts2 詳解

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章