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

前端开发   发布日期:2025年01月02日   浏览次数:198

这篇文章主要介绍“怎么自定义@RequestBody注解获取JSON数据”,在日常操作中,相信很多人在怎么自定义@RequestBody注解获取JSON数据问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”怎么自定义@RequestBody注解获取JSON数据”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

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

自定义注解

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

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

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

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

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

  1. @Retention(RetentionPolicy.RUNTIME)
  2. @Target(ElementType.PARAMETER)
  3. public @interface JsonArg {
  4. @AliasFor("name")
  5. String value() default "";
  6. @AliasFor("value")
  7. String name() default "";
  8. boolean required() default true;
  9. String defaultValue() default ValueConstants.DEFAULT_NONE;
  10. }

其中:

    1. @Retention(RetentionPolicy.RUNTIME)
    声明我们需要在运行期动态地获取它地信息
    1. @Target(ElementType.PARAMETER)
    声明这个注解只能作用在方法参数

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

自定义解析器

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

  1. public class JsonArgMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
  2. /**
  3. * 表示关于 namedValue 的信息,包括名称、是否需要它以及默认值。
  4. *
  5. * @param parameter 待处理的方法参数
  6. * @return {@link JsonArgNamedValueInfo}
  7. */
  8. @Override
  9. protected NamedValueInfo createNamedValueInfo(MethodParameter parameter) {
  10. JsonArg ann = parameter.getParameterAnnotation(JsonArg.class);
  11. return (ann != null ? new JsonArgNamedValueInfo(ann) : new JsonArgNamedValueInfo());
  12. }
  13. /**
  14. * 解析方法
  15. *
  16. * @param name 待解析的 JSON 的 key
  17. * @param parameter 待处理的方法参数
  18. * @return 解析出来的值
  19. */
  20. @Override
  21. protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
  22. ContentCachingRequestWrapper contentCachingRequestWrapper = request.getNativeRequest(ContentCachingRequestWrapper.class);
  23. String body;
  24. assert contentCachingRequestWrapper != null;
  25. byte[] contentAsByteArray = contentCachingRequestWrapper.getContentAsByteArray();
  26. if (contentAsByteArray.length == 0) {
  27. try (BufferedReader reader = contentCachingRequestWrapper.getReader()) {
  28. body = reader.lines().collect(Collectors.joining(""));
  29. }
  30. } else {
  31. body = new String(contentAsByteArray);
  32. }
  33. return JSONObject.parseObject(body).get(name);
  34. }
  35. /**
  36. * 是否支持该方法参数
  37. *
  38. * @param parameter 待处理的方法参数
  39. */
  40. @Override
  41. public boolean supportsParameter(MethodParameter parameter) {
  42. return true;
  43. }
  44. private static class JsonArgNamedValueInfo extends NamedValueInfo {
  45. public JsonArgNamedValueInfo() {
  46. super("", false, ValueConstants.DEFAULT_NONE);
  47. }
  48. public JsonArgNamedValueInfo(JsonArg annotation) {
  49. super(annotation.name(), annotation.required(), annotation.defaultValue());
  50. }
  51. }
  52. }

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

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

包装请求

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

  1. /*
  2. 将request包装成ContentCachingRequest,以反复读取请求体
  3. */
  4. @Component
  5. public class CachingRequestBodyFilter extends GenericFilterBean {
  6. @Override
  7. public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
  8. if (servletRequest instanceof HttpServletRequest) {
  9. filterChain.doFilter(new ContentCachingRequestWrapper((HttpServletRequest) servletRequest), servletResponse);
  10. } else {
  11. filterChain.doFilter(servletRequest, servletResponse);
  12. }
  13. }
  14. }

注册解析器

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

  1. @Configuration
  2. public class SpringMvcConfig implements WebMvcConfigurer {
  3. @Override
  4. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  5. resolvers.add(new JsonArgMethodArgumentResolver());
  6. }
  7. }

用法

和 @RequestParam 的用法相似。

  1. public CommonResult<Object> signUp(
  2. @JsonArg(name = "uname") String username,
  3. @JsonArg(required = false, name = "pwd", defaultValue = "123") String password
  4. ) {
  5. log.info("[Username]: {}, [Password]: {}", username, password);
  6. return null;
  7. }

以上就是怎么自定义@RequestBody注解获取JSON数据的详细内容,更多关于怎么自定义@RequestBody注解获取JSON数据的资料请关注九品源码其它相关文章!