Spring Boot Controller 全类型参数解析器 - 枚举、日期、支持自定义类型(需要在笔者自己写的 ConvertUtil 中实现转换)
前言
在 Controller
处理 Get
/ Post
等请求时,将前端传递的参数反序列化为 Enum
类型。
本文将使用笔者自己写的 ConvertUtil
工具类进行基本的 Obejct
转 Enum<E>
类型转换。
传送门 : 自定义 ConvertUtil 值转换工具类
一共分三步:
- 创建自定义参数解析器
- 配置参数解析器
- 声明并管理自动配置类
创建自定义参数解析器
package com.demo.common.security.resolver;
import com.demo.common.core.utils.converter.ConvertUtil;
import org.springframework.core.MethodParameter;
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.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 自定义参数解析器
*
* @author HeHTao
* @date 2024/05/20
*/
public class CustomArgumentResovler implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
// 最终都走该参数解析器
return true;
}
@Override
public Object resolveArgument(MethodParameter parameter
, ModelAndViewContainer mavContainer
, NativeWebRequest webRequest
, WebDataBinderFactory binderFactory) {
Class<?> paramType = parameter.getParameterType();
Map<String, String[]> paramsMap = webRequest.getParameterMap();
// 已在工具中实现的转换类型,直接转换
if (ConvertUtil.isConvertedClass(paramType)) {
Object value = getValue(paramType, paramsMap, parameter.getParameterName());
return ConvertUtil.convert(paramType, value);
}
// 不在工具中实现的转换类型,需要反序列化后转换
// 获取属性列表
List<Field> fieldList = ConvertUtil.getAllFields(paramType);
// 构建实例
Object result = ConvertUtil.getDefaultValue(paramType);
// 获取所有属性,并反序列化后赋值
for (Field field : fieldList) {
Object value = getValue(field.getType(), paramsMap, field.getName());
ConvertUtil.setFieldValue(result, field, value);
}
return result;
}
/**
* 获取参数值
*
* @param clazz 参数类型
* @param paramsMap 参数 Map
* @param paramName 参数名
* @return
*/
private Object getValue(Class<?> clazz, Map<String, String[]> paramsMap, String paramName) {
if (Map.class.isAssignableFrom(clazz)) {
// 处理 Map 类型的字段
return convertToMap(paramsMap, paramName);
} else if (clazz.isArray()) {
// 处理数组类型的字段
String[] array = paramsMap.get(paramName);
return null == array ? convertToArray(paramsMap, paramName, clazz.getComponentType()) : array;
} else {
// 处理普通字段
String[] value = paramsMap.get(paramName);
return null == value ? paramsMap.get("params[" + paramName + "]") : value;
}
}
/**
* 将匹配指定前缀的参数转换为 Map
*
* @param paramsMap 所有请求参数的 Map
* @param prefix 前缀
* @return 转换后的 Map
*/
private Map<String, Object> convertToMap(Map<String, String[]> paramsMap, String prefix) {
Map<String, Object> resultMap = new HashMap<>();
String prefixWithBracket = prefix + "[";
for (Map.Entry<String, String[]> entry : paramsMap.entrySet()) {
String key = entry.getKey();
if (key.startsWith(prefixWithBracket)) {
String mapKey = key.substring(prefixWithBracket.length(), key.length() - 1);
resultMap.put(mapKey, entry.getValue().length > 1 ? entry.getValue() : entry.getValue()[0]);
}
}
return resultMap;
}
/**
* 将匹配指定前缀的参数转换为数组
*
* @param paramsMap 所有请求参数的 Map
* @param prefix 前缀
* @param componentType 数组的组件类型
* @return 转换后的数组
*/
public static Object convertToArray(Map<String, String[]> paramsMap, String prefix, Class<?> componentType) {
String prefixWithBracket = prefix + "[";
int count = 0;
// 计算匹配前缀的参数个数
for (String key : paramsMap.keySet()) {
if (key.startsWith(prefixWithBracket)) {
count++;
}
}
// 创建数组
Object array = Array.newInstance(componentType, count);
int index = 0;
// 填充数组
for (Map.Entry<String, String[]> entry : paramsMap.entrySet()) {
String key = entry.getKey();
if (key.startsWith(prefixWithBracket)) {
String[] values = entry.getValue();
Object value = ConvertUtil.convert(componentType, values.length > 1 ? values : values[0]);
Array.set(array, index++, value);
}
}
return array;
}
}
配置参数解析器
使用 WebMvcConfigurer
需要在 pom 引入依赖 (如有需要)。(实测在 common-core 中引用会导致 auth 报错,所以在 security 模块中的 WebMvcConfig
中直接添加了该方法,不会报错)
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
</dependency>
然后可以配置 Spring Boot 的解析器:
package com.demo.common.security.config;
import com.demo.common.security.resolver.CustomArgumentResovler;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import java.util.List;
/**
* @author HeHTao
* @description 拦截器配置
* @date 2024/05/17
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
// 添加自定义参数解析器
resolvers.add(new EnumArgumentResolver());
}
}
声明并管理自动配置类
该配置方法是 Spring Boot 3 框架下的配置方法,若是 2 ,网上找找也有对应方法。
在项目的 resource
目录中添加 META-INF.spring
目录,并新建文件 org.springframework.boot.autoconfigure.AutoConfiguration.imports
,在文件中添加:
com.demo.common.security.config.WebConfig
即可默认配置该配置类,而不用在项目启动类中声明。
若不想全局配置,则在启动类中声明:
@SpringBootApplication(scanBasePackages = {"com.demo.common.security.config.WebConfig"})