SpringBoot @RestControllerAdvice注解对返回值统一封装的处理方法

 更新时间:2022年09月26日 11:07:24   作者:fengyehongWorld  
这篇文章主要介绍了SpringBoot @RestControllerAdvice注解对返回值统一封装,使用@RestControllerAdvice对响应进行增强,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

一. 需求场景

如下图所示,后台向前台响应数据的时候,所有的数据都需要放入自定义的封装Entity才返回给前台。现在想要每个Controller中的方法将原数据直接返回,然后通过某种方法统一封装处理。

二. 前期准备

⏹获取状态码的接口

public interface IStatusCode {

    int getCode();

    String getMsg();
}

⏹响应状态码的枚举类

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum ResultCodeEnum implements IStatusCode {

    SUCCESS(1000, "请求成功"),
    FAILED(1001, "请求失败"),
    VALIDATE_ERROR(1002, "参数校验失败"),
    RESPONSE_PACK_ERROR(1003, "response返回包装失败");

    private int code;
    private String msg;
}

⏹业务状态码的枚举类

import lombok.AllArgsConstructor;
import lombok.Getter;

@Getter
@AllArgsConstructor
public enum BusinessCodeEnum implements IStatusCode {

    APP_ERROR(2000, "业务异常"),
    PRICE_ERROR(2001, "价格异常");

    private int code;
    private String msg;
}

⏹自定义业务异常类

import lombok.Getter;

@Getter
public class BusinessException extends RuntimeException {

    private int code;

    private String msg;

    // 手动设置异常
    public BusinessException(IStatusCode codeEnum, String message) {
        // message用于用户设置抛出错误详情
        super(message);
        // 状态码
        this.code = codeEnum.getCode();
        // 状态码配套的msg
        this.msg = codeEnum.getMsg();
    }

    // 默认异常使用APP_ERROR状态码
    public BusinessException(String message) {
        super(message);
        this.code = BusinessCodeEnum.APP_ERROR.getCode();
        this.msg = BusinessCodeEnum.APP_ERROR.getMsg();
    }
}

⏹自定义注解,标记该注解的方法不进行响应增强
让我们的方法更加灵活,可以选择增强封装或者不增强。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NotControllerResponseAdvice {
}

三. 使用@RestControllerAdvice对响应进行增强

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Arrays;
import java.util.List;

// 对指定包下面的Controller进行增强
@RestControllerAdvice(basePackages = {"com.example.jmw.controller"})
public class ControllerResponseAdvice implements ResponseBodyAdvice<Object> {

    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> converterType) {

        List<Boolean> judgeResultList = Arrays.asList(
                // ⭕判断相应的类型是否为ResultVo类型
                methodParameter.getParameterType().isAssignableFrom(ResultVo.class),
                // ⭕判断响应的方法上是否包含 NotControllerResponseAdvice 注解
                methodParameter.hasMethodAnnotation(NotControllerResponseAdvice.class)
        );

        // 若包含其中一项,则不进行封装
        return !judgeResultList.contains(true);
    }

    @Override
    public Object beforeBodyWrite(Object body
            , MethodParameter returnType
            , MediaType selectedContentType
            , Class<? extends HttpMessageConverter<?>> selectedConverterType
            , ServerHttpRequest request
            , ServerHttpResponse response
    ) {

        // String类型不能直接包装
        if (returnType.getGenericParameterType().equals(String.class)) {
            ObjectMapper objectMapper = new ObjectMapper();
            try {
                // 将数据包装在ResultVo里后转换为json串进行返回
                return objectMapper.writeValueAsString(ResultVo.build(body));
            } catch (JsonProcessingException e) {
            	// 抛出自定义的业务异常
                throw new BusinessException(ResultCodeEnum.RESPONSE_PACK_ERROR, e.getMessage());
            }
        }

        // 否则直接包装成ResultVo返回
        return ResultVo.build(body);
    }
}

四. 效果

4.1 直接返回List

@Controller
@RequestMapping("/test12")
public class Test12Controller {

    @PostMapping("/test")
    @ResponseBody
    public List<String> test() {

        return Arrays.asList("1", "2", "3");
    }
}

⏹List被包装之后返回给前台

4.2 标记NotControllerResponseAdvice注解后返回List

List未被包装,直接返回数据给前台

4.3 直接返回字符串

4.4 直接返回ResultVo类型数据

⏹返回的就是ResultVo类型,无需包装,直接返回数据给前台

参考资料:

正规军springboot如何处理:参数校验、统一异常、统一响应

到此这篇关于SpringBoot @RestControllerAdvice注解对返回值统一封装的文章就介绍到这了,更多相关SpringBoot返回值统一封装内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Mybatis SqlSessionFactory与SqlSession详细讲解

    Mybatis SqlSessionFactory与SqlSession详细讲解

    SqlSessionFactory是MyBatis的核心类之一,其最重要的功能就是提供创建MyBatis的核心接口SqlSession,所以我们需要先创建SqlSessionFactory,为此我们需要提供配置文件和相关的参数
    2022-11-11
  • SpringBoot整合HTTPS的项目实践

    SpringBoot整合HTTPS的项目实践

    HTTPS的主要作用是通过SSL证书保护用户数据的安全与隐私,增加网站信任度,防止数据被窃取和篡改,保护网站免受钓鱼攻击,本文就来介绍一下,感兴趣的可以了解一下
    2024-10-10
  • 详解Mybatis拦截器安全加解密MySQL数据实战

    详解Mybatis拦截器安全加解密MySQL数据实战

    本文主要介绍了Mybatis拦截器安全加解密MySQL数据实战,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Java复制一个对象并且不想复制其中的空值属性问题

    Java复制一个对象并且不想复制其中的空值属性问题

    这篇文章主要介绍了Java复制一个对象并且不想复制其中的空值属性问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • Java怎样判断堆区中的对象可以被回收了

    Java怎样判断堆区中的对象可以被回收了

    文章介绍了Java垃圾回收机制的工作原理,主要通过引用计数法和可达性分析法来判断对象是否可以被回收,引用计数法存在循环引用问题,而可达性分析法则使用GCRoot对象来判断对象是否可达,从而决定是否回收,这两种方法各有优缺点,但Java最终采用了可达性分析法来实现垃圾回收
    2024-12-12
  • springmvc常用注解标签详解

    springmvc常用注解标签详解

    本篇文章主要介绍了springmvc常用注解标签详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • 详解java的四舍五入与保留位示例

    详解java的四舍五入与保留位示例

    本篇文章主要介绍了java的四舍五入与保留位示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • 解读RabbitMQ和kafka的相同点和不同点是什么

    解读RabbitMQ和kafka的相同点和不同点是什么

    RabbitMQ和Kafka都是消息中间件,支持分布式系统、高可用性和可靠性,RabbitMQ使用队列模型,适合复杂路由场景;Kafka使用主题-分区模型,适合大规模数据流处理,RabbitMQ在低延迟方面表现更好,Kafka在高吞吐量方面表现更好
    2024-12-12
  • MybatisPlus创建时间不想用默认值的问题

    MybatisPlus创建时间不想用默认值的问题

    MybatisPlus通过FieldFill注解和MpMetaObjectHandler类支持自动填充字段功能,特别地,可以设置字段在插入或更新时自动填充创建时间和更新时间,但在特定场景下,如导入数据时,可能需要自定义创建时间
    2024-09-09
  • SpringBoot实现数据源动态切换的最佳姿势

    SpringBoot实现数据源动态切换的最佳姿势

    这篇文章主要为大家详细介绍一下SpringBoot实现数据源动态切换的最佳姿势,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下
    2025-03-03

最新评论