天天看點

SpringMVC架構基礎知識(04)

1. 重定向

在SpringMVC架構中,如果處理請求的方法的傳回值類型是String,且方法之前沒有添加@ResponseBody注解時,使用redirect:目标路徑作為傳回結果,即可以實作重定向,例如:

return "redirect:hello.do";      

2. 轉發與重定向

轉發:是伺服器内部的行為,是由伺服器端的控制器将請求轉發到視圖元件的過程,由于整個過程是發生在伺服器内部的,是以,對于用戶端來說,是不知道這個過程的,在用戶端的浏覽器的位址欄中的URL也就一直是最初送出請求的URL,在整個過程中,用戶端也隻發出了1次請求,如果重新整理頁面,會再次送出請求,從代碼方面來看,轉發時,控制器需要給出的隻是“視圖名稱”即可,然後,根據伺服器内部的相關配置确定具體的視圖元件,之是以是這樣,還是因為“轉發是伺服器内部的行為”,結合伺服器端的配置一起使用也是非常正常的!由于轉發是伺服器内部端内部的行為,是以,伺服器端的控制器可以轉發任何資料到視圖元件!

重定向:在整個過程中,用戶端發出第1次請求時,伺服器的響應方式是重定向,其具體表現是伺服器端會向用戶端發出302HTTP響應碼,表示“重定向”,同時,還會向用戶端響應目标路徑,當用戶端收到響應碼是302時,就會自動的發出第2次請求,并根據伺服器端響應的目标路徑送出請求。由于用戶端是明确第2次請求的目标的,是以,在用戶端的浏覽器的位址欄中會顯示第2次請求的URL。從代碼方面來,重定向時,必須給出明确的目标路徑,用戶端将根據這個路徑發出第2次請求!由于前後共有2次請求,同時基于HTTP協定是無狀态協定,在沒有結合其它技術時,伺服器端處理第1次請求時得到的資料并不可以用于處理第2次請求。

3. 使用Session

在SpringMVC中,在處理請求的方法的參數清單中添加HttpSession session對象,就可以使用Session了!

一般情況下,儲存在Session中的資料會消失的情景有:

伺服器端的Tomcat重新開機後,Session中的資料會消失;

當用戶端的最後一次請求已經逾時,Session中的資料會消失,逾時時間可以由伺服器端進行設定;

當用戶端軟體被關閉後,将無法通路到此前的Session資料,同時,在逾時後,此前的Session資料也會消失!

一般情況下,會儲存到Session中的資料大緻是這些類型的:

使用者身份的唯一辨別,例如:使用者的id、使用者名等;

高頻率使用的資料,例如:使用者名、頭像這種高頻率顯示的資料,或者使用者權限等;

不便于使用其它技術實作存儲或傳遞的資料。

4. Interceptor攔截器

在SpringMVC中,可以建立Interceptor(攔截器)元件,使得若幹種不同的請求都會先經過攔截器元件,并且,攔截器元件可以對請求進行阻止,或放行。

注意:攔截器的目的并不一定是要“阻止”,也許,隻是希望若幹種不同的請求都執行相同的代碼片斷,然後,攔截器100%放行,也是可以的!

當需要攔截器,可以自定義類(對所在的包沒有要求),實作HandlerInterceptor攔截器接口,例如:

public class LoginInterceptor implements HandlerInterceptor {
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    throws Exception {
  System.out.println("LoginInterceptor.preHandle()"); // syst
  return true;
    }
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    ModelAndView modelAndView) throws Exception {
  System.out.println("LoginInterceptor.postHandle()");
    }
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    throws Exception {
  System.out.println("LoginInterceptor.afterCompletion()");
    }
}      

所有的攔截器必須被注冊之後才會發揮作用!關于攔截器的注冊,必須重寫SpringMVC的配置類中的addInterceptors()方法,通過方法的參數對象來注冊攔截器,例如:

@ComponentScan("cn.tedu.spring")
@Configuration
@EnableWebMvc
public class SpringMvcConfigurer implements WebMvcConfigurer {
    /**
  * 添加攔截器鍊
  */
    public void addInterceptors(InterceptorRegistry registry) {
  // 注意:配置攔截器作用的相關路徑時,路徑值必須使用 / 作為第1個字元
  LoginInterceptor interceptor = new LoginInterceptor();
  registry.addInterceptor(interceptor).addPathPatterns("/hello.do");
    }
   
}      

通過測試運作,可以發現,在攔截器中的preHandle()方法是運作在控制器之前的,并且,當該方法傳回false時,表示“阻止運作”,會導緻控制器中的方法不會被執行,當該方法傳回true時,表示“放行”,接下來,控制器中的方法就會執行,是以,在攔截器的3個方法中,隻有preHandle()是具備真正意義上的“攔截”效果的!

如果需要設計規則“隻有登入了才允許後續的通路”,就可以在preHandle()中對登入資訊進行驗證,如果已登入,則放行,如果未登入,則攔截,且重定向到登入頁!例如:

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println("LoginInterceptor.preHandle()"); // syst
    HttpSession session = request.getSession();
    if (session.getAttribute("loginUsername") == null) {
        String contextPath = request.getContextPath(); // springmvc02
        response.sendRedirect(contextPath + "/login.do");
        return false;
    }
    return true;
}

      

關于攔截器的配置,首先,在同一個項目中,可以存在若幹個攔截器元件,形成“攔截器鍊”,如果某個請求會經曆多個攔截器元件,必須每個攔截器都放行,才能向後繼續執行,如果其中任何一個攔截器執行效果是“阻止”,則嘗試通路的控制器将不會被執行!注冊攔截器時,注冊的先後順序決定各攔截器的執行順序!

在配置攔截路徑時,可調用的方法addPathPatterns()被重載了2次:

public InterceptorRegistration addPathPatterns(String... patterns) {
    return addPathPatterns(Arrays.asList(patterns));
}
public InterceptorRegistration addPathPatterns(List<String> patterns) {
    this.includePatterns.addAll(patterns);
    return this;
}      

是以,在配置攔截路徑時,可以使用List<String>或可變參數String...來表示若幹個被攔截的路徑。

在配置請求路徑時,還可以使用星号(*)作為通配符,例如,嘗試攔截的路徑有:

/blog/publish.do
/blog/edit.do
/blog/delete.do
/blog/list.do      

隻需要配置為以下路徑即可:

/blog/*

需要注意的是:在配置攔截路徑時,使用1個星号(*)的通配符隻能比對1個層級的資源,無法比對多層級資源!例如配置為/blog/*時,就不可以比對到/blog/2020/list.do,如果需要比對若幹個層級(1層或多層)的資源,就需要使用2個星号(**),例如配置為:

/blog/**