SpringBoot中自定义参数解析器,实现如@RequestParam的功能
1. 自定义参数解析器
1-1 参数解析器要实现的接口 (内置接口,这里作解释用)
public interface HandlerMethodArgumentResolver {
boolean supportsParameter(MethodParameter parameter);
@Nullable
Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception;
}
1-2 自定义参数解析器示例
1-2-1 示例需求描述
需求描述:
假设有这样一个需求,在方法的参数上添加了 @CurrentUserName 注解(名称自己定义的),
那么该参数的值就是当前登录的用户名,像下面这样:
@RestController
public class HelloController {
@GetMapping("/hello")
public String hello(@CurrentUserName String name) {
return "hello "+name;
}
}
1-2-2 自定义一个 @CurrentUserName 注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface CurrentUserName {
}
1-2-3 自定义参数解析器 CurrentUserNameHandlerMethodArgumentResolver
public class CurrentUserNameHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.getParameterType().isAssignableFrom(String.class)&¶meter.hasParameterAnnotation(CurrentUserName.class);
}
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
User user = (User) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return user.getUsername();
}
}
1-2-4 新建配置类WebConfig,将自定义的参数解析器配置到 HandlerAdapter
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
resolvers.add(new CurrentUserNameHandlerMethodArgumentResolver());
}
}
2. 内置@RequestParam注解 的 代码参考
2-1 日常使用示例
@RestController
public class HelloController {
@PostMapping("/hello")
public void hello(@RequestParam MultiValueMap map) throws IOException {
}
}
2-2 RequestParamMapMethodArgumentResolver解析器代码
public class RequestParamMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
RequestParam requestParam = parameter.getParameterAnnotation(RequestParam.class);
return (requestParam != null && Map.class.isAssignableFrom(parameter.getParameterType()) &&
!StringUtils.hasText(requestParam.name()));
}
@Override
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
if (MultiValueMap.class.isAssignableFrom(parameter.getParameterType())) {
Class<?> valueType = resolvableType.as(MultiValueMap.class).getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getMultiFileMap() : new LinkedMultiValueMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection<Part> parts = servletRequest.getParts();
LinkedMultiValueMap<String, Part> result = new LinkedMultiValueMap<>(parts.size());
for (Part part : parts) {
result.add(part.getName(), part);
}
return result;
}
return new LinkedMultiValueMap<>(0);
}
else {
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;
}
}
else {
Class<?> valueType = resolvableType.asMap().getGeneric(1).resolve();
if (valueType == MultipartFile.class) {
MultipartRequest multipartRequest = MultipartResolutionDelegate.resolveMultipartRequest(webRequest);
return (multipartRequest != null ? multipartRequest.getFileMap() : new LinkedHashMap<>(0));
}
else if (valueType == Part.class) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
if (servletRequest != null && MultipartResolutionDelegate.isMultipartRequest(servletRequest)) {
Collection<Part> parts = servletRequest.getParts();
LinkedHashMap<String, Part> result = CollectionUtils.newLinkedHashMap(parts.size());
for (Part part : parts) {
if (!result.containsKey(part.getName())) {
result.put(part.getName(), part);
}
}
return result;
}
return new LinkedHashMap<>(0);
}
else {
Map<String, String[]> parameterMap = webRequest.getParameterMap();
Map<String, String> result = CollectionUtils.newLinkedHashMap(parameterMap.size());
parameterMap.forEach((key, values) -> {
if (values.length > 0) {
result.put(key, values[0]);
}
});
return result;
}
}
}
}