Spring注解@RestControllerAdvice原理解析

这篇文章主要介绍了Spring注解@RestControllerAdvice原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下

前言

前段时间部门搭建新系统,需要出异常后统一接口的返回格式,于是用到了Spring的注解@RestControllerAdvice。现在把此注解的用法总结一下。

用法

首先定义返回对象ResponseDto

package com.staff.points.common;

import lombok.Data;

import java.io.Serializable;

@Data
public class ResponseDto<T> implements Serializable {
  private static final long serialVersionUID = -284719732991678911L;

  private String code;

  private String message;

  private T data;

  public static <T> ResponseDto<T> assemblingSuccessResponse(T data) {
    ResponseDto<T> responseDto = new ResponseDto<>();
    responseDto.setCode(ResponseCodeEnum.SUCCESS.getCode());
    responseDto.setMessage(ResponseCodeEnum.SUCCESS.getMessage());
    responseDto.setData(data);
    return responseDto;
  }

  public static <T> ResponseDto<T> assemblingSuccessResponse() {
    ResponseDto<T> responseDto = new ResponseDto<>();
    responseDto.setCode(ResponseCodeEnum.SUCCESS.getCode());
    responseDto.setMessage(ResponseCodeEnum.SUCCESS.getMessage());
    responseDto.setData(null);
    return responseDto;
  }

  public static <T> ResponseDto<T> assemblingFailureResponse(ResponseCodeEnum data) {
    ResponseDto<T> responseDto = new ResponseDto<>();
    responseDto.setCode(data.FAILURE.getCode());
    responseDto.setMessage(data.FAILURE.getMessage());
    return responseDto;
  }

  public static <T> ResponseDto<T> assemblingFailureResponse() {
    ResponseDto<T> responseDto = new ResponseDto<>();
    responseDto.setCode(ResponseCodeEnum.FAILURE.getCode());
    responseDto.setMessage(ResponseCodeEnum.FAILURE.getMessage());
    return responseDto;
  }
}

然后定义返回码的枚举类,此处只定义了两种,有需要可以往下添加很多。

package com.staff.points.common;

import lombok.AllArgsConstructor;
import lombok.Getter;

@AllArgsConstructor
@Getter
public enum ResponseCodeEnum {
  SUCCESS("00", "成功"),
  FAILURE("01", "系统异常");

  private String code;
  private String message;
}

下面是自定义的异常类

package com.staff.points.common;

import lombok.Data;

@Data
public class StaffPointsException extends RuntimeException{
  private String code;
  private String message;
  public StaffPointsException () {}

  public StaffPointsException (Exception e) {
    super(e);
  }

  public StaffPointsException (String code, String message) {
    super(message);
    this.code = code;
    this.message = message;
  }

  public StaffPointsException (ResponseCodeEnum codeEnum) {
    super(codeEnum.getMessage());
    this.code = codeEnum.getCode();
    this.message = codeEnum.getMessage();
  }
}

然后是关键的@RestControllerAdvice修饰的类

package com.staff.points.exception;

import com.staff.points.common.ResponseCodeEnum;
import com.staff.points.common.ResponseDto;
import com.staff.points.common.StaffPointsException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

@RestControllerAdvice
@Component
public class UnifyExceptionHandler {
  private Logger logger = LoggerFactory.getLogger(UnifyExceptionHandler.class);

  @ExceptionHandler(Exception.class)
  public ResponseDto handlerCommonException (Exception e) {
    ResponseDto responseDto = new ResponseDto<>();
    responseDto.setCode(ResponseCodeEnum.FAILURE.getCode());
    responseDto.setMessage(ResponseCodeEnum.FAILURE.getMessage());
    logger.info("UnifyExceptionHandler.handlerCommonException exception:" + e);
    return responseDto;
  }
  // 报StaffPointException时,对其进行拦截并处理的方法
  @ExceptionHandler(StaffPointsException.class)
  public ResponseDto handlerCustomizeException (StaffPointsException e) {
    ResponseDto responseDto = new ResponseDto<>();
    responseDto.setCode(e.getCode());
    responseDto.setMessage(e.getMessage());
    logger.info("UnifyExceptionHandler.handlerCustomizeException StaffPointsException:" + e);
    return responseDto;
  }
}

