SpringMVC第七篇【RESTful支持、攔截器】

RESTful支持

咱們在學習webservice的時候可能就聽過RESTful這麼一個名詞,當時候與SOAP進行對比的…那麼RESTful到底是什麼東東呢???css

RESTful(Representational State Transfer)軟件開發理念,RESTful對http進行很是好的詮釋java

若是一個架構支持RESTful,那麼就稱它爲RESTful架構…web

如下的文章供咱們瞭解:spring

http://www.ruanyifeng.com/blog/2011/09/restful服務器

綜合上面的解釋,咱們總結一下什麼是RESTful架構:restful

  •   (1)每個URI表明一種資源;
  •   (2)客戶端和服務器之間,傳遞這種資源的某種表現層;
  •   (3)客戶端經過四個HTTP動詞,對服務器端資源進行操做,實現」表現層狀態轉化」

其實通常的架構並不能徹底支持RESTful的,所以,只要咱們的系統支持RESTful的某些功能,咱們通常就稱做爲支持RESTful架構markdown

url的RESTful實現

非RESTful的http的url:http://localhost:8080/items/editItems.action?id=1&….session

RESTful的url是簡潔的:http:// localhost:8080/items/editItems/1架構

更改DispatcherServlet的配置

從上面咱們能夠發現,url並無.action後綴的,所以咱們要修改核心分配器的配置mvc

<!-- restful的配置 -->
    <servlet>
        <servlet-name>springmvc_rest</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 加載springmvc配置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <!-- 配置文件的地址 若是不配置contextConfigLocation, 默認查找的配置文件名稱classpath下的:servlet名稱+"-serlvet.xml"即:springmvc-serlvet.xml -->
            <param-value>classpath:spring/springmvc.xml</param-value>
        </init-param>

    </servlet>
    <servlet-mapping>
        <servlet-name>springmvc_rest</servlet-name>
        <!-- rest方式配置爲/ -->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

在Controller上使用PathVariable註解來綁定對應的參數

//根據商品id查看商品信息rest接口
    //@RequestMapping中指定restful方式的url中的參數,參數須要用{}包起來
    //@PathVariable將url中的{}包起參數和形參進行綁定
    @RequestMapping("/viewItems/{id}")
    public @ResponseBody ItemsCustom viewItems(@PathVariable("id") Integer id) throws Exception{
        //調用 service查詢商品信息
        ItemsCustom itemsCustom = itemsService.findItemsById(id);

        return itemsCustom;

    }

當DispatcherServlet攔截/開頭的全部請求,對靜態資源的訪問就報錯:咱們須要配置對靜態資源的解析

<!-- 靜態資源 解析 -->
    <mvc:resources location="/js/" mapping="/js/**" />
    <mvc:resources location="/img/" mapping="/img/**" />

