Spring Boot中关于@ControllerAdvice注解的使用

@ControllerAdvice是在SpringMVC中的,Spring Boot可以直接使用。下面在Spring Boot中使用@ControllerAdvice的不同功能。
@ControllerAdvice注解主要有以下三个功能:

  1. 处理全局异常
  2. 预设全局数据
  3. 全局数据预处理

一、处理全局异常

Spring Boot提供了一个默认的映射:/error,当处理中抛出异常之后,会转到该请求中处理,并且该请求有一个全局的错误页面用来展示异常内容。

例如:
设置我们控制器中发生错误,如

 @GetMapping("/test")
  public String test()  {
    int i=5/0;
    return "success";
  }

这时访问会出现下面的报错页,该页面就是Spring Boot提供的默认error映射页面。
在这里插入图片描述
这样的页面对用户不友好,我们一般对全局异常做统一处理。

我们可以通过使用@ControllerAdvice来定义统一的异常处理类,而不是在每个Controller中逐个定义。而@ExceptionHandler用来定义函数针对的异常类型,最后将Exception对象和请求URL映射到error.html中。
如:创建一个MyGlobalExceptionHandler类

@ControllerAdvice
public class MyGlobalExceptionHandler {
  @ExceptionHandler(Exception.class)
  public ModelAndView myError(Exception e, HttpServletRequest request){
    ModelAndView mav=new ModelAndView();
    mav.setViewName("myerror");
   mav.addObject("url",request.getRequestURL());
    mav.addObject("error",e.getMessage());
    return mav;

  }
  }

项目中的Maven依赖有

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>

myerror.html实现,需要先在项目中引入Thymeleaf模板的依赖

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<h1>Error Page</h1>
<h2 th:text="${url}"></h2>
<div>发生错误:</div>
<h2 th:text="${error}"></h2>
</body>
</html>

这样再次访问test,可以看到如下页面:
在这里插入图片描述
在@ControllerAdvice注解的类中,可以定义多个方法,不同的方法处理不同的异常,例如专门处理空指针的方法、专门处理数组越界的方法等,其中使用@ExceptionHandler匹配抛出的异常类型。
也可以直接像上面代码一样,在一个方法中处理所有的异常信息。

二、预设全局数据

我们可以将一些公共的数据定义在添加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中都能够访问调用这些数据。
使用示例:首先在添加了 @ControllerAdvice 注解的类中定义全局数据

@ControllerAdvice
public class MyGlobalExceptionHandler {
  @ModelAttribute("md")
  public Map<String,Object> myData(){
    Map<String,Object> map=new HashMap<String, Object>();
    map.put("name","张三");
    map.put("age",18);
    return map;
  }
}

这里返回的全局数据map的key默认就是变量名即map,这里可以通过@ModelAttribute注解的name属性进行自定义key。

定义一个控制器。提供接口“/getData”进行访问

@RestController
public class TestController {
  @GetMapping("/getData")
  public void getData(Model model){
    Map<String,Object> map=model.asMap();
    Set<String> set=map.keySet();
    for(String s:set){
      System.out.println(s+":"+map.get(s));
    }
  }
}

在控制台中查看是否取到值
在这里插入图片描述

三、全局数据预处理

@ControllerAdvice还能用于预处理请求参数,当前端传递两个实体类的参数,而两个实体类有相同属性时。就需要对参数进行预处理了。
例如:有一个Teacher类,有id和name属性。

public class Teacher {
  private int id;
  private String name;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @Override
  public String toString() {
    return "Teacher{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
  }
}

另外有个Student类,这两个类有相同的属性,如下:

public class Student {
  private int id;
  private String name;

  public int getId() {
    return id;
  }

  public void setId(int id) {
    this.id = id;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }

  @Override
  public String toString() {
    return "Student{" +
            "id=" + id +
            ", name='" + name + '\'' +
            '}';
  }
}

定义一个Controller

@RestController
public class TestController {

  @PostMapping("/setData")
  public void setData(Teacher teacher,Student student){
    System.out.println(teacher);
    System.out.println(student);
  }

}

通过Postman发送post请求数据
在这里插入图片描述
查看控制台输入的数据:
在这里插入图片描述
可以看到收到的数据有问题,前端发来的数据,因为接受数据的两个实体类属性相同,所以无法区分。

解决方案
在 @ControllerAdvice 注解的类中添加如下代码:

  @InitBinder("s")
  public void s(WebDataBinder binder){
    binder.setFieldDefaultPrefix("s.");
  }
  @InitBinder("t")
  public void t(WebDataBinder binder){
    binder.setFieldDefaultPrefix("t.");
  }

@InitBinder搭配配置WebDataBinder,自动绑定前台请求参数到Model中。
上面的使用:
@InitBinder(“s”) 注解表示该方法用来处理和Student实体类相关的参数,在该注解下的方法中,给参数添加一个 s前缀,那么我们请求参数要有s前缀。
@InitBinder(“t”) 注解表示该方法用来处理和Teacher实体类相关的参数,在该注解下的方法中,给参数添加一个 t前缀,那么我们请求参数要有t前缀。

接口方法中使用@ModelAttribute注解给变量其别名

  @PostMapping("/setData")
  public void setData(@ModelAttribute("t") Teacher teacher, @ModelAttribute("s")Student student){
    System.out.println(teacher);
    System.out.println(student);
  }

请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分。
在这里插入图片描述
查看控制台输出,可以看到数据获取正确。
在这里插入图片描述

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,很高兴能回答您的问题。 首先,让我们了解一下 @ControllerAdvice 注解。它是 Spring MVC 框架提供的一种全局异常处理机制,可以让我们在一个地方集处理所有 Controller 抛出的异常。 使用 @ControllerAdvice 注解的类可以包含多个 @ExceptionHandler 注解的方法,每个方法处理不同的异常类型。当 Controller 抛出异常时,Spring 会根据异常类型找到对应的 @ExceptionHandler 方法进行处理。 以下是一个简单的 @ControllerAdvice 示例: ```java @ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(Exception.class) public ResponseEntity<String> handleException(Exception e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Something went wrong!"); } @ExceptionHandler(MyCustomException.class) public ResponseEntity<String> handleMyCustomException(MyCustomException e) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(e.getMessage()); } } ``` 在上面的例子,我们定义了两个 @ExceptionHandler 方法,分别处理 Exception 和 MyCustomException 类型的异常。 如果您想要更细粒度地处理异常,可以在 @ExceptionHandler 注解指定具体的异常类型,如下所示: ```java @ExceptionHandler({IOException.class, SQLException.class}) public void handleIOExceptionOrSQLException() { // ... } ``` 另外,@ControllerAdvice 还支持自定义返回值类型和异常解析器,具体可以参考 Spring 官方文档。 最后,关于统一处理异常,除了使用 @ControllerAdvice,我们还可以使用 Spring Boot 提供的 ErrorController 接口或实现自己的异常处理器。 希望能对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值