基于@RequestBody 获取前端数据的自定义参数注解,处理泛型和优化@RequestBody

前言:

spring boot 默认的参数处理,不能支持泛型的处理,例如:

后端代码:
	@RequestMapping("entityParamTest")
    @ResponseBody
    public String entityParamTest(UserVO<DepartmentVO> userVO){
        System.out.println(userVO);
        return userVO.toString();
    }
import lombok.Data;

/**
 * @author phacxj
 */
@Data
public class UserVO<T> {

    private T data;

    private String username ;

    private String realName ;

    private Integer age;

    private Boolean isShow;

    private String [] phones;

    private DepartmentVO departmentVO;
}

import lombok.Data;

/**
 * @author phacxj
 */
@Data
public class DepartmentVO {

    private String name ;

    private String code ;
}

前端代码:
	$.ajax({
            url : "entityParamTest?data.name=啊啊&username=安安&departmentVO.code=哈哈",
            type: "post",
        });
控制台输出为:

UserVO(data=java.lang.Object@70cd5f86, username=安安, realName=null, age=null, isShow=null, phones=null, departmentVO=DepartmentVO(name=null, code=哈哈))
其中data是DepartmentVO,但是返回的是Obejct 是因为,spring boot原生的不支持泛型的处理。

@RequestBody方式处理泛型

@RequestBody参数注解是支持泛型的,但前提是ajax的请求必须是
contentType :“application/json”,
data : JSON.stringify(data),

前端代码:
	//@RequestBody处理,必须是JSON格式,且是JSON字符串 contentType :"application/json",data : JSON.stringify(data),
        let data = {
            data : {
                name : "啊啊"
            },
            departmentVO : {
                code : "哈哈"
            }
        };
        $.ajax({
            url : url,
            type: "post",
            contentType :"application/json",
            data : JSON.stringify(data),
        });
后端代码:
	@RequestMapping("entityParamTest")
    @ResponseBody
    public String entityParamTest(@RequestBody UserVO<DepartmentVO> userVO){
        System.out.println(userVO);
        return userVO.toString();
    }
控制台输出为:

UserVO(data=DepartmentVO(name=啊啊, code=null), username=null, realName=null, age=null, isShow=null, phones=null, departmentVO=DepartmentVO(name=null, code=哈哈))
这里可以看到数据是可以输出来的。但是这种情况不支持

自定义参数注解处理泛型的问题和带点参数名的问题

1.定义自定义注解

后端代码:
import java.lang.annotation.*;

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

2.定义自定义参数解析器(最核心的步骤)

/**
 * @author phacxj
 */
@Configuration
public class EntityParamHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
    private static final String POINT = ".";
    private static final String LEFT_PARENTHESIS = "[";
    private static final String RIGHT_PARENTHESIS = "]";
    private static final String PARENTHESIS = "[]";
    private static final String CONTENT_TYPE = "application/json";


    private final Logger logger = LoggerFactory.getLogger(EntityParamHandlerMethodArgumentResolver.class);

    @Override
    public boolean supportsParameter(MethodParameter methodParameter) {
        return methodParameter.hasParameterAnnotation(EntityParam.class);
    }

    @Override
    public Object resolveArgument(MethodParameter methodParameter, ModelAndViewContainer modelAndViewContainer, NativeWebRequest nativeWebRequest, WebDataBinderFactory webDataBinderFactory){
        //获取JSON字符串
        String jsonStr;
        //判断content-type是否是application/json 的数据类型
        String contentType = nativeWebRequest.getHeader("content-type");
        if (StringUtils.isNotBlank(contentType) && contentType.contains(CONTENT_TYPE)){
            jsonStr = getJSONParam(nativeWebRequest);
        }else {
            jsonStr = parseParamToJSONStr(nativeWebRequest);
        }
        try {
            return JSON.parseObject(jsonStr, methodParameter.getGenericParameterType());
        }catch (JSONException e){
            logger.error("resolveArgument中JSON.parseObject方法出错:"+e.getMessage(),e);
            return null;
        }
    }

    /**
     *@Description 获取JSON字符串中的数据
     *@Author  phacxj
     *@Createtime  2019/2/12 16:12
     *@Param [request]
     *@Return java.lang.String
     */
    private String getJSONParam(NativeWebRequest request){
        StringBuilder stringBuilder = new StringBuilder();
        try {
            //1.获取输入流
            BufferedReader stramReader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(request.getNativeRequest(HttpServletRequest.class)).getInputStream()));

            //2.写入数据到StringBuilder
            String line;
            while ((line = stramReader.readLine()) != null){
                stringBuilder.append(line);
            }
        }catch (Exception e){
            logger.error("获取JSON字符串中的数据错误:"+e.getMessage(),e);
        }
        return stringBuilder.toString();
    }

    /**
     *@Description 将user.id=1这种形式的数据转为{user:{id:1}}形式
     *@Author  phacxj
     *@Createtime  2019/2/13 9:42
     *@Param [request]
     *@Return java.lang.String
     */
    private String parseParamToJSONStr(NativeWebRequest request){
        Map<String,String [] > conditionMap = request.getParameterMap();
        JSONObject jsonObject = new JSONObject();
        Iterator<String> names = request.getParameterNames();
        while (names.hasNext()){
            String name = names.next();
            String [] value = conditionMap.get(name);
            if (value != null){
                parseHavePointParamToJSON(jsonObject,name,value);
            }
        }
        return jsonObject.toJSONString();
    }

    /**
     *@Description 处理带有点的参数
     *@Author  phacxj
     *@Createtime  2019/2/13 10:12
     *@Param [jsonObject, name, value]
     *@Return void
     */
    private void parseHavePointParamToJSON(JSONObject jsonObject,String name,String [] value){
        //处理中括号
        if (name.contains(LEFT_PARENTHESIS)){
            name = name
                    .replace(PARENTHESIS,"")
                    .replace(LEFT_PARENTHESIS,POINT)
                    .replace(RIGHT_PARENTHESIS,"");

        }
        if (!name.contains(POINT)){
            //如果没有小数点,证明已经是最后一个了
            //判断是否是已经设置过值
            if (value.length>1){
                //如果是组数,则以数组的形式存放数据
                JSONArray jsonArray = new JSONArray();
                jsonArray.addAll(Arrays.asList(value));
                jsonObject.put(name,jsonArray);
            }else {
                jsonObject.put(name,value[0]);
            }
        }else {
            //如果还有小数点
            int pointIndex = name.indexOf(POINT);
            String tempName = name.substring(0,pointIndex);
            String subName = name.substring(name.indexOf(POINT)+1,name.length());
            JSONObject subJSONObject;
            //判断是否已经有对应的属性了
            if (jsonObject.getJSONObject(tempName) == null){
                //如果没有
                subJSONObject = new JSONObject();
            }else {
                //如果有
                subJSONObject = jsonObject.getJSONObject(tempName);
            }
            jsonObject.put(tempName,subJSONObject);
            //递归处理
            parseHavePointParamToJSON(subJSONObject,subName,value);
        }

    }
}

