验证码: 看不清楚,换一张 查询 注册会员,免验证
  • {{ basic.site_slogan }}
  • 打开微信扫一扫,
    您还可以在这里找到我们哟

    关注我们

怎么自定义@RequestBody注解获取JSON数据

阅读:966 来源:乙速云 作者:代码code

怎么自定义@RequestBody注解获取JSON数据

Spring MVC 的 @RequestBody 注解只能将请求体中的 JSON 数据封装成 Bean,而无法对单一字段实施管理(例如 required、name 等属性)。

自定义注解

首先思考,我们需要这个注解做什么?

  • 设置该字段的必选性(required)

  • 设置该字段在请求体 JSON 中的 key 值(name、value)

  • 设置该字段的默认值(defaultValue)

于是我们的注解类 @JsonArg 至少应该长这样:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface JsonArg {
    @AliasFor("name")
    String value() default "";

    @AliasFor("value")
    String name() default "";

    boolean required() default true;

    String defaultValue() default ValueConstants.DEFAULT_NONE;
}

其中:

  • @Retention(RetentionPolicy.RUNTIME) 声明我们需要在运行期动态地获取它地信息

  • @Target(ElementType.PARAMETER) 声明这个注解只能作用在方法参数

是的,它和 Spring MVC 自带的 @RequestParam 注解非常像,但 @RequestParam 只能作用于 query parameters 和 form data。

自定义解析器

单纯的定义注解类程序是无法知道我们要它做什么的,所以我们要告诉程序在遇到这个注解时该做什么。

public class JsonArgMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
    /**
     * 表示关于 namedValue 的信息,包括名称、是否需要它以及默认值。
     *
     * @param parameter 待处理的方法参数
     * @return {@link JsonArgNamedValueInfo}
     */
    @Override
    protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
        JsonArg ann = parameter.getParameterAnnotation(JsonArg.class);
        return (ann != null ? new JsonArgNamedValueInfo(ann) : new JsonArgNamedValueInfo());
    }

    /**
     * 解析方法
     *
     * @param name      待解析的 JSON 的 key
     * @param parameter 待处理的方法参数
     * @return 解析出来的值
     */
    @Override
    protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
        ContentCachingRequestWrapper contentCachingRequestWrapper = request.getNativeRequest(ContentCachingRequestWrapper.class);
        String body;
        assert contentCachingRequestWrapper != null;
        byte[] contentAsByteArray = contentCachingRequestWrapper.getContentAsByteArray();
        if (contentAsByteArray.length == 0) {
            try (BufferedReader reader = contentCachingRequestWrapper.getReader()) {
                body = reader.lines().collect(Collectors.joining(""));
            }
        } else {
            body = new String(contentAsByteArray);
        }
        return JSONObject.parseObject(body).get(name);
    }

    /**
     * 是否支持该方法参数
     *
     * @param parameter 待处理的方法参数
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return true;
    }

    private static class JsonArgNamedValueInfo extends NamedValueInfo {
        public JsonArgNamedValueInfo() {
            super("", false, ValueConstants.DEFAULT_NONE);
        }

        public JsonArgNamedValueInfo(JsonArg annotation) {
            super(annotation.name(), annotation.required(), annotation.defaultValue());
        }
    }
}

注意到在 resolveName() 方法中我们获取的 request 类型是 ContentCachingRequestWrapper。

这是因为默认的 request 只能读取一次请求体,而我们的解析器在解析每个方法参数时都需要读取一次请求体。

包装请求

添加过滤器将我们的请求转换为所需要的 ContentCachingRequestWrapper。

/*
    将request包装成ContentCachingRequest,以反复读取请求体
 */
@Component
public class CachingRequestBodyFilter extends GenericFilterBean {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        if (servletRequest instanceof HttpServletRequest) {
            filterChain.doFilter(new ContentCachingRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
        } else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }
}

注册解析器

最后,将自定义的解析器注册到 Spring MVC。

@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
    @Override
    public void addArgumentResolvers(List resolvers) {
        resolvers.add(new JsonArgMethodArgumentResolver());
    }
}

用法

和 @RequestParam 的用法相似。

public CommonResult signUp(
            @JsonArg(name = "uname") String username,
            @JsonArg(required = false, name = "pwd", defaultValue = "123") String password
    ) {
        log.info("[Username]: {}, [Password]: {}", username, password);
        return null;
}            
                    
                    
                        分享到:
                        
                    
                    
*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: hlamps#outlook.com (#换成@)。
相关文章
{{ v.title }}
{{ v.description||(cleanHtml(v.content)).substr(0,100)+'···' }}
你可能感兴趣
推荐阅读 更多>

{{ basic.bottom_text }}