SpringMVC中自定义注解,实现同时支持将POST-Json/POST-Form/GET请求的参数封装为对象

问题描述:

在我现在的项目中,由于人员更替,代码有些不规范。前端Web、App 对后端同一接口的请求方式可能不一样。例如,有的接口Web请求的时候,使用的是 Post  请求,数据包装为一个Json Object;但是在App端,可能使用的是Post 一个 表单数据过来。这样,后端接收数据的时候,@RequestBody 便不能满足需求。所以需要我们寻求一种解决方式同时兼容这些请求的方式。

解决方案:

自定义注解@RequestModel,重写WebMvcConfigurerAdapter并添加自定义的HandlerMethodArgumentResolver。

具体操作:

1、自定义注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestModel {

}

2、自定义HandlerMethodArgumentResolver:

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
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 javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class RequestHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(RequestModel.class);
    }

    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
        if (StringUtils.equals(request.getMethod(), "POST")) {
            // 处理Post请求
            if (request.getContentType().contains("application/json")) {
                // 处理 json 数据的Post请求
                return this.doPostJson(parameter, request);
            } else {
                // 处理 form 表单类型Post请求
                return this.doGetAndPostForm(parameter, webRequest);
            }
        } else if (StringUtils.equals(request.getMethod(), "GET")) {
            // 处理Get类型的请求
            return this.doGetAndPostForm(parameter, webRequest);
        }
        return parameter.getParameterType().newInstance();
    }

    /**
     * 处理 Get请求、Form表单形式的Post请求
     *
     * @param parameter  MethodParameter
     * @param webRequest NativeWebRequest
     * @return 解析出的Object
     */
    private Object doGetAndPostForm(MethodParameter parameter, NativeWebRequest webRequest) throws IllegalAccessException, InstantiationException, IOException {
        Map parameterMap = webRequest.getParameterMap();
        Class parameterType = parameter.getParameterType();
        if (parameterMap == null || parameterMap.size() <= 0) {
            return parameterType.newInstance();
        }
        Map map = new HashMap<>();
        for (Map.Entry entry : parameterMap.entrySet()) {
            String[] arr = entry.getValue();
            if (ArrayUtils.isNotEmpty(arr)) {
                map.put(entry.getKey(), arr[0]);
            }
        }
        ObjectMapper mapper = new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        String json = mapper.writeValueAsString(map);
        return mapper.readValue(json, parameterType);
    }

    /**
     * 处理 json 形式的Post请求
     *
     * @param parameter MethodParameter
     * @param request   HttpServletRequest
     * @return 解析出的Object
     */
    private Object doPostJson(MethodParameter parameter, HttpServletRequest request) throws IOException {
        BufferedReader reader = request.getReader();
        StringBuilder sb = new StringBuilder();
        char[] buf = new char[1024];
        int len;
        while ((len = reader.read(buf)) != -1) {
            sb.append(buf, 0, len);
        }
        Class parameterType = parameter.getParameterType();
        return JSON.parseObject(sb.toString(), parameterType);
    }
}

3、重写WebMvcConfigurerAdapter,并添加上面自定义的HandlerMethodArgumentResolver

import org.springframework.context.annotation.Configuration;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import java.util.List;

@Configuration
public class ApiWebMvcConfigurerAdapter extends WebMvcConfigurerAdapter {
    @Override
    public void addArgumentResolvers(List argumentResolvers) {
        argumentResolvers.add(new RequestHandlerMethodArgumentResolver());
        super.addArgumentResolvers(argumentResolvers);
    }
}

使用范例:

// 不管前端传递的是JSON还是 Form 表单,都能注入进去
@RequestMapping(value = "test")
public ResultModel test(@RequestModel TestModel testModel) {
    // do something
}

最后的最后:

作者也是在不断学习之中,难免有疏漏或者错误的地方,有什么地方有问题的,欢迎留言探讨,一起进步!

你可能感兴趣的:(Spring/Spring,Boot)