SpringBoot的@RestControllerAdvice作用详解

 更新时间:2024年01月17日 09:30:08   作者:java-zh  
这篇文章主要介绍了SpringBoot的@RestControllerAdvice作用详解,@RestContrllerAdvice是一种组合注解,由@ControllerAdvice,@ResponseBody组成,本质上就是@Component,需要的朋友可以参考下

一、@RestControllerAdvice是什么?

@RestContrllerAdvice是一种组合注解,由@ControllerAdvice,@ResponseBody组成

@ControllerAdvice继承了@Component,反过来,可以理解为@RestContrllerAdvice本质上就是@Component

1.1 @Component是什么?

本质上是一个类,泛指各种组件,就是说当我们的类不属于各种归类的时候(不属于@Controller,@Service等的时候),我们就可以使用@Component

作用就是实现bean注入,利用这个注解可以取代spring的xml配置文件

1.2 @Component案例

1.2.1 准备的jar

 <dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.75</version>
</dependency>

1.2.2 controller

@RestController
public class TestController {
    @Autowired
    private TestService testService;
    @GetMapping("/test3")
    public String test3() {
        return testService.test();
    }
}

1.2.3 接口

public interface TestService {
    String test();
}

1.2.4组件

@Component
public class TestServiceImpl implements TestService {
    @Autowired
    private ObjectMapper objectMapper;
    @Override
    public String test() {
        String b = null;
        try {
            b =  objectMapper.writeValueAsString("a");
            System.out.println(b);
        } catch (Exception e) {
        }
        return b;
    }
}

二、@RestControllerAdvice有什么作用?

  • 自定义客户端返回格式
  • 捕获客户端返回异常

三、@RestControllerAdvice案例和使用场景

捕获客户端返回异常案例(自定义返回异常)

3.1 未自定义捕获异常之前

3.2 自定义捕获异常以后

3.3代码实现自定义捕获异常

3.3.1 自定义异常枚举

