今天深入了一下spring mvc里面的代码,了解到几个部分 处理器适配器 和处理器适配器里面的处理器参数解析器,然后写了一个自定义的处理器参数解析器对参数进行包装直接上代码
我们先定义一个拦截器处理器
@Component
public class MyInterceptorImpl implements HandlerInterceptor {
/**
* 定义前置拦截器
*
* @param request servlet封装的请求对象
* @param response servlet封装的响应对象
* @param handler 处理器
* @return
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
System.out.println("前置拦截器执行");
request.setAttribute("testInterceptor","这就是爱情");
return true;
}
}
然后在定义一个拦截器 对指定路径的对象进行拦截封装
@Configuration
public class MyInterceptor implements WebMvcConfigurer {
@Autowired
private MyInterceptorImpl myInterceptor;
/**
* 对指定controller地址进行添加拦截器
*
* @param registry 注册器
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
System.out.println("进入拦截器");
registry.addInterceptor(myInterceptor).addPathPatterns("/*/interceptor/**");
}
}
之后创建自定义的处理器参数处理器
@Component
public class MyHandlerArgumentResolver implements HandlerMethodArgumentResolver {
/**
* 注入springboot的处理器适配器
* */
@Autowired
private RequestMappingHandlerAdapter adapter;
/**
* 当前方法参数解析器会先调用supportsParameter如果返回true
* 才会调用resolverArgument
*
* @param methodParameter 处理器适配器的方法参数解析器
* @return 当前解析器是否支持携带指定参数
*/
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
// 判断我们controller里面的参数是否是Order的子类
return Order.class.isAssignableFrom(methodParameter.getParameterType());
}
/**
* 获取处理后的对象
*
* @param methodParameter 最终传递到controller里面的参数
* @param modelAndViewContainer 视图解析器
* @param nativeWebRequest 本地方法请求对象
* @param webDataBinderFactory 页面数据绑定的工厂
* @return 返回经过处理的后的对象,该对象一定是处理器也就是controller里面参数的父类
* @throws Exception
*/
@Override
public Object resolveArgument(@NotNull MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer,@NotNull NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory) throws Exception {
// 拿到非当前对象并且支持该参数的解析器
System.out.println("进入自定义解析器内部方法");
HandlerMethodArgumentResolver handlerMethodArgumentResolver =
returnHandlerMethodArgumentResolver(methodParameter);
System.out.println("获取到解析器的对象是"+handlerMethodArgumentResolver);
/**
* 通过该解析器获取到处理器里面的参数
* 因为上面supportsParameter是Order的子类才会执行当前方法
* 所以获取到的参数一定是Order子类的对象 强转成Order
* */
Order order = (Order) handlerMethodArgumentResolver.resolveArgument(methodParameter
, modelAndViewContainer, nativeWebRequest, webDataBinderFactory);
System.out.println("获取到处理器里面未封装的参数对象是"+order.toString());
// 从request里面获取数据 进行参数封装
order.setTestInterceptor(String.valueOf(nativeWebRequest.getAttribute("testInterceptor",0)));
return order;
}
public HandlerMethodArgumentResolver returnHandlerMethodArgumentResolver(MethodParameter methodParameter){
// 这里获取到的解析器就是我们添加了自定义的解析器后的了
List<HandlerMethodArgumentResolver> argumentResolvers = adapter.getArgumentResolvers();
if(CollectionUtils.isEmpty(argumentResolvers)){
return null;
}
for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) {
/*
这里不等于自己是因为为了通过处理器方法参数解析器来获取到传递到controller里面的参数对象
也是为了不让resolveArgument出现递归调用,最后会栈内存异常
*/
if (argumentResolver.supportsParameter(methodParameter) && argumentResolver != this) {
return argumentResolver;
}
}
return null;
}
}
之后就是将自定义的拦截器处理器添加到拦截器适配器里面
@Configuration
public class AutoMyHandlerArgumentResolver {
@Autowired
private RequestMappingHandlerAdapter adapter;
@Autowired
private MyHandlerArgumentResolver resolver;
@PostConstruct
public void autoHandler(){
// 获取到springboot内置的处理器方法参数解析器集合
System.out.println("进入到自定义解析器塞到适配器");
List<HandlerMethodArgumentResolver> argumentResolvers = adapter.getArgumentResolvers();
if (CollectionUtils.isNotEmpty(argumentResolvers)) {
// 定义自己的
List<HandlerMethodArgumentResolver> list = new ArrayList<>();
// 先添加自己的解析器
list.add(resolver);
System.out.println("自定义解析器的值是:"+resolver);
// 在添加springboot的解析器
list.addAll(argumentResolvers);
// 在将其塞回到适配器里面
adapter.setArgumentResolvers(list);
System.out.println("进入到自定义解析器塞到适配器结束");
}
}
}
简答的测试一下
@Data
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Order {
private String id;
private String name;
private String testInterceptor;
public Order(String id,String name){
this.id = id;
this.name = name;
}
}
public class OrderSon extends Order {
}
@PostMapping("/interceptor/test")
public void testInterceptor(@RequestBody OrderSon order){
/*这里的OrderSon对象是实现了Order我们上面
supportsParameter判断了处理器里面的参数是否属于Order*/
System.out.println("经过封装后进入到处理器内容部对象是:{}"+order.toString());
}
运行结果:
前置拦截器执行
进入自定义解析器内部方法
获取到解析器的对象是org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@7bf2b829
获取到处理器里面未封装的参数对象是Order(id=null, name=null, testInterceptor=null)
经过封装后进入到处理器内容部对象是:{}Order(id=null, name=null, testInterceptor=这就是爱情)
通过运行结果可以看到,通过处理器参数解析器刚拿到处理器里面的参数testIntercepote的值是null
经过逻辑后到处理器里面testInterceptor里面就有值了