Springmvc form-data body 解析爲對象

1背景

本文只適用與Content-type 爲form-data 媒體類型。

springmvc 是默認支持將form-data 傳過來的表單數據的,但是有一個限制,那即是表單的key值要和對象的屬性值是一樣的,然而生產環境中,一般前端使用的參數都是下劃線的,而我們對象裏的key是駝峯的,這樣就設置不到對應的值了。

這裏有倆種方法:

  1. 一種爲將對象裏的key全部改爲下劃線(不推薦);
  2. 自定義參數解析。

這裏我們使用第二種方法。 

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;
}
    

測試結果與我們預期的一樣

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章