MyCustomArgumentResolver:自定义请求参数解析器
MyCustomReturnValueHandler:自定义返回值处理器
MyResponse:返回值处理时使用的注释解决方案,analogy@ResponseBody
ResolverHandler配置 :参数解析器和返回值处理器的配置
ResponseResut:具体返回值,想想你项目中各个接口的返回值是否和一个泛型Type java类
Token2UserId:请求参数解析器使用的注解,类似于@RequestParam
以上是对各个职业的作用的简单介绍。定制的内容比较简单,主要是为了吸引别人。现在我们来谈谈这个自定义内容:
-
通过注解@TokenUserId将请求头中的token转换为userId。
-
标注注解@MyResponse注解,或者指定类型返回对象
ResponseResult
接口,使用我们自定义的接口进行处理,如果返回对象是 响应结果时,统一设置msg。
Token2UserId
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Token2UserId {
}
注解用于标记接口方法输入参数,以便自定义参数解析器能够识别。
MyCustomArgumentResolver
@Component
public classMyCustomArgumentResolver 实现 HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(方法参数参数) {
returnparameter.getParameterAnnotation (Token2UserId.class) != null;
}
@Override
公共 对象resolveArgument(MethodParameter参数、ModelAndViewContainer mavContainer、NativeWebRequest webRequest、WebDataBinderFactorybinderFactory)抛出异常 {
字符串令牌 = webRequest.getHeader("令牌");
返回 getUserIdByToken(token);
}
private字符串getUserIdByToken(字符串令牌) {
//这里通过去数据库或服务器,可以将token转换成userId
return token + ”:100";
}
}
逻辑比较简单,如果标记了@Token2UserId 注解,然后使用当前解析器进行解析。流程也很简单,从header中取出token值,然后通过token获取userId并返回。
该类用 @Component 进行注释。虽然是由Spring管理,但仅此还不够。我们的解析器还不能生效。这里添加这个注解主要是提到这里可以注入一些其他的bean,比如RedisTemplate
,用于用userId替换token。为了进行测试,我设置了 user=token+100
。
我的回复
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface 我的回复 {
}
注释用于标记方法,以便我们的返回值处理器可以识别它们。
响应结果
公共 类 响应结果<T> 实现 java.io.可序列化 {
私有 整数代码;
私有 字符串消息;
私有 T 数据;
公共 静态 响应结果 成功(T数据) {
响应结果 ret = new 响应结果<>();
ret.code = 0; www.sychzs.cn = 数据;
返回 ret;
}
}
看到这个内容并不是很熟悉了,我们一般在开发项目中,都会有一个统一的返回体,类似这样。
MyCustomReturnValueHandler
公共 类 MyCustomReturnValueHandler 实现 HandlerMethodReturnValueHandler {
@Override
public boolean 支持ReturnType(方法参数返回类型) {
//判断方法中是否包含自定义注解MyResonse或返回结果为指定类型
return returnType.getMethodAnnotation(MyResponse.class) ! = 空 || ResponseResult.class.isAssignableFrom(returnType。 getParameterType());
}
@Override
public void handleReturnValue(对象返回值、方法参数返回类型、ModelAndViewContainer mavContainer、NativeWebRequest webRequest) throws异常 {
//表示请求已处理完毕,spring稍后不会再处理
mavContainer.setRequestHandled() 真);
if(返回值!= null && ResponseResult.class.isAssignableFrom( returnType.getParameterType())) {
字符串消息 = ((ResponseResult>)returnValue).getCode() == 0 ? "成功" : "失败";
((ResponseResult>)returnValue).setMsg(msg);
}
HttpServletResponse 响应 = webRequest. getNativeResponse(HttpServletResponse.class);
response.setCharacterEncoding("UTF-8");
response.setContentType(" application/json;charset=UTF-8");
System.out.println("由MyCustomReturnValueHandler处理的返回值。");
response.getWriter().println (JSON.toJSONString(returnValue));
}
}
自定义的返回值处理器,就没有加@Component注解哦。逻辑比较简单,如果方法包含@MyResponse注解,或者类型是ResponseResult
及其子类,那么就采用我们的这个返回值处理器进行处理。
真正处理返回值的handlerReturnValue()方法中
-
我们首先标记请求已被处理(这个标记应该是第三次提到)。
-
然后我们判断如果返回类型是ResponseResult
及其子类,我们根据代码设置msg信息。
-
ResolverHandler配置
@Configuration(proxyBeanMethods = false)
公共类 ResolverHandlerConfiguration {
@Bean
publicWebMvcConfigurermyWebMvcConfigurer(@Autowired MyCustomArgumentResolver myCustomArgumentResolver) {
回归 新 WebMvcConfigurer() {
@Override
public void addArgumentResolvers(列表 参数解析器) {
// 将自定义请求参数解析器添加到解析器列表中
argumentResolvers.add(0, myCustomArgumentResolver);
}
@覆盖
public void addReturnValueHandlers(列表处理程序) {
//自定义我们的返回值handler添加到返回值处理程序列表
handlers.add(0, new MyCustomReturnValueHandler());
}
};
}
}
自定义 请求参数解析器 和 返回值处理器 配置方法,虽然我们调用的方法是添加到第0个集合的位置,但它并不是真正的第一个。
添加逻辑
我们的解析器添加逻辑全部在RequestMappingHandlerAdapter#afterPropeties()
方法中,在《Spring源码解析(第六弹)》中提到过,但不深入。这里特别注意,添加逻辑,先添加默认的,再添加自定义的,使用时不排序! ! !添加顺序是主要的! 所以这里我们实际上只是将第一个添加到自定义中。返回值处理程序也是如此。这是一个简单的代码。代码太长,影响阅读。逻辑是一样的。以解析器为例,只贴出解析器部分。
public void afterPropertiesSet() {
...
如果 (这个.argumentResolvers == null){
列表解析器 = getDefaultArgumentResolvers();
这个.argumentResolvers = 新 HandlerMethodArgumentResolverComposite().addResolvers(解析器);
}
...
}
私有列表 getDefaultArgumentResolvers() {
List 解析器 = new ArrayList<>();
//这里会添加一堆默认的
...
//添加自定义
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(get CustomArgumentResolvers());
}
返回解析器;
}
测试接口
@Controller
公共 类TestController {
@GetMapping("/testResolverHandler" )
@MyResponse
公共响应结果 testResolverHandler(@Token2UserId String userId){
返回 ResponseResult.success(userId);
}
}
这个地方需要注意。我使用@Controller而不是@RestController,并且该方法没有标记@ResponseBody注释!
当我们使用自定义返回值处理时,如上所述,是默认优先级,不支持排序。因此,如果我们使用@ResponseBody,那么就会默认的返回值处理器已经处理完毕,而我们自定义的返回值处理器就没有轮到了!
结果调试,图有真相
获取http://localhost:8080/testResolverHandler
接受:*/*
令牌:abcd