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.indexOf(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;
}
測試結果與我們預期的一樣