springboot接收JSON字符串绑定基础类型参数和String类型

原因

由于前端框架原因,后端post请求一致用applition/json 请求。对于后端而言实体类需要加上@RequestBody注解,但是有时候修改接口等只需要一两个参数,如果将其分装为实体,费时费力。因此可以自己写一个参数处理器。

解决

可以自己写一个参数处理器。实现HandlerMethodArgumentResolver接口,再将其配置到WebMvcConfigurer类中的参数处理集合当中。

具体代码

  1. 注解:
/**
 * tip:只支持application/json格式下 的基本数据类型包装类,和Sring
 *
 */
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface JsonParam {
    /**
     * 值
     */
    String value() default "";

    /**
     * 是否必须
     */
    boolean require() default false;
}
  1. 参数处理器:
/**
 * 参数转换(POST,默认前端以JSON形式提交)
 */
public class Json2ParamsHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    private static final Logger LOG = LoggerUtils.getLogger(Json2ParamsHandlerMethodArgumentResolver.class);

    /**
     * key
     */
    private static final String JSON_BODY_KEY = "JSON_BODY_KEY";

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


    @Override
    public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
        // 获取jsonNode
        JsonNode jsonNode = getJsonBody(webRequest);

        JsonParam requestSingleParam = parameter.getParameterAnnotation(JsonParam.class);
        // 名
        String value = determineParamName(parameter, requestSingleParam);
        // 结果
        JsonNode paramValue = jsonNode.get(value);
        // 是否必须
        boolean require = requestSingleParam.require();
        if (paramValue == null && require) {
            throw new ServerException("parameter[" + value + "]不能为空。");
        }

        if (paramValue == null) {
            return null;
        }
        Class<?> parameterType = parameter.getParameterType();
        Constructor<?> constructor = parameterType.getConstructor(String.class);
        Object param = null;
        try {
            param = constructor.newInstance(paramValue.asText());
        } catch (Exception e) {
            LOG.error("bind method parameters error", e);
            throw new ServerException("parameter[" + value + "] format error for input value[" + paramValue.toString() + "]");
        }
        return param;
    }

    private String determineParamName(MethodParameter parameter, JsonParam requestSingleParam) {
        String value = requestSingleParam.value();
        if (BaseVaildedUtils.isEmpty(value)) {
            value = parameter.getParameterName();
        }
        return value;
    }

    private JsonNode getJsonBody(NativeWebRequest webRequest) {

        // 有就直接获取
        String jsonBody = (String) webRequest.getAttribute(JSON_BODY_KEY, NativeWebRequest.SCOPE_REQUEST);
        // 没有就从请求中读取
        if (jsonBody == null) {
            try {
                HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
                jsonBody = IOUtils.toString(servletRequest.getReader());
                webRequest.setAttribute(JSON_BODY_KEY, jsonBody, NativeWebRequest.SCOPE_REQUEST);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        return JsonUtil.parseObject(jsonBody);
    }

}
  1. 配置类:
@Configuration
public class BaseMvcConfig implements WebMvcConfigurer {

    @Override
    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
        resolvers.add(new Json2ParamsHandlerMethodArgumentResolver());
    }
}

结语:

这样就可以使用@JsonParam 来标记基础类型包装类(包括String)的参数,来实现Application/json的方式提交json字符串无法接受的问题了。
tip: 上述代码其实可以和@RequestBody的解析器合并成同一个,这样使用体验更佳。因为时间关系,暂时没做研究。

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值