Spring Boot 统一功能处理(二)

2024-04-18 1166阅读

        本篇主要介绍Spring Boot统一功能处理中的统一数据返回格式。

目录

一、定义统一的返回类

 二、配置统一数据格式

三、测试配置效果

四、统一格式返回的优点 

五、源码角度解析String问题


一、定义统一的返回类

在我们的接口在处理请求时,返回的结果可以说是参差不齐,既可以是一个String类型的数据,又可以是一个Integer类型的数据,这样未免会显得我们的代码很不规范,并且这种不规范的代码还会增加前后端之间的交流成本。因此,我们可以设计一个统一的类来作为所有接口的返回结果。这个统一的类通常需要包含以下三个部分:

  • code:由我们自己定义的一个状态码
  • msg:响应结果的描述
  • data:响应的数据

    下面我们通过代码来具体来实现一下这个类 :

    Spring Boot 统一功能处理(二)

    这里可以使用泛型来作为data的参数,毕竟返回的数据类型是多种多样的。

    下面我们来改造一下上一篇中所定义的login方法:

    Spring Boot 统一功能处理(二)这里的状态码200代表请求成功,-1代表失败。

    仔细观察可以发现,这串代码其实是有点冗余的,每次返回数据时都得设置一次Result的三个属性。因此,我们还可以对Result进行一些优化,具体如下:

    Spring Boot 统一功能处理(二)

    这里我们将设置Result属性的代码进行了封装,因此接口在返回数据时,直接调用这里的方法即可(由于fail表示请求失败,请求失败了通常不会有返回的数据,因此fail没有设置data参数)。接下来我们再优化一下前面的login方法:

     Spring Boot 统一功能处理(二)

    这样代码就看着简洁多了。

     二、配置统一数据格式

    虽然我们这里已经定义了统一的数据返回类Result,但我们并不能保证所有接口都会以这个类作为返回结果,因此我们还需要借助Spring 来配置一下统一的数据返回格式。

    首先我们需要创建一个类来实现ResposeBodyAdvice:

    Spring Boot 统一功能处理(二)

    然后重写两个方法:Spring Boot 统一功能处理(二)

     其中supports是用来选择要进行统一返回处理的方法,如果直接返回true那就是所有接口都会进行这个统一处理,如果不想全部都统一处理,也可以通过下面的方式获取相关的类或者方法,并以此来判定是否要统一处理:

             //获取执行返回操作的类
            Class declaringClass = returnType.getMethod().getDeclaringClass();
            //获取执行返回操作的方法
            Method method = returnType.getMethod();

     另一个方法beforeBodyWrite是对返回的数据具体进行统一处理的逻辑,其中body就是我们在接口里返回的数据。这里已经写好了一个大体逻辑,如果是我们前面定义的返回类直接返回,如果不是就把body封装到返回类里再返回。

    最后我们还需要再类上加上一个@ControllerAdvice注解:

    Spring Boot 统一功能处理(二)

    通过这个注解的实现可以发现,他是@Component的衍生注解,因此加了这个注解的类也会被加到Spring容器中。并且可以发现@ControllerAdvice还多了很多别的功能,这里就不过多介绍了。 

    三、测试配置效果

    接下来我们通过postMan来测试一下配置的效果。

    我们先测试一下返回类型为Result的接口:

    Spring Boot 统一功能处理(二)

    postMan请求后的结果:

    Spring Boot 统一功能处理(二)

    通过结果可以发现响应符合我们的统一要求。

    然后我们创建一个返回值不为Result的接口:
    Spring Boot 统一功能处理(二)

    通过PostMan来访问可以发现结果也是符合预期的:

     Spring Boot 统一功能处理(二)

    然后我们再试试返回集合:

    Spring Boot 统一功能处理(二)

    通过postMan来访问一下可以发现结果正常:
    Spring Boot 统一功能处理(二)

    接下来我们再看看返回对象,

    首先我们创建一个User类然后对这个User类进行返回:
    Spring Boot 统一功能处理(二)

    通过PostMan可以发现结果正确。

    最后我们再来看一下返回类型是String类型:

    Spring Boot 统一功能处理(二)

     通过PostMan来访问可以发现报错了:

    Spring Boot 统一功能处理(二)

     我们再去后端看一下:

    Spring Boot 统一功能处理(二)

    可以发现后端报了一个类型不匹配异常,至于为什么会报这个异常,后面会解释,我们先来看看解决方法。

    首先我们得在项目中引入Jackson依赖,由于Spring web中内置了这个依赖,因此不需要自己特意去引入Jackson直接引入Spring web依赖即可。

    然后使用Jackson提供的ObjectMapper类,由于Spring中已经自动添加了这个类的Bean,我们可以直接注入使用,然后利用Object将返回的Result转为字符串,由于使用objectmapper转换成字符串需要处理一个异常,因此在这里可以加上@SneakyThrows(使用这个注解可以将受检查异常转为非受检查异常(运行时异常),从而使我们不再需要去处理异常信息)具体代码如下:

    Spring Boot 统一功能处理(二)

    我们再通过postMan来测试一下,可以发现,这次没有报错了,但返回类型不在是Json,而是text了:

    Spring Boot 统一功能处理(二)

    四、统一格式返回的优点 

    为什么要这么大费周章设置一个统一返回的格式呢。因为它具有如下一些优点:

    • 方便前端接受和处理后端响应的数据
    • 降低了前后端的沟通成本
    • 有利于项目统一数据的维护和修改
    • 有利于后端进行统一的规范和标准制定,以免后端返回一些乱七八糟的数据
      五、源码角度解析String问题

      接下来我们从源码角度来解释一下为什么当返回的数据类型是String时在进行统一返回处理时会出现类型不匹配异常。

      Spring mvc在使用时,会自动注册一些自带的HttpMessageConverter来处理返回的数据,注册的先后顺序为:

      ByteArrayHttpMessageConverter、StringHttpMessageConverter、SourceHttpMessageCoverter、AllencompassingFormHttpMessageConverter

      Spring Boot 统一功能处理(二)在注册AllencompassingFormHttpMessageConverter时会去引入一些根据项目依赖去引入其它的拓展HttpMessageConvert,例如,项目中如果添加了Jackson则会引入MappingJackson2HttpMessageConverter。

      Spring Boot 统一功能处理(二)

      这些HttpMessageConverter会按照注册的顺序形成一条调用链,如果有数据返回时,spring会对这条链按照先后顺序进行遍历 ,如果找到能处理当前返回数据的数据类型的HttpMessageConverter则会直接使用这个HttpMessageConverter来处理,当我们返回的数据类型是非String时,例如集合,对象等,由于前面的几个HttpMessageConverter都不能使用,所以会使用前面最后引入的MappingJackson2HttpMessageConverter来处理数据,而当返回的是String时,则能够使用StringHttpMessageConverter来进行处理,而StringHttpMessageConverter又在链中靠前的位置,因此在返回String时会使用StringHttpMessageConverter来进行处理。

      接下来我们进到HttpMessageConverter处理数据的具体方法writeWithHttpMessageConvert来看一下:

      打开方法实现往下翻可以看到这样一行代码

      Spring Boot 统一功能处理(二)

      仔细观察可以发现这行代码就是在调用我们前面所设置beforeBodyWrite方法,由此可以推断出在执行完这行代码后body由String转换为我们前面所设置的Result类型了。

      继续往下翻可以发现这样一行代码

      Spring Boot 统一功能处理(二) 由于我们返回的是String,所以这里的converter应该是StringHttpMessageConverter类型的,我们进到write(这里使用的是StringHttpMessageConverter父类AbstarctHttpMessageConverter实现的write方法)方法来看一下:

      Spring Boot 统一功能处理(二)

      可以发现在这里使用的是泛型参数t来接收body,因此没有出现类型匹配问题,在这个方法里调用了一个addDefaultHeaders方法,由于StringHttpMessageConverter重写了这个方法,因此在这里使用的是StringHttpMessageConverter实现的这个方法,我们进到里面去看一下:
      Spring Boot 统一功能处理(二)

      进到里面可以发现这个方法采用的是String类型的s来接收我们前面的t,也就是body,但body已经在前面通过我们定义的beforeBdoyWriter方法由String转换为了Result类型,因此这里在接收参数时,发生了类型不匹配异常,从而也就产生了前面类型不匹配的报错。

VPS购买请点击我

免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

目录[+]