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

导读:本篇文章讲解 Spring Boot中关于@ControllerAdvice注解的使用,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

@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);
  }

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

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之家整理,本文链接:https://www.bmabk.com/index.php/post/44374.html

(0)
小半的头像小半

相关推荐

极客之家——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!