Spring MVC实现自定义参数注解
如果熟悉SpringMVC原理和相关代码的话,就比较容易实现。关键点就是HandlerMethodArgumentResolver类—>实现请求参数解析
SpringMVC默认提供实现
- 常见实现类-类图
- 常见参数注解说明–更多实现可以查看HandlerMethodArgumentResolver子类
类名 | 支持注解 | 备注说明 |
---|---|---|
PathVariableMapMethodArgumentResolver | 支持注解@PathVariable | 能够实现参数转换成Map |
RequestParamMapMethodArgumentResolver | 支持注解@RequestParam | 能够实现参数转换Map |
RequestAttributeMethodArgumentResolver | 支持注解@RequestAttribute | 能够获取WebRequest参数转换到Map |
RequestHeaderMapMethodArgumentResolver | 支持注解@RequestHeader | 能够获取RequestHeader参数转换到Map |
- 默认添加HandlerMethodArgumentResolver实现类对应的方法–org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#getDefaultArgumentResolvers
注意点:从代码可以参数优先级是通过添加顺序来控制的
private List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<>(30);
// Annotation-based argument resolution
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new PathVariableMapMethodArgumentResolver());
resolvers.add(new MatrixVariableMethodArgumentResolver());
resolvers.add(new MatrixVariableMapMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false));
resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
resolvers.add(new RequestHeaderMapMethodArgumentResolver());
resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
resolvers.add(new SessionAttributeMethodArgumentResolver());
resolvers.add(new RequestAttributeMethodArgumentResolver());
// Type-based argument resolution
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(getMessageConverters(), this.requestResponseBodyAdvice));
resolvers.add(new RedirectAttributesMethodArgumentResolver());
resolvers.add(new ModelMethodProcessor());
resolvers.add(new MapMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
resolvers.add(new SessionStatusMethodArgumentResolver());
resolvers.add(new UriComponentsBuilderMethodArgumentResolver());
if (KotlinDetector.isKotlinPresent()) {
resolvers.add(new ContinuationHandlerMethodArgumentResolver());
}
// Custom arguments
if (getCustomArgumentResolvers() != null) {
resolvers.addAll(getCustomArgumentResolvers());
}
// Catch-all
resolvers.add(new PrincipalMethodArgumentResolver());
resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
- 参数属性来源
1、spring 容器Bean
2、request 参数
3、外部化配置属性
4、servlet 容器参数
实现自定义参数注解步骤
- 自定义注解类
import java.lang.annotation.*;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface MyMvcReqParam {
String value() default "";
}
- 实现HandlerMethodArgumentResolver类,并实现supportsParameter和resolveArgument方法
import org.springframework.core.MethodParameter;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
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 java.util.Map;
/**
* 处理@MyMvcReqParam注解
*/
public class MyMvcReqParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
MyMvcReqParam ann = parameter.getParameterAnnotation(MyMvcReqParam.class);
return (ann != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(ann.value()));
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
//将参数转换成map对象
Map<String, String[]> parameterMap = webRequest.getParameterMap();
MultiValueMap<String, String> result = new LinkedMultiValueMap<>(parameterMap.size());
parameterMap.forEach((key, values) -> {
for (String value : values) {
result.add(key, value);
}
});
return result;
}
}
- 将实现HandlerMethodArgumentResolver类,添加到SpringMVC对应的RequestMappingHandlerAdapter类中
@Configuration
public class MyWebMvcConfig implements WebMvcConfigurer {
/**
* add formatter registry
*
* @param registry
*/
@Override
public void addFormatters(FormatterRegistry registry) {
DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
registrar.setUseIsoFormat(true);
registry.addConverter(new StringToDataConverter());
registrar.registerFormatters(registry);
}
/**
* 添加自定义HandlerMethodArgumentResolver
* @param resolvers
*/
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new MyMvcReqParamMapMethodArgumentResolver());
WebMvcConfigurer.super.addArgumentResolvers(resolvers);
}
}
总结
如果要实现一个简单的自定义注解,只要按照上述步骤进行实现就行,如果要实现比较复杂的实现类,可以参考ModelAttributeMethodProcessor。如果要深入使用,需要对Spring core源码有一定了解,才能更好的利用Spring框架提供的功能进行扩展。