1背景
本文只适用与Content-type 为form-data 媒体类型。
springmvc 是默认支持将form-data 传过来的表单数据的,但是有一个限制,那即是表单的key值要和对象的属性值是一样的,然而生产环境中,一般前端使用的参数都是下划线的,而我们对象里的key是驼峰的,这样就设置不到对应的值了。
这里有俩种方法:
- 一种为将对象里的key全部改为下划线(不推荐);
- 自定义参数解析。
这里我们使用第二种方法。
2 实现
首先我们先定义一个class 工具类。
public class ClassUtil {
private static Logger log = LoggerFactory.getLogger(ClassUtil.class);
//将字符串转化为对应的类型,数组类型不支持
public static Object getFieldValue(Field field, String origin) {
Class<?> fileType = field.getType();
if (fileType == String.class) {
return origin;
}
if (fileType.isArray()) {
throw new IllegalArgumentException("array type is not support");
}
if (fileType == int.class || fileType == Integer.class) {
return Integer.parseInt(origin);
}
if (fileType == long.class || fileType == Long.class) {
return Long.parseLong(origin);
}
if (fileType == byte.class || fileType == Byte.class) {
return Byte.parseByte(origin);
}
if (fileType == short.class || fileType == Short.class) {
return Short.parseShort(origin);
}
if (fileType == char.class || fileType == Character.class) {
return origin.charAt(0);
}
if (fileType == float.class || fileType == Float.class) {
return Float.parseFloat(origin);
}
if (fileType == double.class || fileType == Double.class) {
return Double.parseDouble(origin);
}
if (fileType == boolean.class || fileType == Boolean.class) {
return Boolean.parseBoolean(origin);
}
return JSONObject.parseObject(origin, fileType);
}
//为对应的属性设置,调用set方法
public static void setFieldValue(Class clazz, Field field, Object instance, Object o) {
if (clazz == null || field == null || o == null) {
return;
}
String name = field.getName();
Class<?> fieldType = field.getType();
//获取set方法名称
{
String prefix = "set";
name = prefix + name.substring(0, 1).toUpperCase() + name.substring(1);
}
try {
Method setMethod = clazz.getDeclaredMethod(name, fieldType);
setMethod.invoke(instance, o);
} catch (NoSuchMethodException e) {
log.error("no such method", e);
} catch (IllegalAccessException e) {
log.error("", e);
} catch (InvocationTargetException e) {
log.error("", e);
}
}
然后我们创建一个注解,表明这个参数使用我们的自定义解析。
/**
* 用于spring mvc 表单接受参数
* 支持form data 转化对象, 使用fastjson 转化 , 目前只支持基本数据类型,属性类型为对象类型不支持
*/
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface FormDataJsonBody {
}
接下来我们实现自定义解析器,为了实现简单,我们其中使用了一些fastjson 的方法,所以需要依赖fastjson
public class FormDataJsonResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
FormDataJsonBody annotation = methodParameter.getParameterAnnotation(FormDataJsonBody.class);
return annotation != null;
}
@Override
public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest request, WebDataBinderFactory webDataBinderFactory) throws Exception {
Class<?> clazz = methodParameter.getParameterType();
Object instance = clazz.newInstance();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
String keyName = "" ;
{
JSONField jsonAnnotation = field.getAnnotation(JSONField.class);
if(jsonAnnotation == null){
keyName = field.getName() ;
}else{
keyName = jsonAnnotation.name();
}
}
String[] values = request.getParameterMap().get(keyName);
//数组不进行处理
if(values == null || values.length<1 || values.length>1){
continue;
}
String dataStr = values[0];
Object fieldValue = ClassUtil.getFieldValue(field, dataStr);
ClassUtil.setFieldValue(clazz,field,instance,fieldValue);
}
return instance;
}
然后我们需要将自定义解析起加入到Spring mvc 的解析器里,
@Configuration
@Slf4j
public class WebMvcConfigurer extends WebMvcConfigurationSupport {
@Override
protected void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
argumentResolvers.add(new FormDataJsonResolver());
super.addArgumentResolvers(argumentResolvers);
}
}
3 测试
@PostMapping("/save_or_update")
public Map<String, Object> saveOrUpdate(@FormDataJsonBody DemoParam param) {
return new HashMap();
}
public static class DemoParam{
@JSONField(name = "start_time")
private Long startTime;
@JSONField(name = "type")
private Integer sendType;
@JSONField(name = "id")
private Long id ;
@JSONField(name = "details")
private String details;
}
测试结果与我们预期的一样