在Springboot中的WebMvcConfigurer接口在Web開發中經常被使用,例如配置攔截器、配置ViewController、配置Cors跨域等。本文主要講解另一個方法:addArgumentResolvers()
在實例中的應用。
一、方法作用
該方法可以用在對於Controller中方法參數傳入之前對該參數進行處理。然后將處理好的參數在傳給Controller中的方法。
官方API文檔解釋:添加解析器以支持自定義控制器方法參數類型。
這不會覆蓋對解析處理程序方法參數的內置支持。要自定義對參數解析的內置支持,請RequestMappingHandlerAdapter直接配置。
二、場景描述
在權限場景中,通常會有要求用戶登錄之后才能訪問的場景。對於這些問題可以多種解決方案,如:使用Cookie+Session的會話控制、使用攔截器、使用SpringSecurity或shiro等權限管理框架等。
這里使用Cookie+Session處理。處理的邏輯為:
用戶第一次登錄之后會得到一個cookie,在以后每次的訪問過程中都會攜帶Cookie進行訪問。在后台的Controller中對於需要登錄權限的訪問接口都要先獲取Cookie中的Token,再使用Token從session中獲取用戶登錄信息來判斷用戶登錄情況決定是否放行。
三、存在問題
如果在每個需要登錄權限訪問的方法中都要寫這個邏輯就會使代碼重復,出現了冗余。代碼基本如下:
@GetMapping("goods")
public Result showGoods1(HttpSession session, @CookieValue("Token") String token){
// 你每次都要在這里判斷token或session
if (token == null || MyObjectUtil.isEmpty(session.getAttribute(token))){
return Result.error();
}
return Result.ok();
}
所以需要尋找是否有更好的解決方法。
最終找到addArgumentResolvers()
這個方法。只需要在這個方法中進行處理即可。
四、問題解決
該方法的處理流程如下:
代碼如下:
-
Controller中的方法
@GetMapping("goods") public Result showGoods(User user){ // 注意:這里的User參數不是由前端傳入的,而是由addArgumentResolvers方法處理之后傳進來的 log.info(user.toString()); // 根據處理之后傳入的參數判斷是否登錄 if (user == null) return Result.error(); return Result.ok(); }
-
WebMvcController實現了類
@Configuration public class WebConfig implements WebMvcConfigurer { @Autowired private UserArgumentResolver userArgumentResolver; /** * 該方法作用在調用Controller方法的參數傳入之前 * @param resolvers */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { // userArgumentResolver該類對Controller傳入的參數做了具體處理 resolvers.add(UserArgumentResolver); } // 其他配置 }
-
UserArgumentResolver自定義實現類
/** * 該類用於WebConfig配置類的addArgumentResolvers方法傳入 */ @Component public class UserArgumentResolver implements HandlerMethodArgumentResolver { /** * 該方法用於判斷Controller中方法參數中是否有符合條件的參數: * 有則進入下一個方法resolveArgument; * 沒有則跳過不做處理 * @param parameter * @return */ @Override public boolean supportsParameter(MethodParameter parameter) { // 獲取傳入參數的類型 Class<?> type = parameter.getParameterType(); // 如果參數類型有為User類的則符合,進入resolveArgument方法 if (User.class == type) return true; return false; } /** * 該方法在上一個方法同通過之后調用: * 在這里可以進行處理,根據情況返回對象——返回的對象將被賦值到Controller的方法的參數中 * @param parameter * @param mavContainer * @param webRequest * @param binderFactory * @return * @throws Exception */ @Override public Object resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory ) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); HttpSession session = request.getSession(); // 獲取cookie Cookie[] cookies = request.getCookies(); String token = null; for (Cookie c : cookies){ if (c.getName().equals("token")){ token = c.getValue(); break; } } // 如果token不存在,則返回null if (token == null) return null; // 獲取session中對象 User user = (User)session.getAttribute(token); return user; } }