SpringMVC 自定義參數解析器.
- 2019 年 11 月 22 日
- 筆記
一、簡述
有沒有想過像 @RequestParam、@RequestBody 這些註解的工作原理呢?為什麼 form 表單、application/json 的參數能夠直接封裝進 Bean 對象中呢?這就要說到 HandlerMethodArgumentResolver — 方法參數解析器,該接口有兩個方法:
public interface HandlerMethodArgumentResolver { boolean supportsParameter(MethodParameter parameter); Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception; }
supportsParameter 方法返回 boolean 值,表示是否啟用該解析器,true 表示啟用,false 表示不啟用;resolveArgument 方法表示方法參數的解析過程,就是你把 HTTP 的請求參數轉換為方法參數的過程,返回 Object 對象,即參數的轉換結果。
@RequestParam 對應的參數解析器是 RequestParamMethodArgumentResolver;@RequestBody 對應的參數解析器是 RequestResponseBodyMethodProcessor;諸如此類的解析器,讀者可自行閱讀。
二、自定義參數解析器
我想在控制器方法參數中得到當前用戶的登陸信息,大概是如下這個效果,只要添加了 @CurrentUser 註解,那麼 UserParam 參數中就會有當前用戶的登陸信息。
@RequestMapping(value = "/list", method = RequestMethod.POST) public ResponseData<List<SysWayDto>> list(@CurrentUser UserParam userParam) { Map<String, Object> objectMap = MapUtils.convertObjToMap(userParam); return sysWayService.findWithOriginDest(objectMap); }
怎麼實現呢?首先我們需要有一個 @CurrentUser 註解:
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface CurrentUser { }
那麼剩下來的工作就是 HandlerMethodArgumentResolver 的事情了:
@Slf4j public class CurrentUserHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { /** * 用於判定是否需要處理該參數分解,返回 true 為需要,並會去調用下面的方法resolveArgument。 */ @Override public boolean supportsParameter(MethodParameter methodParameter) { return methodParameter.getParameterType().isAssignableFrom(UserParam.class) && methodParameter.hasParameterAnnotation(CurrentUser.class); } /** * 真正用於處理參數分解的方法,返回的 Object 就是 controller 方法上的形參對象。 */ @Override public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception { String accessToken = nativeWebRequest.getHeader(GatewayHeader.accessToken); try { UserParam userParam = JsonUtils.readValue(JwtHelper.parseJWT(accessToken), UserParam.class); return userParam ; } catch (IOException e) { log.error("CurrentUserHandlerMethodArgumentResolver resolveArgument readValue error.accessToken:{}", accessToken, e); } catch (Exception e) { log.error("CurrentUserHandlerMethodArgumentResolver resolveArgument error.accessToken:{}", accessToken, e); } return null; } }
最後,別忘了註冊上自定義的參數解析器哦!
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) { argumentResolvers.add(new CurrentUserHandlerMethodArgumentResolver()); } }