public interface BaseCodeMsg {
    String getCode();
    String getMsg();
}
public enum PlatformExceptionMsgEnum implements BaseCodeMsg {
    /**
     * base平台返回的异常信息
     */
    SELECT_NULL("000000001", "查询数据为空"),
    INVOKE_IS_REJECT("00000002", "请求被拒绝"),
    ILLEGAL_ARGUMENT_FORMAT("000000003", "非法参数格式"),
    ILLEGAL_ARGUMENT("000000004","数据非法"),
    SYSTEM_EXCEPTION("000000005", "系统异常");
    /**
     * 错误码
     */
    private final String code;
    /**
     * 错误信息
     */
    private final String msg;
    PlatformExceptionMsgEnum(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    @Override
    public String getCode() {
        return code;
    }
    @Override
    public String getMsg() {
        return msg;
    }
}

3.3.2 自定义平台异常

public abstract class AbstractApiException extends RuntimeException{
    public AbstractApiException() {
    }
    public abstract String getCode();
    public abstract String getMsg();
}
public class PlatformException extends AbstractApiException {
    private String code;
    private String msg;
    public PlatformException(BaseCodeMsg baseCodeMsg) {
        code = baseCodeMsg.getCode();
        msg = baseCodeMsg.getMsg();
    }
    public static void throwException(BaseCodeMsg baseCodeMsg) {
        throw new PlatformException(baseCodeMsg.getCode(), baseCodeMsg.getMsg());
    }
    public static void throwException(BaseCodeMsg baseCodeMsg, String msg) {
        throw new PlatformException(baseCodeMsg.getCode(), StringUtils.isEmpty(baseCodeMsg.getMsg()) ? msg : baseCodeMsg.getMsg());
    }
    public static void throwException(String code, String msg) {
        throw new PlatformException(code, msg);
    }
    public static void throwException(String msg) {
        throw new PlatformException(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION.getCode(), msg);
    }
    public PlatformException(String code, String msg) {
        this.code = code;
        this.msg = msg;
    }
    @Override
    public String getCode() {
        return code;
    }
    @Override
    public String getMsg() {
        return msg;
    }
}

3.3.3 自定义返回类

@Data
public class BaseResult<T> implements Serializable {
    private static final long serialVersionUID = 1L;
    private String code;
    private String msg;
    private String traceId;
    private T data;
    public boolean isSuccess() {
        return PlatformExceptionMsgEnum.SUCCESS.getCode().equals(this.code);
    }
    public static BaseResult ok() {
        return restBaseResult((Object)null, PlatformExceptionMsgEnum.SUCCESS);
    }
    public static <T> BaseResult<T> ok(T data) {
        return restBaseResult(data, PlatformExceptionMsgEnum.SUCCESS);
    }
    public static BaseResult fail() {
        return restBaseResult((Object)null, PlatformExceptionMsgEnum.SYSTEM_ERROR);
    }
    public static BaseResult fail(BaseCodeMsg baseCodeMsg) {
        return restBaseResult((Object)null, baseCodeMsg);
    }
    public static BaseResult fail(String code, String msg) {
        return restBaseResult((Object)null, code, msg);
    }
    private static <T> BaseResult<T> restBaseResult(T data, BaseCodeMsg baseCodeMsg) {
        return restBaseResult(data, baseCodeMsg.getCode(), baseCodeMsg.getMsg());
    }
    private static <T> BaseResult<T> restBaseResult(T data, String code, String msg) {
        BaseResult<T> apiBaseResult = new BaseResult();
        apiBaseResult.setCode(code);
        apiBaseResult.setData(data);
        apiBaseResult.setMsg(msg);
        apiBaseResult.setTraceId(MDC.get("traceId"));
        return apiBaseResult;
    }
    public BaseResult() {
    }
}

3.3.4 controller层

@RestController
public class TestController {
    @GetMapping("/test")
    public void test() {
        PlatformException.throwException(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION);
    }
}

3.3.5 @RestControllerAdvice

@RestControllerAdvice
@Configuration
public class GlobalExceptionHandler {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    private MessageSource messageSource;
    /**
     * 捕获全局异常类
     *
     * @param e
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public BaseResult handle(MethodArgumentNotValidException e) {
        if (e.getBindingResult().hasErrors()) {
            String msg = ((ObjectError) e.getBindingResult().getAllErrors().get(0)).getDefaultMessage();
            return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getCode(), this.getI18nMsg(msg));
        } else {
            log.info(e.getMessage(), e);
            return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT.getMsg()));
        }
    }
    /**
     * 捕获API调用接口的异常类
     *
     * @param e
     * @return
     */
    @ExceptionHandler(AbstractApiException.class)
    public BaseResult abstractApiException(AbstractApiException e) {
        return BaseResult.fail(e.getCode(), e.getMsg());
    }
    /**
     * 前端传入的参数和后端传入的参数接收不匹配
     *
     * @param e
     * @return
     */
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public BaseResult handle(HttpMessageNotReadableException e) {
        log.warn(e.getMessage(), e);
        return BaseResult.fail(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT_FORMAT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.ILLEGAL_ARGUMENT_FORMAT.getMsg()));
    }
    /**
     * 子类异常(相当于子类不能抛出比父类更广泛异常)
     *
     * @param e
     * @return
     */
    @ExceptionHandler({UndeclaredThrowableException.class})
    public BaseResult handle(UndeclaredThrowableException e) {
        log.warn(e.getMessage(), e);
        return BaseResult.fail(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getCode(), this.getI18nMsg(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getMsg()));
    }
    /**
     * 异常捕获
     *
     * @param e 捕获的异常,封装返回的对象
     * @return
     */
    @ExceptionHandler(Exception.class)
    public BaseResult handleException(Exception e) {
        log.warn(e.getMessage(), e);
        StringJoiner joiner = new StringJoiner(":");
        joiner.add(this.getI18nMsg(PlatformExceptionMsgEnum.INVOKE_IS_REJECT.getMsg())).add(e.getMessage());
        return BaseResult.fail(PlatformExceptionMsgEnum.SYSTEM_EXCEPTION.getCode(), joiner.toString());
    }
    private String getI18nMsg(String msg) {
        try {
            return this.messageSource.getMessage(msg, (Object[]) null, LocaleContextHolder.getLocale());
        } catch (NoSuchMessageException var3) {
            return msg;
        }
    }
    public GlobalExceptionHandler(MessageSource messageSource) {
        this.messageSource = messageSource;
    }
}

3.4 代码实现自定义返回结果

没有自定义返回结果之前

自定义返回结果以后

3.4.1 controller

@RestController
public class TestController {
    @GetMapping("/test2")
    public String test2() {
        return "test2";
    }
}

3.4.2 返回结果来

BaseResult返回结果类在上面,对应需要导入json的jar也在上面

3.4.3 @RestControllerAdvice

