上一节通过调用方法获取了Spring提供的参数解析器,这节通过案例测试这些参数解析器的工作方式。
MyRequestMappingHandlerAdapter handlerAdapter = applicationContext.getBean(MyRequestMappingHandlerAdapter.class);
handlerAdapter.getArgumentResolvers().forEach(System.out::println);
准备工作
准备配置以及Model
@Configuration
class WebConfig {
}
@Data
class User {
private String name;
private int age;
}
准备一个模拟控制器
分别测试
- @RequestParam参数
- 不带@RequestParam参数
- @RequestParam int类型
- @RequestParam中默认值是Spring环境参数
- @RequestParam 文件类型的
- @PathVariable
- @RequestHeader
- @CookieValue
- @Value
- HttpServletRequest
- @ModelAttribute
- 不带@ModelAttribute参数
- @RequestBody
class TestController {
public void test(
@RequestParam("name1") String name1, // name1=张三
String name2, // name2=李四 不带注解@RequestParam
@RequestParam("age") int age, // age=18 默认字符串 需要处理类型转换
@RequestParam(name = "home", defaultValue = "${JAVA_HOME}") String home1, // Spring环境获取数据
@RequestParam("file") MultipartFile file, //文件上传
@PathVariable("id") int id, // 请求路径参数 /test/124 test/{id}
@RequestHeader("Content-Type") String header, // 请求头参数
@CookieValue("token") String token, // cookie获取数据
@Value("${JAVA_HOME}") String home2, // Spring环境获取数据
HttpServletRequest request, // request,response,session
@ModelAttribute("abc") User user1, // name=张三&age=18
User user2, // name=张三&age=18 省略@ModelAttribute
@RequestBody User user3 // json
) {
}
}
准备一个模拟请求
private static HttpServletRequest mockRequest() {
MockHttpServletRequest request = new MockHttpServletRequest();
// @RequestParam
request.setParameter("name1", "张三");
request.setParameter("name2", "李四");
request.setParameter("age", "18");
// 文件
request.addPart(new MockPart("file", "abc", "hello world".getBytes(StandardCharsets.UTF_8)));
// @PathVariable 解析路径参数并放入RequestAttribute中
Map<String, String> uriTemplateVariables = new AntPathMatcher().extractUriTemplateVariables("/test/{id}", "/test/124");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);
// @RequestHeader
request.setContentType("application/json");
// @CookieValue
request.setCookies(new Cookie("token", "2345"));
// @ModelAttribute
request.setParameter("name", "张三");
// @RequestBody
request.setContent("{\"name\": \"李四\", \"age\":\"20\"}".getBytes(StandardCharsets.UTF_8));
return new StandardServletMultipartResolver().resolveMultipart(request);
}
RequestParamMethodArgumentResolver
// 0. 准备Spring环境 非Web环境
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class);
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
// 1. 准备请求
HttpServletRequest request = mockRequest();
// 2. 准备控制器方法
HandlerMethod handlerMethod = new HandlerMethod(new TestController(), TestController.class.getMethod("test", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));
// 3. 准备绑定对象的类型转换 处理数据类型转换 例如 字符串->数字
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(null, null);
// 4. 准备 ModelAndViewContainer容器存储中间Model对象
ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();
// RequestParam参数解析器 false表示参数上必须有注解才会解析
RequestParamMethodArgumentResolver requestParamMethodArgumentResolver = new RequestParamMethodArgumentResolver(beanFactory, false);
// 5. 解析每个参数的值
for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) {
// 获取这个参数的注解
String annotationVal = Arrays.stream(methodParameter.getParameterAnnotations()).map(annotation -> annotation.annotationType().getSimpleName()).collect(Collectors.joining());
String paramAnnotation = StrUtil.isNotBlank(annotationVal) ? "@" + annotationVal + " " : " ";
// 参数名生成
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
StringBuilder ret = new StringBuilder("[").append(methodParameter.getParameterIndex()).append("] ").append(paramAnnotation)
.append(methodParameter.getParameterType().getSimpleName()).append(" ").append(methodParameter.getParameterName());
if (requestParamMethodArgumentResolver.supportsParameter(methodParameter)) {
Object paramValue = requestParamMethodArgumentResolver.resolveArgument(methodParameter, modelAndViewContainer, new ServletWebRequest(request), servletRequestDataBinderFactory);
// System.out.println("解析的参数类型" + paramValue.getClass());
ret.append("->").append(paramValue);
}
System.out.println(ret);
}
组合模式
如果对每个参数进行所有解析器逐个supportsParameter判断解析,代码会很啰嗦,Spring中使用组合模式进行参数解析.
// 0. 准备Spring环境
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class);
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
// 1. 准备请求
HttpServletRequest request = mockRequest();
// 2. 准备控制器方法
HandlerMethod handlerMethod = new HandlerMethod(new TestController(), TestController.class.getMethod("test", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));
// 3. 准备绑定对象的类型转换 处理数据类型转换 例如 字符串->数字
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(null, null);
// 4. 准备 ModelAndViewContainer容器存储中间Model对象
ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();
// 组合模式
HandlerMethodArgumentResolverComposite resolverComposite = new HandlerMethodArgumentResolverComposite();
resolverComposite.addResolvers(
// RequestParam参数解析器 false表示参数上必须有注解才会解析
new RequestParamMethodArgumentResolver(beanFactory, false)
);
// 5. 解析每个参数的值
for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) {
// 获取这个参数的注解
String annotationVal = Arrays.stream(methodParameter.getParameterAnnotations()).map(annotation -> annotation.annotationType().getSimpleName()).collect(Collectors.joining());
String paramAnnotation = StrUtil.isNotBlank(annotationVal) ? "@" + annotationVal + " " : " ";
// 参数名生成
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
StringBuilder ret = new StringBuilder("[").append(methodParameter.getParameterIndex()).append("] ").append(paramAnnotation)
.append(methodParameter.getParameterType().getSimpleName()).append(" ").append(methodParameter.getParameterName());
if (resolverComposite.supportsParameter(methodParameter)) {
Object paramValue = resolverComposite.resolveArgument(methodParameter, modelAndViewContainer, new ServletWebRequest(request), servletRequestDataBinderFactory);
// System.out.println("解析的参数类型" + paramValue.getClass());
ret.append("->").append(paramValue);
}
System.out.println(ret);
}
其余参数解析器
// 0. 准备Spring环境
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig.class);
DefaultListableBeanFactory beanFactory = applicationContext.getDefaultListableBeanFactory();
// 1. 准备请求
HttpServletRequest request = mockRequest();
// 2. 准备控制器方法
HandlerMethod handlerMethod = new HandlerMethod(new TestController(), TestController.class.getMethod("test", String.class, String.class, int.class, String.class, MultipartFile.class, int.class, String.class, String.class, String.class, HttpServletRequest.class, User.class, User.class, User.class));
// 3. 准备绑定对象的类型转换 处理数据类型转换 例如 字符串->数字
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(null, null);
// 4. 准备 ModelAndViewContainer容器存储中间Model对象
ModelAndViewContainer modelAndViewContainer = new ModelAndViewContainer();
// 组合模式
HandlerMethodArgumentResolverComposite resolverComposite = new HandlerMethodArgumentResolverComposite();
resolverComposite.addResolvers(
// @RequestParam参数解析器 false表示参数上必须有注解才会解析
new RequestParamMethodArgumentResolver(beanFactory, false),
// @PathVariable
new PathVariableMethodArgumentResolver(),
// @RequestHeader
new RequestHeaderMethodArgumentResolver(beanFactory),
// @CookieValue
new ServletCookieValueMethodArgumentResolver(beanFactory),
// Spring表达式参数解析器
new ExpressionValueMethodArgumentResolver(beanFactory),
// HttpServletRequest
new ServletRequestMethodArgumentResolver(),
// 是否不需要注解@ModelAttribute false:需要 即没有@ModelAttribute的实体参数不解析
new ServletModelAttributeMethodProcessor(false),
// @RequestBody
new RequestResponseBodyMethodProcessor(CollUtil.newArrayList(new MappingJackson2HttpMessageConverter())),
/**
*是否不需要注解@ModelAttribute true:不需要 即没有@ModelAttribute的实体参数也解析
* 注意!!! 这个解析器必须放在@RequestBody解析器后面,否则这个解析器将会优先被使用去解析
*/
new ServletModelAttributeMethodProcessor(true),
/**
* @RequestParam 参数解析器 true表示参数上没有注解也会解析
* 注意!!! 这个解析器必须放在后面 否则其它类型参数将使用这个解析器解析
*/
new RequestParamMethodArgumentResolver(beanFactory, true)
);
// 5. 解析每个参数的值
for (MethodParameter methodParameter : handlerMethod.getMethodParameters()) {
// 获取这个参数的注解
String annotationVal = Arrays.stream(methodParameter.getParameterAnnotations()).map(annotation -> annotation.annotationType().getSimpleName()).collect(Collectors.joining());
String paramAnnotation = StrUtil.isNotBlank(annotationVal) ? "@" + annotationVal + " " : " ";
// 参数名生成
methodParameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
StringBuilder ret = new StringBuilder("[").append(methodParameter.getParameterIndex()).append("] ").append(paramAnnotation)
.append(methodParameter.getParameterType().getSimpleName()).append(" ").append(methodParameter.getParameterName());
if (resolverComposite.supportsParameter(methodParameter)) {
Object paramValue = resolverComposite.resolveArgument(methodParameter, modelAndViewContainer, new ServletWebRequest(request), servletRequestDataBinderFactory);
// System.out.println("解析的参数类型" + paramValue.getClass());
ret.append("->").append(paramValue);
}
System.out.println(ret);
System.out.println("模型数据为:" + modelAndViewContainer.getModel());
}
类型转换器
准备Bean
准备一个带Getter,Setter的Bean,和一个不带Getter,Setter的Bean
@Getter
@Setter
@ToString
class Bean1 {
private int a;
private String b;
private Date c;
}
@ToString
class Bean2 {
private int a;
private String b;
private Date c;
}
SimpleTypeConverter
private static void testSimpleTypeConverter() {
// 仅有类型转换功能
SimpleTypeConverter simpleTypeConverter = new SimpleTypeConverter();
Integer num = simpleTypeConverter.convertIfNecessary("12", int.class);
Date date = simpleTypeConverter.convertIfNecessary("2023/03/19", Date.class);
System.out.println("num = " + num);
System.out.println("date = " + date);
}
BeanWrapperImpl
private static void testBeanWrapper() {
Bean1 target = new Bean1();
// 通过反射调用Bean的get set方法 所操作的属性必须要有set方法
BeanWrapperImpl beanWrapper = new BeanWrapperImpl(target);
beanWrapper.setPropertyValue("a", "123");
beanWrapper.setPropertyValue("b", "456");
beanWrapper.setPropertyValue("c", "2023/03/19");
System.out.println("target = " + target);
}
DirectFieldAccessor
private static void testDirectFieldAccessor() {
Bean2 target = new Bean2();
// 通过反射调用 直接操作bean的属性
DirectFieldAccessor directFieldAccessor = new DirectFieldAccessor(target);
directFieldAccessor.setPropertyValue("a", "123");
directFieldAccessor.setPropertyValue("b", "456");
directFieldAccessor.setPropertyValue("c", "2023/03/19");
System.out.println("target = " + target);
}
数据绑定器
DataBinder+BeanWrapperImpl
private static void testDataBinder() {
Bean1 target = new Bean1();
// 默认走反射调用set方法的方式 即BeanWrapperImpl
DataBinder dataBinder = new DataBinder(target);
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("a", "123");
propertyValues.add("b", "456");
propertyValues.add("c", "2023/03/19");
dataBinder.bind(propertyValues);
System.out.println(target);
}
DataBinder+DirectFieldAccessor
private static void testDataBinder2() {
Bean2 target = new Bean2();
DataBinder dataBinder = new DataBinder(target);
// 改成走DirectFieldAccessor方式
dataBinder.initDirectFieldAccess();
MutablePropertyValues propertyValues = new MutablePropertyValues();
propertyValues.add("a", "123");
propertyValues.add("b", "456");
propertyValues.add("c", "2023/03/19");
dataBinder.bind(propertyValues);
System.out.println(target);
}
ServletRequestDataBinder
private static void testWebDataBinder() {
Bean1 target = new Bean1();
ServletRequestDataBinder servletRequestDataBinder = new ServletRequestDataBinder(target);
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("a", "123");
request.setParameter("b", "456");
request.setParameter("c", "2023/03/19");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
servletRequestDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
WebDataBinder
准备对象
@Data
static class User {
private Date birthday;
private Address address;
}
@Data
static class Address {
private String name;
}
正常绑定
private static void testWebDataBinder2() {
MockHttpServletRequest request = new MockHttpServletRequest();
// 无法解析
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
ServletRequestDataBinder servletRequestDataBinder = new ServletRequestDataBinder(target);
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
servletRequestDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
使用无参工厂进行绑定
@SneakyThrows
private static void testWebDataBinderFactory() {
MockHttpServletRequest request = new MockHttpServletRequest();
// 无法解析
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(null, null);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
使用带@InitBinder的工厂进行绑定
准备时间格式化器
@Slf4j
@RequiredArgsConstructor
public class MyDateFormatter implements Formatter<Date> {
private final String desc;
@Override
public Date parse(String text, Locale locale) throws ParseException {
log.warn("=====>进入了:{}", desc);
return DateUtil.parse(text, "yyyy|MM|dd");
}
@Override
public String print(Date object, Locale locale) {
log.warn("=====>进入了:{}", desc);
return DateUtil.format(object, "yyyy|MM|dd");
}
}
准备局部@InitBinder
static class MyController {
@InitBinder
public void a(WebDataBinder webDataBinder) {
// 扩展dataBinder的转换器
webDataBinder.addCustomFormatter(new MyDateFormatter("MyController下@InitBinder进行扩展"));
}
}
测试
@SneakyThrows
private static void testInitBinder() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
InvocableHandlerMethod invocableHandlerMethod = new InvocableHandlerMethod(new MyController(), MyController.class.getMethod("a", WebDataBinder.class));
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(
CollUtil.newArrayList(invocableHandlerMethod),
null);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
使用带ConversionService的工厂进行绑定
@SneakyThrows
private static void testConversionService() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
FormattingConversionService formattingConversionService = new FormattingConversionService();
formattingConversionService.addFormatter(new MyDateFormatter("FormattingConversionService进行扩展"));
ConfigurableWebBindingInitializer configurableWebBindingInitializer = new ConfigurableWebBindingInitializer();
configurableWebBindingInitializer.setConversionService(formattingConversionService);
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(
null,
configurableWebBindingInitializer);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
使用带@InitBinder和ConversionService的工厂进行绑定
private static void testInitBinderAndConversionService() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
InvocableHandlerMethod invocableHandlerMethod = new InvocableHandlerMethod(new MyController(), MyController.class.getMethod("a", WebDataBinder.class));
FormattingConversionService formattingConversionService = new FormattingConversionService();
formattingConversionService.addFormatter(new MyDateFormatter("FormattingConversionService进行扩展"));
ConfigurableWebBindingInitializer configurableWebBindingInitializer = new ConfigurableWebBindingInitializer();
configurableWebBindingInitializer.setConversionService(formattingConversionService);
// @InitBinder优先级比ConversionService高
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(
CollUtil.newArrayList(invocableHandlerMethod),
configurableWebBindingInitializer);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
DefaultFormattingConversionService
@SneakyThrows
private static void testDefaultConversionService() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
// 需要搭配注解 @DateTimeFormat(pattern = "yyyy|MM|dd") springmvc
DefaultFormattingConversionService defaultFormattingConversionService = new DefaultFormattingConversionService();
ConfigurableWebBindingInitializer configurableWebBindingInitializer = new ConfigurableWebBindingInitializer();
configurableWebBindingInitializer.setConversionService(defaultFormattingConversionService);
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(
null,
configurableWebBindingInitializer);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
ApplicationConversionService
@SneakyThrows
private static void testApplicationConversionService() {
MockHttpServletRequest request = new MockHttpServletRequest();
request.setParameter("birthday", "1994|07|08");
request.setParameter("address.name", "上海");
User target = new User();
// 需要搭配注解 @DateTimeFormat(pattern = "yyyy|MM|dd") springboot
ApplicationConversionService applicationConversionService = new ApplicationConversionService();
ConfigurableWebBindingInitializer configurableWebBindingInitializer = new ConfigurableWebBindingInitializer();
configurableWebBindingInitializer.setConversionService(applicationConversionService);
ServletRequestDataBinderFactory servletRequestDataBinderFactory = new ServletRequestDataBinderFactory(
null,
configurableWebBindingInitializer);
WebDataBinder webDataBinder = servletRequestDataBinderFactory.createBinder(new ServletWebRequest(request), target, "target");
ServletRequestParameterPropertyValues propertyValues = new ServletRequestParameterPropertyValues(request);
webDataBinder.bind(propertyValues);
System.out.println("target = " + target);
}
@InitBinder配置方式
@InitBinder 的来源有两个
- @ControllerAdvice中的@InitBinder方法,由RequestMappingHandlerAdapter在初始化时解析并记录。
- Controller中的@InitBinder,由RequestMappingHandlerAdapter在控制器的任意方法首次执行时解析并记录。
配置@InitBinder
@Configuration
public class WebConfig2 {
@Controller
static class Controller1 {
/**
* 添加当前Controller局部转换器 由RequestMappingHandlerAdapter在控制器的任意方法首次执行时解析并记录。
*/
@InitBinder
public void binder1(WebDataBinder webDataBinder) {
webDataBinder.addCustomFormatter(new MyDateFormatter("binder1转换器"));
}
public void foo() {
}
}
@Controller
static class Controller2 {
/**
* 添加当前Controller局部转换器
*/
@InitBinder
public void binder21(WebDataBinder webDataBinder) {
webDataBinder.addCustomFormatter(new MyDateFormatter("binder2-1转换器"));
}
@InitBinder
public void binder22(WebDataBinder webDataBinder) {
webDataBinder.addCustomFormatter(new MyDateFormatter("binder2-2转换器"));
}
public void bar() {
}
}
@ControllerAdvice
static class MyControllerAdvice {
/**
* 添加全局转换器 由RequestMappingHandlerAdapter在初始化时解析并记录。
*/
@InitBinder
public void binder3(WebDataBinder webDataBinder) {
webDataBinder.addCustomFormatter(new MyDateFormatter("binder3转换器"));
}
// @ExceptionHandler
// @ModelAttribute
}
}
验证
@Slf4j
public class TestWebDataBinder {
@SneakyThrows
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(WebConfig2.class);
RequestMappingHandlerAdapter requestMappingHandlerAdapter = new RequestMappingHandlerAdapter();
requestMappingHandlerAdapter.setApplicationContext(applicationContext);
requestMappingHandlerAdapter.afterPropertiesSet();
// 全局的
log.warn("刚开始...");
showBindMethods(requestMappingHandlerAdapter);
Method getDataBinderFactoryMethod = RequestMappingHandlerAdapter.class.getDeclaredMethod("getDataBinderFactory", HandlerMethod.class);
getDataBinderFactoryMethod.setAccessible(true);
// 模拟调用Controller1局部方法foo
getDataBinderFactoryMethod.invoke(requestMappingHandlerAdapter, new HandlerMethod(new WebConfig2.Controller1(), WebConfig2.Controller1.class.getMethod("foo")));
showBindMethods(requestMappingHandlerAdapter);
// 模拟调用Controller2局部方法bar
getDataBinderFactoryMethod.invoke(requestMappingHandlerAdapter, new HandlerMethod(new WebConfig2.Controller2(), WebConfig2.Controller2.class.getMethod("bar")));
showBindMethods(requestMappingHandlerAdapter);
applicationContext.close();
}
@SneakyThrows
public static void showBindMethods(RequestMappingHandlerAdapter handlerAdapter) {
Field initBinderAdviceCacheField = RequestMappingHandlerAdapter.class.getDeclaredField("initBinderAdviceCache");
initBinderAdviceCacheField.setAccessible(true);
Map<ControllerAdviceBean, Set<Method>> globalMap = (Map<ControllerAdviceBean, Set<Method>>) initBinderAdviceCacheField.get(handlerAdapter);
log.warn("ControllerAdvice全局的@InitBinder方法:{}", globalMap.values().stream().flatMap(methods ->
methods.stream().map(Method::getName)).collect(Collectors.toList()));
Field initBinderCacheField = RequestMappingHandlerAdapter.class.getDeclaredField("initBinderCache");
initBinderCacheField.setAccessible(true);
Map<Class<?>, Set<Method>> localMap = (Map<Class<?>, Set<Method>>) initBinderCacheField.get(handlerAdapter);
log.warn("控制器局部的@InitBinder方法:{}", localMap.values().stream().flatMap(methods ->
methods.stream().map(Method::getName)).collect(Collectors.toList()));
}
}
获取泛型类型
准备泛型类
static class Teacher {
}
static class TeacherMapper {
}
static class BaseDAO<M, E> {
}
static class TeacherDAO extends BaseDAO<TeacherMapper, Teacher> {
}
JDK方式获取泛型类型
private static void testJDKGetGenericTypeName() {
// 获取带有范型的父类
Type genericSuperclass = TeacherDAO.class.getGenericSuperclass();
System.out.println(genericSuperclass);
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
System.out.println(parameterizedType.getActualTypeArguments()[0]);
System.out.println(parameterizedType.getActualTypeArguments()[1]);
}
}
Spring方式获取泛型类型
private static void testSpringGetGenericTypeName() {
Class<?>[] typeArguments = GenericTypeResolver.resolveTypeArguments(TeacherDAO.class, BaseDAO.class);
for (Class<?> typeArgument : typeArguments) {
System.out.println(typeArgument);
}
}