HandlerMethodArgumentResolver 用於將方法參數解析爲參數值的策略接口,我們常說的自定義參數解析器,源碼如下
/** * Strategy interface for resolving method parameters into argument values in * the context of a given request. * * @author Arjen Poutsma * @since 3.1 * @see HandlerMethodReturnValueHandler */ public interface HandlerMethodArgumentResolver { /** * Whether the given {@linkplain MethodParameter method parameter} is * supported by this resolver. * @param parameter the method parameter to check * @return {@code true} if this resolver supports the supplied parameter; * {@code false} otherwise */ boolean supportsParameter(MethodParameter parameter); /** * Resolves a method parameter into an argument value from a given request. * A {@link ModelAndViewContainer} provides access to the model for the * request. A {@link WebDataBinderFactory} provides a way to create * a {@link WebDataBinder} instance when needed for data binding and * type conversion purposes. * @param parameter the method parameter to resolve. This parameter must * have previously been passed to {@link #supportsParameter} which must * have returned {@code true}. * @param mavContainer the ModelAndViewContainer for the current request * @param webRequest the current request * @param binderFactory a factory for creating {@link WebDataBinder} instances * @return the resolved argument value, or {@code null} if not resolvable * @throws Exception in case of errors with the preparation of argument values */ @Nullable Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception; }
下面是我的一個小例子,主要是通過自定義參數解析器去將分頁參數,提取出來封裝成實體對象
1.首先自定義一個註解
/** * @Author: 虞雲波(18088704) * @Date: 2020/11/7 10:18 * @Description: */ @Target(ElementType.PARAMETER) @Inherited @Documented @Retention(RetentionPolicy.RUNTIME) public @interface CustomArgumentPage { }
2.寫一個自定義參數解析器實現類
import com.suning.logistics.jwms.on.base.vo.PageBean; import org.apache.commons.lang3.StringUtils; import org.springframework.core.MethodParameter; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.ModelAndViewContainer; import javax.servlet.http.HttpServletRequest; /** * @Author: 虞雲波(18088704) * @Date: 2020/11/7 10:14 * @Description: */ public class CustomArgumentResolvers implements HandlerMethodArgumentResolver { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(CustomArgumentPage.class); } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); String page = request.getParameter("page"); String pageSize = request.getParameter("pageSize"); PageBean pageBean = new PageBean(); if (StringUtils.isNotEmpty(page)) { pageBean.setCurrentPage(Integer.valueOf(page).intValue()); } if (StringUtils.isNotEmpty(pageSize)) { pageBean.setPageSize(Integer.valueOf(pageSize).intValue()); } pageBean.setStartPage((pageBean.getCurrentPage()-1)*pageBean.getPageSize()); return pageBean; } }
3.將自定義解析器注入到IOC 中
@Bean public CustomArgumentResolvers initCustomArgumentResolvers(){ return new CustomArgumentResolvers(); }
4.將自定義的參數解析器,注入到MvcConfigure中
@Configuration public class WebMvcCustomConfigurer implements WebMvcConfigurer { @Autowired private CustomArgumentResolvers customArgumentResolvers; /** * Add resolvers to support custom controller method argument types. * <p>This does not override the built-in support for resolving handler * method arguments. To customize the built-in support for argument * resolution, configure {@link RequestMappingHandlerAdapter} directly. * * @param resolvers initially an empty list */ @Override public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) { resolvers.add(customArgumentResolvers); } }
5.編寫測試Controller
@RequestMapping("/queryPageConfigList") @ResponseBody public Object getWarehouseCodeReadyonly(@CustomArgumentPage PageBean pageBean){ return warehouseConfigService.queryPage(pageBean,null); }
6.效果如下
下面源碼分析一波,講述一下整個流程,
1.在Springboot AutoConfiguration 會自動注入 WebMvcAutoConfiguration
2.在WebMvcAutoConfiguration 中 靜態內部類 EnableWebMvcConfiguration它繼承了DelegatingWebMvcConfiguration這個類,這個很重要,中的 requestMappingHandlerAdapter方法,初始化HandlerAdapter
super.requestMappingHandlerAdapter()
3.在父類WebMvcConfigurationSupport 中,如下圖 565行代碼,會給HandlerAdapter 設置自定義的參數解析器
4.進入getArgumentResolvers方法,核心方法 addArgumentResolvers
5.是個空方法???,源碼跟蹤是進入了其子類 DelegatingWebMvcConfiguration 這個類中
6.繼續代碼跟蹤下一步,會到WebMvcConfigurerComposite 中addArgumentResolvers 方法,會循環WebMvcConfigurer List 調用裏面的 addArgumentResolvers 至於這個this.delegates 怎麼初始化的,你們可以自己研究一下
7.最終調到我們自定義的WebMvcCustomConfigurer 中,將我們自定義的參數解析器,添加到整個參數解析List中
8.將數參數解析List 設置到HandlerAdapter 中
9.調用的時候,整個調用鏈如下圖,剛興趣的同學可以自己去分析一下