/**就表示無論有多少層,都對其進行解析,/*表明的是當前層的全部資源..


SpringMVC攔截器

在Struts2中攔截器就是咱們當時的核心,原來在SpringMVC中也是有攔截器的

用戶請求到DispatherServlet中,DispatherServlet調用HandlerMapping查找Handler,HandlerMapping返回一個攔截的鏈兒(多個攔截),springmvc中的攔截器是經過HandlerMapping發起的。

實現攔截器的接口:

public class HandlerInterceptor1 implements HandlerInterceptor {

    //在執行handler以前來執行的
    //用於用戶認證校驗、用戶權限校驗
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        System.out.println("HandlerInterceptor1...preHandle");

        //若是返回false表示攔截不繼續執行handler,若是返回true表示放行
        return false;
    }
    //在執行handler返回modelAndView以前來執行
    //若是須要向頁面提供一些公用 的數據或配置一些視圖信息,使用此方法實現 從modelAndView入手
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1...postHandle");

    }
    //執行handler以後執行此方法
    //做系統 統一異常處理,進行方法執行性能監控,在preHandle中設置一個時間點,在afterCompletion設置一個時間,兩個時間點的差就是執行時長
    //實現 系統 統一日誌記錄
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HandlerInterceptor1...afterCompletion");
    }

}

配置攔截器

<!--攔截器 -->
    <mvc:interceptors>
        <!--多個攔截器,順序執行 -->
        <!-- <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor1"></bean> </mvc:interceptor> <mvc:interceptor> <mvc:mapping path="/**" /> <bean class="cn.itcast.ssm.controller.interceptor.HandlerInterceptor2"></bean> </mvc:interceptor> -->

        <mvc:interceptor>
            <!-- /**能夠攔截路徑無論多少層 -->
            <mvc:mapping path="/**" />
            <bean class="cn.itcast.ssm.controller.interceptor.LoginInterceptor"></bean>
        </mvc:interceptor>
    </mvc:interceptors>

測試執行順序

若是兩個攔截器都放行

測試結果:
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle

HandlerInterceptor2...postHandle
HandlerInterceptor1...postHandle

HandlerInterceptor2...afterCompletion
HandlerInterceptor1...afterCompletion

總結:
執行preHandle是順序執行。
執行postHandle、afterCompletion是倒序執行

1 號放行和2號不放行

測試結果:
HandlerInterceptor1...preHandle
HandlerInterceptor2...preHandle
HandlerInterceptor1...afterCompletion

總結:
若是preHandle不放行,postHandle、afterCompletion都不執行。
只要有一個攔截器不放行,controller不能執行完成

1 號不放行和2號不放行

測試結果:
HandlerInterceptor1...preHandle
總結:
只有前邊的攔截器preHandle方法放行,下邊的攔截器的preHandle才執行。

日誌攔截器或異常攔截器要求

  • 將日誌攔截器或異常攔截器放在攔截器鏈兒中第一個位置,且preHandle方法放行

攔截器應用-身份認證

攔截器攔截

public class LoginInterceptor implements HandlerInterceptor {

    //在執行handler以前來執行的
    //用於用戶認證校驗、用戶權限校驗
    @Override
    public boolean preHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler) throws Exception {

        //獲得請求的url
        String url = request.getRequestURI();

        //判斷是不是公開 地址
        //實際開發中須要公開 地址配置在配置文件中
        //...
        if(url.indexOf("login.action")>=0){
            //若是是公開 地址則放行
            return true;
        }

        //判斷用戶身份在session中是否存在
        HttpSession session = request.getSession();
        String usercode = (String) session.getAttribute("usercode");
        //若是用戶身份在session中存在放行
        if(usercode!=null){
            return true;
        }
        //執行到這裏攔截,跳轉到登錄頁面,用戶進行身份認證
        request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);

        //若是返回false表示攔截不繼續執行handler,若是返回true表示放行
        return false;
    }
    //在執行handler返回modelAndView以前來執行
    //若是須要向頁面提供一些公用 的數據或配置一些視圖信息,使用此方法實現 從modelAndView入手
    @Override
    public void postHandle(HttpServletRequest request,
            HttpServletResponse response, Object handler,
            ModelAndView modelAndView) throws Exception {
        System.out.println("HandlerInterceptor1...postHandle");

    }
    //執行handler以後執行此方法
    //做系統 統一異常處理,進行方法執行性能監控,在preHandle中設置一個時間點,在afterCompletion設置一個時間,兩個時間點的差就是執行時長
    //實現 系統 統一日誌記錄
    @Override
    public void afterCompletion(HttpServletRequest request,
            HttpServletResponse response, Object handler, Exception ex)
            throws Exception {
        System.out.println("HandlerInterceptor1...afterCompletion");
    }

}

Controller

@Controller
public class LoginController {


    //用戶登錄提交方法
    @RequestMapping("/login")
    public String login(HttpSession session, String usercode,String password)throws Exception{

        //調用service校驗用戶帳號和密碼的正確性
        //..

        //若是service校驗經過,將用戶身份記錄到session
        session.setAttribute("usercode", usercode);
        //重定向到商品查詢頁面
        return "redirect:/items/queryItems.action";
    }

    //用戶退出
    @RequestMapping("/logout")
    public String logout(HttpSession session)throws Exception{

        //session失效
        session.invalidate();
        //重定向到商品查詢頁面
        return "redirect:/items/queryItems.action";

    }


}
相關文章
相關標籤/搜索