3.拦截器配置

注意:这里是spring boot 2.0以上的版本,定义了拦截器之后,默认的静态资源目录会被改变,所以需要
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
/**
 * @author phacxj
 */
@Configuration
public class MyWebMvcConfigurerAdapter extends WebMvcConfigurationSupport {
    /**
     * @Description 注册到spring容器中
     * @Author phacxj
     * @Createtime 2019/1/31 11:03
     * @Param
     * @Return
     */
    @Resource
    private EntityParamHandlerMethodArgumentResolver handlerParameterResolver;


    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
        argumentResolvers.add(handlerParameterResolver);
        super.addArgumentResolvers(argumentResolvers);
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/");
    }
}

测试:

带有.的参数名称泛型处理(例如:user.name=111)
后端代码:
	@RequestMapping("entityParamTest")
    @ResponseBody
    public String entityParamTest(@EntityParam UserVO<DepartmentVO> userVO){
        System.out.println(userVO);
        return userVO.toString();
    }
前端代码:
	let url = "entityParamTest?data.name=啊啊&username=安安&departmentVO.code=哈哈";
     $.ajax({
         url : url,
         type: "post",
     });	
控制台输出:

UserVO(data=DepartmentVO(name=啊啊, code=null), username=null, realName=null, age=null, isShow=null, phones=null, departmentVO=DepartmentVO(name=null, code=哈哈))
可以看到,泛型的问题解决了。

优化@RequestBody 的ajax请求必须是JSON字符串请求的问题测试:
后端代码:
	@RequestMapping("entityParamTest")
    @ResponseBody
    public String entityParamTest(@EntityParam UserVO<DepartmentVO> userVO){
        System.out.println(userVO);
        return userVO.toString();
    }
前端代码:
	let data = {
            data : {
                name : "啊啊"
            },
            departmentVO : {
                code : "哈哈"
            }
        };

        $.ajax({
            url : "entityParamTest",
            type : "post",
            data : data
        })
控制台输出:	

UserVO(data=DepartmentVO(name=啊啊, code=null), username=null, realName=null, age=null, isShow=null, phones=null, departmentVO=DepartmentVO(name=null, code=哈哈))
可以看到,没有:
contentType :“application/json”,
data : JSON.stringify(data),
依然可以接受到数据

注意:这种方式,只能使用与JSONObject的情况,如果要传递JSONArray的数据,还是需要指定
contentType :“application/json”,
data : JSON.stringify(data),

总结

这个参数注解的作用有:
	1.替代@RequestBody
	2.处理带有点(user.name)且是泛型的参数问题
	3.优化@RequestBody中前端必须是以JSON字符串方式传递参数的问题
  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值