1. 程式人生 > >Struts2開發前奏

Struts2開發前奏

nts 轉發 import http cti lock error 瀏覽器 返回

  我們在學習Struts之前,先來復習一下Servlet,眾所周知ServletJavaWeb的三大組件。我們發送一個請求,這個請求交給Servlet處理,Servlet將處理的結果返還給瀏覽器。每個Servlet對應一個URL-pattern。那麽有沒有這麽一種情況呢?我們訪問多個URL-pattern,這些URL-pattern具有共同的功能,那就是轉發到其它頁面,但是又不想寫那麽多ServletServlet雖然是單例的,但是能少一個對象,對於JVM也是一種優化不是嗎,那麽有什麽辦法可以做到呢?如下圖

技術分享圖片

  熟悉Servlet的前輩,可能一看就會知道只是不可能的,一個Servlet

只能對應一個URLPattern,那麽怎麽實現這個功能呢?下面我們通過項目來實現一下:

  • 創建Web項目struts2_1
  • 創建test.jsp頁面,在頁面中建立三個URL請求鏈接
<body>
<h3>入門路徑:</h3><br>
<a href="${pageContext.request.contextPath }/UserServlet">userWorld</a><br>
<a href="${pageContext.request.contextPath }/HelloServlet"
>helloWorld</a><br> <a href="${pageContext.request.contextPath }/CustomerServlet">addWorld</a><br> </body>
  • 我們首先通過傳統的Servlet來實現:

UserServlet

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType(
"text/html;charset=utf-8"); PrintWriter pw = response.getWriter(); System.out.println("歡迎訪問UserServlet"); //pw.println("訪問一次,我就得寫一個Servlet!!!");請求轉發會將response攜帶的數據丟失 request.getRequestDispatcher("/success.jsp").forward(request, response); pw.flush(); pw.close(); }
Web.xml 
 <servlet>
      <servlet-name>UserServlet</servlet-name>
      <servlet-class>cn.web.UserServlet</servlet-class>
  </servlet>
  <servlet-mapping>
      <servlet-name>UserServlet</servlet-name>
      <url-pattern>/UserServlet</url-pattern>
  </servlet-mapping>
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        System.out.println("歡迎訪問HelloServlet");
        pw.println("訪問一次,我就得寫一個Servlet!!!!");
        request.getRequestDispatcher("/error.jsp").forward(request, response);
        pw.flush();
        pw.close();
    }
@WebServlet("/CustomerServlet")
public class CustomerServlet extends HttpServlet {
    
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        PrintWriter pw = response.getWriter();
        System.out.println("歡迎訪問CustomerServlet");
        pw.println("訪問一次,我就得寫一個Servlet!!!!!");
        request.getRequestDispatcher("/add.jsp").forward(request, response);
        pw.flush();
        pw.close();
    }
Success.jsp
  <body>
        xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  </body>
Error.jsp
  <body>
       錯誤頁面
  </body>
Add.jsp
  <body>
       添加
  </body>

  我們在瀏覽器訪問test.jsp,然後可以訪問到這些Servlet,但是我們也註意到了,每一個URLpattern對應一個Servlet,這麽多請求造成了我們寫了很多Servlet,並且需要很多web.xml中的配置(Servlet3.0以後支持註解)。 那麽能否實現在web容器中只配置一次,就可以實現以上3URL都可以跳轉到指定的頁面呢?

  結論:可以使用過濾器實現:我們在過濾器中過濾所有的請求,進行判斷,如果是test.jsp那麽放行,否則就全部過濾操作。實際上根據上圖我們知道這樣一個對應關系,那就是一個請求對應一個Servlet,然後一個Servlet對應一個頁面,那麽我們創建兩個Map集合,一個放請求和類的對應,一個放返回值和頁面的對應.

  • 創建一個Action接口,作為請求對應的類,它有三個實現類對應三個Servlet
package cn.filter;

public interface Action {
    public String excute();
}
package cn.filter;

public class HelloAction implements Action{

    @Override
    public String excute() {
        System.out.println("訪問HelloAction!");
        return "error";
    }
}
package cn.filter;

public class UserAction implements Action {

    @Override
    public String excute() {
        System.out.println("訪問UserAction!");
        return "success";//對應請求轉發的頁面名稱
    }
}
package cn.filter;

public class CustomerAction implements Action {

    @Override
    public String excute() {
        System.out.println("訪問CustomerAction!");
        return "add";
    }
}
  • 創建Filter,然後對過濾進行操作

技術分享圖片

package cn.filter;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import javax.servlet.DispatcherType;
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.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebFilter(
        dispatcherTypes = {DispatcherType.REQUEST }
                    , 
        urlPatterns = { 
                "/TestFilter", 
                "/*"
        })
public class TestFilter implements Filter {
    //使頁面的訪問路徑對應Action類
    Map<String, String> actionMap = new HashMap<>();
    //使對應的action返回值對應相應的jsp頁面
    Map<String, String> returnMap = new HashMap<>();
    //web容器啟動時執行
    public void init(FilterConfig fConfig) throws ServletException {
        actionMap.put("/UserServlet", "cn.filter.UserAction");
        actionMap.put("/HelloServlet", "cn.filter.HelloAction");
        actionMap.put("/CustomerServlet", "cn.filter.CustomerAction");
        returnMap.put("success", "/success.jsp");
        returnMap.put("add", "/add.jsp");
        returnMap.put("error", "/error.jsp");
    }
    
    public void destroy() {
        // TODO Auto-generated method stub
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request= (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        //獲取請求Servlet路徑
        String path = request.getServletPath();
        if(path != null && path.equals("/test.jsp")){
            chain.doFilter(request, response);
            return;
        }//如果是test.jsp那麽放行
        //如果不是test.jsp頁面,那就進行過濾操作
        //獲取訪問的action路徑
        String actionClass = actionMap.get(path);
        try {
            //通過反射獲取Action類的對象
            Action action = (Action) Class.forName(actionClass).newInstance();
            //獲取返回的頁面名稱
            String returnValue = action.excute();
            //利用Action類的返回值,獲取所對應的頁面
            String page = returnMap.get(returnValue);
            //轉發到相應頁面
            request.getRequestDispatcher(page).forward(request, response);
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
    }
}

  我們使用瀏覽器進行測試,發現,這次我們的請求沒有經過Servlet,而是通過Action類處理了(對比前後兩次控制臺打印輸出可以看出),通過過濾器,我們簡單避免了web.xml中的反復配置.上面其實就是一個簡單的Struts2實現:

Struts2開發前奏