@RestControllerAdvice(
        annotations = {RestController.class}
)
@Configuration
public class BaseResultResponseAdvice implements ResponseBodyAdvice<Object> {
    @Autowired
    private ObjectMapper objectMapper;
    /**
     * @param methodParameter 利用这个参数判断注解信息
     * @param aClass
     * @return
     */
    @Override
    public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
        return true;
    }
    /**
     * @param body               原controller需要返回的内容
     * @param methodParameter    利用这个参数判断注解信息
     * @param mediaType
     * @param aClass
     * @param serverHttpRequest
     * @param serverHttpResponse
     * @return
     */
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter methodParameter, MediaType mediaType, Class<? extends HttpMessageConverter<?>> aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse) {
        try {
            if (methodParameter.getParameterType() == ResponseEntity.class) {
                return body;
            } else if (methodParameter.getParameterType() == BaseResult.class) {
                return body;
            } else if (methodParameter.getParameterType() == String.class) {
                serverHttpResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
                return this.objectMapper.writeValueAsString(BaseResult.ok(body));
            } else {
                return BaseResult.ok(body);
            }
        } catch (Throwable t) {
            return BaseResult.fail();
        }
    }
}

四、拓展

@RestControllerAdvice的使用还可以指定对应的注解、包,类。比如你需要返回自定义结果格式,可以指定@RestController层使用,如果你要指定类和包也可以

4.1 指定注解

@RestControllerAdvice(
        annotations = {RestController.class}
)

4.2 指定类

@RestControllerAdvice(
        basePackageClasses = TestController.class
)

4.3 指定包

@RestControllerAdvice(
        basePackages = "com.common.base.controller"
)

到此这篇关于SpringBoot的@RestControllerAdvice作用详解的文章就介绍到这了,更多相关@RestControllerAdvice作用内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Boot如何移除内嵌Tomcat,使用非web方式启动

    Spring Boot如何移除内嵌Tomcat,使用非web方式启动

    这篇文章主要介绍了Spring Boot如何移除内嵌Tomcat,使用非web方式启动,帮助大家更好的理解和学习使用spring boot框架,感兴趣的朋友可以了解下
    2021-02-02
  • java工具类static静态方法读取yml配置过程

    java工具类static静态方法读取yml配置过程

    文章介绍了在工具类中获取YAML配置时遇到的问题,由于变量是静态的,而Spring加载静态方法比IOC容器早,导致无法直接使用@Value注解读取YAML配置,从而读取结果为null
    2024-11-11
  • SpringBoot中的Lombok库及使用举例详解

    SpringBoot中的Lombok库及使用举例详解

    Lombok是一个Java库,通过注解的方式简化代码编写,减少样板代码,它能够自动生成getter、setter、构造函数、toString等方法,提升开发效率,这篇文章主要介绍了SpringBoot中的Lombok库,需要的朋友可以参考下
    2025-05-05
  • java音频播放示例分享(java如何播放音频)

    java音频播放示例分享(java如何播放音频)

    java如何播放音频?下面的代码就介绍了java音频播放示例,需要的朋友可以参考下
    2014-04-04
  • Java 普通代码块静态代码块执行顺序(实例讲解)

    Java 普通代码块静态代码块执行顺序(实例讲解)

    下面小编就为大家带来一篇Java 普通代码块静态代码块执行顺序(实例讲解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • SpringBoot项目使用mybatis-plus代码生成的实例详解

    SpringBoot项目使用mybatis-plus代码生成的实例详解

    mybatis-plus是mybatis的增强,不对mybatis做任何改变,涵盖了代码生成,自定义ID生成器,快速实现CRUD,自动分页,逻辑删除等功能。本文就来讲讲SpringBoot项目如何使用mybatis-plus实现代码生成,需要的可以了解一下
    2022-10-10
  • SpringBoot 分布式验证码登录方案示例详解

    SpringBoot 分布式验证码登录方案示例详解

    为了防止验证系统被暴力破解,很多系统都增加了验证码效验,比较常见的就是图片二维码,业内比较安全的是短信验证码,当然还有一些拼图验证码,加入人工智能的二维码等等,我们今天的主题就是前后端分离的图片二维码登录方案,感兴趣的朋友一起看看吧
    2023-10-10
  • java IO实现电脑搜索、删除功能的实例

    java IO实现电脑搜索、删除功能的实例

    下面小编就为大家带来一篇java IO实现电脑搜索、删除功能的实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • SpringBoot3.3.0升级方案

    SpringBoot3.3.0升级方案

    本文介绍了由SpringBoot2升级到SpringBoot3.3.0升级方案,新版本的升级可以解决旧版本存在的部分漏洞问题,感兴趣的可以了解一下
    2024-08-08
  • java异常处理throws完成异常抛出详解

    java异常处理throws完成异常抛出详解

    这篇文章主要介绍了java异常处理中throws完成异常抛出示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家学有所得多多进步
    2021-10-10

最新评论