带你玩转SpringMVC自定义HTTP请求响应数据转换

环境:SpringBoot2.7.12

乐东黎族网站制作公司哪家好,找创新互联建站!从网页设计、网站建设、微信开发、APP开发、成都响应式网站建设等网站项目制作,到程序开发,运营维护。创新互联建站于2013年创立到现在10年的时间,我们拥有了丰富的建站经验和运维经验,来保证我们的工作的顺利进行。专注于网站建设就选创新互联建站

1. 简介

在Spring MVC中,HttpMessageConverter主要用于将HTTP请求的输入内容转换为指定的Java对象,以及将Java对象转换为HTTP响应的输出内容。这种灵活的消息转换机制就是利用HttpMessageConverter来实现的。

Spring MVC提供了多个默认的HttpMessageConverter实现,包括处理JSON、XML、文本等格式的Converter。另外,我们也可以自定义HttpMessageConverter来处理其他格式的数据。

Spring MVC提供了两个注解:@RequestBody和@ResponseBody,分别用于完成请求报文到对象和对象到响应报文的转换。

然而,有时候默认的HttpMessageConverter无法满足特定的需求,例如,当我们需要处理的数据格式没有默认的Converter时,或者我们需要对现有的Converter进行扩展时,就需要自定义HttpMessageConverter。

自定义HttpMessageConverter可以让我们更加灵活地控制数据转换的过程,例如我们可以自定义转换规则、异常处理等。

接下来我们通过一个实例讲解如何自定义HttpMessageConverter。

需求

接口请求数据格式:

xxx|yyy|zzz|...

接口返回JSON数据格式

{
    "xxx": xxx,
    "yyy": yyy,
    "zzz": zzz,
    ...
}

其实就上面的数据格式,我们完全可以不用自定义HttpMessageConverter也是完全可以实现的。我们这里主要就是教大家如何在特殊的需求下实现特定的数据转换处理。

2. 实战案例

自定义HttpMessageConverter转换器

public class PackHttpMessageConverter implements HttpMessageConverter {
    
  // 设置自定义的Content-Type类型,这样就限定了只有请求的内容类型是该类型才会使用该转换器进行处理
  private static final MediaType PACK = new MediaType("application", "pack", StandardCharsets.UTF_8) ;


  // 判断当前转换器是否能够读取数据
  @Override
  public boolean canRead(Class clazz, MediaType mediaType) {
    return PACK.equals(mediaType) ;
  }
  // 判断当前转换器是否可以将结果数据进行输出到客户端
  @Override
  public boolean canWrite(Class clazz, MediaType mediaType) {
    return true ;
  }
  // 返回当前转换器只支持application/pack类型的数据格式
  @Override
  public List getSupportedMediaTypes() {
    return Arrays.asList(PACK) ;
  }


  // 从请求中读取数据
  @Override
  public Object read(Class clazz, HttpInputMessage inputMessage)
      throws IOException, HttpMessageNotReadableException {
    InputStream is = inputMessage.getBody() ;
    String res = IOUtils.toString(is, StandardCharsets.UTF_8) ;
    // 这里简单处理只针对Users类型的对象处理
    if (clazz == Users.class) {
      try {
        // 创建实例
        Users target = (Users) clazz.newInstance() ;
        String[] s = res.split("\\|");
        target.setId(Long.valueOf(s[0])) ;
        target.setName(s[1]) ;
        target.setAge(Integer.valueOf(s[2])) ;
        target.setIdNo(s[3]) ;
        return target ;
      } catch (InstantiationException | IllegalAccessException e) {
        e.printStackTrace() ;
      }
    }
    return null ;
  }


  // 将Controller方法返回值写到客户端
  @Override
  public void write(Object t, MediaType contentType, HttpOutputMessage outputMessage)
      throws IOException, HttpMessageNotWritableException {
    // 设置响应头为json格式
    outputMessage.getHeaders().add("Content-Type", "application/json;charset=UTF-8") ;
    ObjectMapper mapper = new ObjectMapper() ;
    OutputStream os = outputMessage.getBody();
    // 输出结果内容
    os.write(mapper.writeValueAsString(t).getBytes(StandardCharsets.UTF_8)) ;
    os.flush(); 
  }
  
}


将PackHttpMessageConverter注册到容器中

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
  
  @Override
  public void configureMessageConverters(List> converters) {
    converters.add(new PackHttpMessageConverter()) ;
  }
}

到这里自定义HttpMessageConverter及注册到容器中就全部完成了,开发还是比较简单,接下来做测试

接口

// 方法非常简单还是用的那些常用的类,@RequestBody接收请求body中的内容
@PostMapping("/i")
public Object i(@RequestBody Users user) {
  System.out.println(handlerAdapter) ;
  return user ;
}

通过Postman测试接口

设置请求的header

图片

图片

似乎没有任何的问题,其实你只要在写的方法中打印下日志,或者调试下,你会发现你的write方法根本就没有被调用,也就是说写数据并没有使用到我们自定义的实现,这是因为有优先级比我们自定义的转换器高,所以要想让写消息也调用自定义的。我们需要如下修改注册方式:

public void configureMessageConverters(List> converters) {
  converters.add(0, new PackHttpMessageConverter()) ;
}

这样我们自定义的转换器就排到了第一的位置,这样就会调用我们自定义的write方法。

以上就是自定义HttpMessageConverter全部内容。

3. 实现原理

请求参数由于添加了@RequestBody,所以方法的参数解析器使用的是RequestResponseBodyMethodProcessor。

public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
  protected  Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
      Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
    // ...
    // 读取请求数据;调用父类方法
    Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
    // ...
  }
}

AbstractMessageConverterMethodArgumentResolver

public abstract class AbstractMessageConverterMethodArgumentResolver {
  protected  Object readWithMessageConverters(...) {
    // ...
    // 遍历所有的消息转换器
    for (HttpMessageConverter converter : this.messageConverters) {
        Class> converterType = (Class>) converter.getClass();
        GenericHttpMessageConverter genericConverter = (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter) converter : null);
        // 判断当前转换器是否读,也就上面我们自定义中实现的canRead方法
        if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
            (targetClass != null && converter.canRead(targetClass, contentType))) {
          if (message.hasBody()) {
            HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
            // 读取具体的数据内容
            body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter) converter).read(targetClass, msgToUse));
            body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
          }
          else {
            body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
          }
          break;
        }
      }
  }
}

原理也比较的简单。

自定义HttpMessageConverter是Spring MVC中一个强大的工具,它可以帮助开发者更加灵活地控制数据转换的过程,满足特定的需求。

本文题目:带你玩转SpringMVC自定义HTTP请求响应数据转换
分享网址:http://www.mswzjz.cn/qtweb/news10/280410.html

攀枝花网站建设、攀枝花网站运维推广公司-贝锐智能,是专注品牌与效果的网络营销公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 贝锐智能