Spring MVC攔截器的使用
Spring MVC中攔截器(Interceptor)是比較重要的功能,主要作用是攔截使用者的請求并根據實際需求以做出相應的處理。一般常用來使用者權限驗證、若需要同一賬号隻能登入一次還可以做是否已經登入判斷等。Struts2也有類似攔截器,而在Servlet中主要通過過濾器實作。
Spring MVC中攔截器是通過實作HandlerInterceptor接口完成的。要想使用攔截器,可以直接實作該接口,或者繼承實作了該接口的抽象類HandlerInterceptorAdapter。
以下以使用者權限驗證為例:
1.登入頁面loginUI.jsp
輸入使用者名、密碼,送出給背景處理,若使用者名、密碼錯誤時提示資訊通過message顯示。
<h1>${requestScope.message}</h1>
<form id="loginForm" action="${pageContext.request.contextPath}/user/login.do" method="post">
<table>
<tr>
<td>使用者名</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密碼</td>
<td><input type="password" name="pwd"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="登入">
</td>
</tr>
</table>
</form>
2.處理登入請求UserController.java
登入頁面在WEB-INF/jsp/user目錄下,是以需通過控制器轉發;登入頁面點選登入,判斷使用者名、密碼是否正确,正确則session中存儲登入使用者;否則傳回到登入頁面,給出提示資訊。
@Controller
@RequestMapping("/user")
public class UserController {
/**
* 使用者登入頁面
*/
@RequestMapping("/loginUI")
public String loginUI() throws Exception {
return "user/loginUI";
}
/**
* 使用者登入
*/
@RequestMapping("/login")
public String login(Model model, HttpSession session, User user) throws Exception {
if (user != null && StringUtils.isNotBlank(user.getUsername()) && StringUtils.isNotBlank(user.getPwd())) {
// 模拟使用者登入
if (user.getUsername().equals("user") && user.getPwd().equals("user")) {
// 登入成功,session域中存儲登入使用者
session.setAttribute("user", user);
model.addAttribute("message", "登入成功");
return "success";
}
}
model.addAttribute("message", "使用者或密碼錯誤");
return "user/loginUI";
}
}
3.攔截器RequestInterceptor.java
攔截所有以".do"字尾結尾的請求,對于請求登入頁面,首頁等頁面時放行;其他頁面時則需判斷使用者是否已經登入,即session中是否有使用者資訊,已登入則放行,否則跳轉進入登入頁面。
/**
* 請求攔截器
*/
public class RequestInterceptor implements HandlerInterceptor {
private static final String[] IGNORE_URI = { "/loginUI", "/login", "/index" };
/**
* 請求攔截
* @param request
* @param response
* @param handler
* @return true:執行下一攔截器或Controller;false:請求結束
* <p>
* 1.preHandle方法是攔截器攔截到請求後最先執行的,是以可以在該方法中進行一些初始化或者攔截操作,如權限過濾。<br>
* 2.Spring MVC是鍊式調用,即可以存在多個攔截器進行攔截,隻有在preHandle傳回true時,才會繼續執行下一個攔截器或者Controller;<br>
* </p>
* */
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
boolean result = false;
String uri = request.getRequestURI();
for (String u : IGNORE_URI) {
if (uri.contains(u)) {
result = true;
break;
}
}
if (!result) {
User user = (User) request.getSession().getAttribute("user");
if (user == null) {
request.setAttribute("message", "請先登入再通路該頁面");
request.getRequestDispatcher("/user/loginUI.do").forward(request, response);
} else {
result = true;
}
}
return result;
}
/**
* <p>
* 1.afterCompletion和postHandle在preHandle方法傳回值為true時才能執行;<br>
* 2.也就是在Controller方法執行後、視圖渲染之前調用,是以可以對Contoller處理後的ModelAndView對象進行操作;<br>
* 3.postHandle方法的執行次序和preHandle相反,類似于Struts2中的攔截器。<br>
* </p>
* */
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView mv)
throws Exception {
}
/**
* <p>
* 1.afterCompletion和postHandle在preHandle方法傳回值為true時才能執行;<br>
* 2.該方法在整個請求結束之後,即視圖渲染結束後執行;<br>
* 3.該方法主要作用是進行資源的清理。<br>
* </p>
* */
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception e)
throws Exception {
}
}
4.攔截器配置
在springmvc.xml中通過<mvc:interceptors>配置攔截器,<mvc:interceptor>配置具體攔截器資訊,攔截的url,調用的攔截器類,可以配置多個攔截器,注意次序即可。
<!-- 定義攔截器 -->
<!-- path屬性
/**:所有檔案夾及其子檔案夾
/* :所有檔案夾,不含子檔案夾
/ :web項目的根目錄
-->
<mvc:interceptors>
<mvc:interceptor>
<!-- <mvc:mapping path="/*"/> -->
<!-- <mvc:mapping path="/**"/> --><!-- 攔截所有 -->
<mvc:mapping path="/**/*.do"/><!-- 攔截指定字尾 -->
<!-- <mvc:exclude-mapping path=""/> --><!-- 不攔截的路徑 -->
<bean class="cn.edu.njit.interceptor.RequestInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
5.測試
(1).未登入時通路其他頁面
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICNwATMyYjMxEjNyMDM3EDMy8CX0Vmbu4GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.jpg)
(2).使用者或密碼錯誤
6.注
(1).對于需要放行(不攔截)的url需要考慮清楚;
(2).攔截器的配置可以通過springmvc.xml中顯示配置,也可通過注解實作。
(3).<mvc:mapping path=""/>中,path屬性有多種寫法,**.do,根據實際情況配置。
(4).本例中UserController、login(...)上都有@RequestMapping("/xxx"),類似于有二級路徑,是以通過'/*'則攔截不到請求。