运行代码时,如果出现了StaffPointException,那么就会被拦截进入第27行的方法(就是说可以自由的在业务代码里往外throw自定义异常了);如果出现了其他的异常,则进入18行的方法,统一返回。

验证一下,在代码里造一个NPE异常时,返回结果:

 {
  "code": "01",
  "message": "系统异常",
  "data": null
 }

造一个StaffPointsException异常时,返回结果:

 {
  "code": "99",
  "message": "自定义业务异常",
  "data": null
 }

它的作用原理,大体是先在spring初始化时将类扫描进容器,出异常后,在DispatcherServlet类的doDispatch方法中调用了对异常的拦截处理。

小结

看@RestControllerAdvice源码可以知道,它就是@ControllerAdvice和@ResponseBody的合并。此注解通过对异常的拦截实现的统一异常返回处理,如果大家在项目中有类似的需求,不妨试一下,好用又方便。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 解决SpringMVC Controller 接收页面传递的中文参数出现乱码的问题

    新配置一个spring的MVC项目,发现对Get请求的中文参数出现了乱码: 查看了SpingMVC中关于编码的配置(在web.xml中),如下: <filter> <filter-name>encodingFilter</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param>

  • 解决Spring Boot 正常启动后访问Controller提示404问题

    问题描述 今天重新在搭建Spring Boot项目的时候遇到访问Controller报404错误,之前在搭建的时候没怎么注意这块.新创建项目成功后,作为项目启动类的Application在com.blog.start包下面,然后我写了一个Controller,然后包的路径是com.blog.ty.controller用的@RestController 注解去配置的controller,然后路径也搭好了,但是浏览器一直报404.最后找到原因是Spring Boot只会扫描启动类当前包和以下的包 ,

  • SpringBoot Controller Post接口单元测试示例

    概述 在日常的开发中,我们一般会定义一个service层,用于实现业务逻辑,并且针对service层会有与之对应的齐全的覆盖率高的单元测试.而对于controller层,一般不怎么做单元测试,因为主要的核心业务逻辑都在service层里,controller层只是做转发,调用service层接口而已.但是还是建议使用单元测试简单的将controller的方法跑一下,看看转发和数据转换的代码是否能正常工作. 在Spring Boot里对controller层进行单元测试非常简单,只需要几个注解和一

  • SpringMVC @ControllerAdvice使用场景

    这篇文章主要介绍了SpringMVC @ControllerAdvice使用场景,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 @ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller.使用这个 Controller ,可以实现三个方面的功能: 全局异常处理 全局数据绑定 全局数据预处理 灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这

  • 详解SpringBoot Controller接收参数的几种常用方式

    第一类:请求路径参数 1.@PathVariable 获取路径参数.即url/{id}这种形式. 2.@RequestParam 获取查询参数.即url?name=这种形式 例子 GET http://localhost:8080/demo/123?name=suki_rong 对应的java代码: @GetMapping("/demo/{id}") public void demo(@PathVariable(name = "id") String id, @Re

  • java springboot poi 从controller 接收不同类型excel 文件处理

    根据poi接收controller层的excel文件导入 可使用后缀名xls或xlsx格式的excel. 1.pom引入 <!-- poi 操作Excel --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> <d

  • spring boot中controller的使用及url参数的获取方法

    类上加上@RequestMapping其访问的地址就是类上的加上方法上的菜能访问到该方法,例如上图的地址就是/hello/say @RequestMapping(value = "/hello",method = RequestMethod.GET) 和@GetMapping(value = "/hello")是等同的 这样就能获取url参数的值了,其结果如下 总结 以上所述是小编给大家介绍的spring boot中controller的使用及url参数的获取方法,

  • 详解Spring MVC如何测试Controller(使用springmvc mock测试)

    在springmvc中一般的测试用例都是测试service层,今天我来演示下如何使用springmvc mock直接测试controller层代码. 1.什么是mock测试? mock测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法. 2.为什么要使用mock测试? 使用Mock O bject进行测试,主要是用来模拟那些在应用中不容易构造(如HttpServletRequest必须在Servlet容器中才能构造出来)或者比较复杂的对象(如J

  • Spring注解@RestControllerAdvice原理解析

    这篇文章主要介绍了Spring注解@RestControllerAdvice原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言 前段时间部门搭建新系统,需要出异常后统一接口的返回格式,于是用到了Spring的注解@RestControllerAdvice.现在把此注解的用法总结一下. 用法 首先定义返回对象ResponseDto package com.staff.points.common; import lombok.Data;

  • Spring注解@Import原理解析

    目录 正文 @Import 原理 示例 @EnableAsync 正文 在项目开发的过程中,我们会遇到很多名字为 @Enablexxx 的注解,比如@EnableApolloConfig. @EnableFeignClients. @EnableAsync 等.他们的功能都是通过这样的注解实现一个开关,决定了是否开启某个功能模块的所有组件的自动化配置,这极大的降低了我们的使用成本. 那么你是好奇过 @Enablexxx 是如何达到这种效果呢,其作用机制是怎么样的呢? @Import 原理 按照默

  • SpringBoot http请求注解@RestController原理解析

    这篇文章主要介绍了SpringBoot http请求注解@RestController原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 @RestController @RestController = @Controller + @ResponseBody组成,等号右边两位同志简单介绍两句,就明白我们@RestController的意义了: @Controller 将当前修饰的类注入SpringBoot IOC容器,使得从该类所在的项目

  • 阿里四面之Spring Exception的原理解析

    错误场景 验证请求的Token合法性的Filter.Token校验失败时,直接抛自定义异常,移交给Spring处理: 测试HTTP请求: 日志输出如下:说明IllegalRequestExceptionHandler未生效. why?这就需要精通Spring异常处理流程了. 解析 当所有Filter被执行完毕,Spring才会处理Servlet相关,而DispatcherServlet才是整个Servlet处理核心,它是前端控制器设计模式,提供 Spring Web MVC 的集中访问点并负责职

  • Spring底层事务原理解析

    目录 一.@EnableTransactionManagement工作原理 二.Spring事务基本执行原理 四.Spring事务传播机制 五.Spring事务传播机制分类 六.Spring事务强制回滚 七.TransactionSynchronization 一.@EnableTransactionManagement工作原理 开启Spring事务本质上就是增加了一个Advisor,但我们使用 @EnableTransactionManagement注解来开启Spring事务是,该注解代理的功

  • Spring注解@Scope原理及用法解析

    主要从以下几方面来介绍一下@Scope注解 @Scope注解是什么 @Scope注解怎么使用 @Scope注解的使用场景 1,@Scope注解是什么 @Scope注解是springIoc容器中的一个作用域,在 Spring IoC 容器中具有以下几种作用域:基本作用域singleton(单例).prototype(多例),Web 作用域(reqeust.session.globalsession),自定义作用域 a.singleton单例模式 -- 全局有且仅有一个实例 b.prototype原

  • Spring AOP实现原理解析

    什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善.OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无

  • Spring注解@Conditional案例解析

    [1]@Conditional介绍 @Conditional是Spring4新提供的注解,它的作用是按照一定的条件进行判断,满足条件给容器注册bean. @Conditional源码: //此注解可以标注在类和方法上 @Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Conditional { Class<? exten

  • 彻底理解Spring注解@Autowired实现原理

    目录 前言 1.@Autowired注解用法 2.@Autowired注解的作用到底是什么 3.@Autowired注解是如何实现的 自己实现一个注解 4.@Autowired注解实现逻辑分析 5.问题 5.1.注解的有效周期是什么? 5.2.注入的bean和用它的bean的关系是如何维护的? 5.3.为什么注入的bean不能被定义为static的? 前言 使用spring开发时,进行配置主要有两种方式,一是xml的方式,二是java config的方式. spring技术自身也在不断的发展和改

  • Spring @Conditional注解原理解析

    这篇文章主要介绍了Spring @Conditional注解原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 @Conditional是Spring4新提供的注解,它的作用是根据某个条件加载特定的bean. 我们需要创建实现类来实现Condition接口,这是Condition的源码 public interface Condition { boolean matches(ConditionContext var1, AnnotatedT

随机推荐