• Spring MVC总结2 - @ControllerAdvice详解


    目录:

    1. @ControllerAdvice详解
    2.  @ControllerAdvice与@ExceptionHandler、@InitBinder搭配使用

    一.@ControllerAdvice详解

    @ControllerAdvice是Spring提供的注释,使您可以编写可应用于各种控制器的全局代码-从所有控制器到选定的包,甚至是特定的注释。在这个简短的教程中,我们将专注于处理异常使用@ControllerAdvice和@ExceptionHandler(@InitBinder和@ModalAttribute也可以使用@ControllerAdvice)。

    默认情况下,  @ControllerAdvice将应用于使用@Controller注释的所有类(扩展到使用的类@RestController)。如果您想更具体一点,可以使用一些属性来实现这一点。

    要按包减少适用的类,您只需要将包的名称添加到注释中。选择一个程序包后,将为该程序包内的子类以及子程序包启用该程序包。也可以按照相同的过程选择多个包,但是使用数组而不是单个字符串(其中的所有属性都@ControllerAdvice可以是单个或多个)。

    @ControllerAdvice("my.chosen.package")
    @ControllerAdvice(value = "my.chosen.package")
    @ControllerAdvice(basePackages = "my.chosen.package")
    如果要指定特定的包,可以通过basePackageClasses属性来指定包,该属性将使@ControllerAdvice类(或接口)所在的包中的所有控制器都可用。
    如果要指定特定的类,可以通过assignableTypes = MyController.class来指定。
    如果要应用于某些带注释的控制器,可以使用  @ControllerAdvice(annotations = RestController.class) ,此处仅对RestController起作用,而不会对带controller的起作用,尽管RestControlle注解相当于@ResponseBody + @Controller。

    @ExceptionHandler顾名思义,您可以定义一个处理异常的方法。如果您不使用@ControllerAdvice ,则处理这些异常的代码将在控制器本身中,这可能会给类增加很多重复和混乱,并导致其不那么“干净”。您可以将这些@ExceptionHandler方法移到控制器扩展以分离代码的基类中。此方法并不完美,并且存在一个问题,即您需要此全局异常处理的每个控制器现在都需要扩展基本控制器。因此,当您创建一个新的控制器而忘记扩展此基类时,您现在不再处理某些异常,以后可能会陷入困境。使用@ControllerAdvice随@ExceptionHandler 通过提供全局(更具体的)错误处理来防止这种情况的发生,因此您无需记住自己实现它们或每次扩展另一个类。

    示例:

    1. import java.text.DateFormat;
    2. import java.text.SimpleDateFormat;
    3. import java.util.Date;
    4. import java.util.HashMap;
    5. import java.util.Map;
    6. import org.slf4j.Logger;
    7. import org.slf4j.LoggerFactory;
    8. import org.springframework.beans.propertyeditors.CustomDateEditor;
    9. import org.springframework.http.HttpStatus;
    10. import org.springframework.http.ResponseEntity;
    11. import org.springframework.web.bind.WebDataBinder;
    12. import org.springframework.web.bind.annotation.ControllerAdvice;
    13. import org.springframework.web.bind.annotation.ExceptionHandler;
    14. import org.springframework.web.bind.annotation.InitBinder;
    15. import org.springframework.web.bind.annotation.ModelAttribute;
    16. //@ControllerAdvice(basePackages = {"springboot.controller"}) //指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
    17. //@ControllerAdvice(basePackageClasses = {HelloController.class}) //指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
    18. //@ControllerAdvice(assignableTypes = {HelloController.class}) //指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理
    19. //@ControllerAdvice(annotations = {HelloController.class}) //指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理。
    20. //指定特定的类生效(assignableTypes = HelloController.class)) 只对HelloController文件做异常处理
    21. //指定所在的包生效(basePackageClasses={HelloController.class})
    22. @ControllerAdvice
    23. public class GlobalExceptionHandler {
    24. private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    25. // 全局异常处理
    26. @ExceptionHandler(ArithmeticException.class)
    27. // 或者 public ResponseEntity<Object> costomException(ArithmeticException e) {
    28. public ResponseEntity<Object> costomException1(Exception e) {
    29. logger.info("被除数不能为0", e);
    30. Map<String, Object> result = new HashMap();
    31. result.put("code", 1);
    32. result.put("msg", "被除数不能为0");
    33. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    34. }
    35. @ExceptionHandler(ArrayIndexOutOfBoundsException.class)
    36. // 或者 public ResponseEntity<Object> costomException(ArrayIndexOutOfBoundsException e) {
    37. public ResponseEntity<Object> costomException2(Exception e) {
    38. logger.info("数组索引越界异常", e);
    39. Map<String, Object> result = new HashMap();
    40. result.put("code", 1);
    41. result.put("msg", "数组索引超出异常");
    42. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    43. }
    44. /**
    45. * @Description: 没有指定的异常走这里
    46. */
    47. @ExceptionHandler
    48. public ResponseEntity<Object> costomException(Exception e) {
    49. logger.info("未知错误", e);
    50. Map<String, Object> result = new HashMap();
    51. result.put("code", 1);
    52. result.put("msg", "未知错误");
    53. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    54. }
    55. // 全局数据绑定
    56. @ModelAttribute(name = "initData")
    57. public Map<String,Object> mydata() {
    58. HashMap<String, Object> map = new HashMap<>();
    59. map.put("age", 99);
    60. map.put("gender", "男");
    61. return map;
    62. }
    63. // 全局数据预处理
    64. @InitBinder
    65. public void InitBinder(WebDataBinder binder) {
    66. //前端传入的时间格式必须是"yyyy-MM-dd"效果!
    67. DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    68. CustomDateEditor dateEditor = new CustomDateEditor(df, true);
    69. binder.registerCustomEditor(Date.class, dateEditor);
    70. }
    71. }

    此类@ExceptionHandler为所有控制器全局提供了方法,因为(单独从此代码中看不到)有多个throw的控制器PersonNotFoundException需要处理。RequestMapping此处的注释用于设置所返回的内容类型ResponseEntity。这些可以添加到方法本身,而不是需要返回的不同类型。每个@ExceptionHandler标记实例都负责处理一个异常。本示例中的方法仅捕获异常并获取其错误消息,然后将其与适当的响应代码组合在一起。

    @ExceptionHandler为同一异常定义了多个对象  ,需要进行监视。当在同一类中定义时,Spring足以引发异常并在启动时失败。但是,当它们出现在不同的类中时,例如说两个@ControllerAdvice类,都带有的处理程序PersonNotFoundException,应用程序将启动-但将使用找到的第一个处理程序。如果您不知道,这可能会导致意外的行为。

     

    二.@ControllerAdvice与@ExceptionHandler、@InitBinder搭配使用

    @ControllerAdvice ,很多初学者可能都没有听说过这个注解,实际上,这是一个非常有用的注解,顾名思义,这是一个增强的 Controller。使用这个 Controller ,可以实现三个方面的功能:

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

    灵活使用这三个功能,可以帮助我们简化很多工作,需要注意的是,这是 SpringMVC 提供的功能,在 Spring Boot 中可以直接使用,下面分别来看。

    springboot项目全局异常处理@ControllerAdvice(方式二) - 探歌 - 博客园

    示例:

    GlobalExceptionHandler.class

    1. package springboot.controller;
    2. import java.text.DateFormat;
    3. import java.text.SimpleDateFormat;
    4. import java.util.Date;
    5. import java.util.HashMap;
    6. import java.util.Map;
    7. import org.slf4j.Logger;
    8. import org.slf4j.LoggerFactory;
    9. import org.springframework.beans.propertyeditors.CustomDateEditor;
    10. import org.springframework.http.HttpStatus;
    11. import org.springframework.http.ResponseEntity;
    12. import org.springframework.web.bind.WebDataBinder;
    13. import org.springframework.web.bind.annotation.ControllerAdvice;
    14. import org.springframework.web.bind.annotation.ExceptionHandler;
    15. import org.springframework.web.bind.annotation.InitBinder;
    16. import org.springframework.web.bind.annotation.ModelAttribute;
    17. //@ControllerAdvice(basePackages = {"springboot.controller"}) //指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
    18. //@ControllerAdvice(basePackageClasses = {HelloController.class}) //指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。
    19. //@ControllerAdvice(assignableTypes = {HelloController.class}) //指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理
    20. //@ControllerAdvice(annotations = {HelloController.class}) //指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理。
    21. //指定特定的类生效(assignableTypes = HelloController.class)) 只对HelloController文件做异常处理
    22. //指定所在的包生效(basePackageClasses={HelloController.class})
    23. @ControllerAdvice
    24. public class GlobalExceptionHandler {
    25. private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    26. // 全局异常处理
    27. @ExceptionHandler(ArithmeticException.class)
    28. // 或者 public ResponseEntity<Object> costomException(ArithmeticException e) {
    29. public ResponseEntity<Object> costomException1(Exception e) {
    30. logger.info("被除数不能为0", e);
    31. Map<String, Object> result = new HashMap();
    32. result.put("code", 1);
    33. result.put("msg", "被除数不能为0");
    34. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    35. }
    36. @ExceptionHandler(ArrayIndexOutOfBoundsException.class)
    37. // 或者 public ResponseEntity<Object> costomException(ArrayIndexOutOfBoundsException e) {
    38. public ResponseEntity<Object> costomException2(Exception e) {
    39. logger.info("数组索引越界异常", e);
    40. Map<String, Object> result = new HashMap();
    41. result.put("code", 1);
    42. result.put("msg", "数组索引超出异常");
    43. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    44. }
    45. /**
    46. * @Description: 没有指定的异常走这里
    47. */
    48. @ExceptionHandler
    49. public ResponseEntity<Object> costomException(Exception e) {
    50. logger.info("未知错误", e);
    51. Map<String, Object> result = new HashMap();
    52. result.put("code", 1);
    53. result.put("msg", "未知错误");
    54. return new ResponseEntity<>(result, HttpStatus.BAD_REQUEST);
    55. }
    56. // 全局数据绑定
    57. @ModelAttribute(name = "initData")
    58. public Map<String,Object> mydata() {
    59. HashMap<String, Object> map = new HashMap<>();
    60. map.put("age", 99);
    61. map.put("gender", "男");
    62. return map;
    63. }
    64. // 全局数据预处理
    65. @InitBinder
    66. public void InitBinder(WebDataBinder binder) {
    67. //前端传入的时间格式必须是"yyyy-MM-dd"效果!
    68. DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    69. CustomDateEditor dateEditor = new CustomDateEditor(df, true);
    70. binder.registerCustomEditor(Date.class, dateEditor);
    71. }
    72. }

    HelloController。 

    1. package springboot.controller;
    2. import java.text.DateFormat;
    3. import java.text.SimpleDateFormat;
    4. import java.util.Date;
    5. import org.springframework.beans.factory.annotation.Autowired;
    6. import org.springframework.beans.propertyeditors.CustomDateEditor;
    7. import org.springframework.boot.context.properties.EnableConfigurationProperties;
    8. import org.springframework.stereotype.Controller;
    9. import org.springframework.ui.Model;
    10. import org.springframework.ui.ModelMap;
    11. import org.springframework.web.bind.WebDataBinder;
    12. import org.springframework.web.bind.annotation.RequestMapping;
    13. import org.springframework.web.bind.annotation.ResponseBody;
    14. import org.springframework.web.bind.annotation.RestController;
    15. @RestController
    16. @RequestMapping("/hello")
    17. public class HelloController {
    18. @RequestMapping("/hello1")
    19. public String hello1(Date date) { // http://localhost:8080/hello/hello1?date=2022-05-16
    20. System.out.println(date); // Mon May 16 00:00:00 CST 2022
    21. System.out.println(1/0);
    22. return "Hello Spring Boot!";
    23. }
    24. @RequestMapping("/hello2")
    25. public String hello2(Date date) {
    26. System.out.println(date);
    27. int[] aa = {2,34};
    28. System.out.println(aa[3]);
    29. return "Hello Spring Boot!";
    30. }
    31. @RequestMapping("/hello3")
    32. public String hello3(ModelMap param) {
    33. System.out.println(param); // {initData={gender=男, age=99}}
    34. return "Hello Spring Boot!";
    35. }
    36. }

  • 相关阅读:
    【OpenGL】OpenGL Examples
    【获取cookie的真实到期时间】
    Kotlin 中 apply、let、also、run的区别
    uniapp 搜索内容关键字高亮
    非零基础自学Java (老师:韩顺平) 第7章 面向对象编程(基础部分) 7.1 类与对象
    【深入浅出Spring6】第二期——依赖注入
    Windows安装mysql详细步骤(通俗易懂,简单上手)
    自然语言处理学习笔记(八)———— 准确率
    基于springboot实现滴答拍摄影项目【项目源码+论文说明】计算机毕业设计
    2022-11-30 mysql-innodb-ibd文件读取工具
  • 原文地址:https://blog.csdn.net/yiguang_820/article/details/125423217