springboot(12):@ControllerAdvice和@RestControllerAdvice注解使用

目录

  • @ControllerAdvice注解
    • 全局异常处理
    • 全局数据绑定
    • 全局数据预处理
  • @RestControllerAdvice注解
  • @ControllerAdvice属性

上一节讲到springboot异常处理时,使用到了@ControllerAdvice
下面详细讲解讲解下@ControllerAdvice用法,以及Restful风格的@RestControllerAdvice注解使用。
上节文章:Spring Boot(11):异常处理

@ControllerAdvice注解

@ControllerAdvice就是@Controller 的增强版。@ControllerAdvice主要有三个用途:全局异常处理、全局数据绑定、全局数据预处理。一般搭配@ExceptionHandler、@ModelAttribute以及@InitBinder使用。

全局异常处理

结合@ExceptionHandler,用来指明异常的处理类型。

参考上节内容。如下,创一个自己的全局异常处理类,代码如下:

/**
 * 全局异常处理类
 */
@ControllerAdvice
public class GlobalController {

    /**
     * 该方法返回ModelAndView:目的是为了可以让我们封装视图和错误信息
     * @param e 参数 Exception e:会将产生异常对象注入到方法中
     * @return
     */
    //拦截的异常可以写Exception
    @ExceptionHandler(value = {java.lang.ArithmeticException.class})
    public ModelAndView arithmeticExceptionHandler(Exception e){
        ModelAndView mv = new ModelAndView();
        mv.addObject("errorMsg",e+"controllerAdvice");
        mv.setViewName("error");
        return mv;
    }
}

在该类中,可以定义多个方法,不同的方法处理不同的异常,,也可以直接向上面代码一样,在一个方法中处理所有的异常。

全局数据绑定

结合@ModelAttribute注解使用。

全局数据绑定功能可以用来做一些初始化的数据操作,我们可以将一些公共的数据定义在添
加了 @ControllerAdvice 注解的类中,这样,在每一个 Controller 的接口中,就都能
够访问导致这些数据。

首先定义全局数据,如下:

@ControllerAdvice
public class MyGlobalExceptionHandler {
	@ModelAttribute(name = "mydata")
	public Map<String,Object> mydata() {
		HashMap<String, Object> map = new HashMap<>();
		map.put("age", 20);
		map.put("gender", "男");
		return map; 
	} 
}

使用 @ModelAttribute 注解标记该方法的返回数据是一个全局数据,默认情况下,这个全局数据的 key 就是返回的变量名,value 就是方法返回值,也可以通过@ModelAttribute 注解的 name 属性去重新指定 key。

然后,个早Controller 的接口中,可以获取到这里定义的数据:

@RestController
public class HelloController {
	@GetMapping("/hello")
	public String hello(Model model) {
		Map<String, Object> map = model.asMap();
		System.out.println(map);
		return "hello controller advice"; 
	} 
}

全局数据预处理

结合@InitBinder使用,实现请求参数预处理。

例如有两个实体类 Book和 Author,代码如下:

@Data
@AllArgsConstructor
@NoArgsConstructor
@Component
@ToString
public class Book {
    private String name;
    private String author;
    @JsonIgnore//一般标记在属性或者方法上,返回的json数据即不包含该属性
    private Float price;
    @JsonFormat(pattern = "yyyy-MM-dd")
    private Date publicationDate;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Author {
    private String name;
    private int age;
}

此时,定义一个数据添加接口,如下:

@PostMapping("/book")
public void addBook(Book book, Author author) {
	System.out.println(book);
	System.out.println(author);
}

这个时候,添加操作就会有问题,因为两个实体类都有一个 name 属性,从前端传递时 ,无法区分。此时,通过 @ControllerAdvice 的全局数据预处理可以解决这个问题。
解决步骤如下:

1.给接口中的变量取别名

@PostMapping("/book")
public void addBook(@ModelAttribute("b") Book book,
					@ModelAttribute("a") Author author) 
{
	System.out.println(book);
	System.out.println(author);
}

2.进行请求数据预处理

@ControllerAdvice
public class GlobalConfig1 {
    @InitBinder("b")
    public void init(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("b.");
    }

    @InitBinder("a")
    public void init2(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("a.");
    }
}

在 GlobalConfig类中创建两个方法,第一个@InitBinder(“b”)表示该方法是处理@ModelAttribute(“b”)对应的参数的,第二个@InitBinder(“a”)表示该方法是处理@ModelAttribute(“a”)对应的参数的。

@InitBinder(“b”) 注解表示该方法用来处理和 Book 和相关的参数,在方法中,给参数添加一个 b 前缀,即请求参数要有 b 前缀。

3.发送请求

请求发送时,通过给不同对象的参数添加不同的前缀,可以实现参数的区分,如下:
http:/localhost:8080/book?b.name=三国演义&b.author=罗贯中&a.name=曹雪芹&a.age=48,即可成功地区分出name属性。

@RestControllerAdvice注解

@RestControllerAdvice是一个组合注解,由@ControllerAdvice、@ResponseBody组成,用于Restful风格的controller。

@RestControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。

@RestControllerAdvice用法上与@ControllerAdvice没什么不同,也可与@ExceptionHandler,@InitBinder和@ModelAttribute注解结合使用。

下面有个简单示例:

@ControllerAdvice  
public class GlobalController{  
     
    // 全局数据绑定
    @ModelAttribute 
    public void addUser(Model model) {   
        model.addAttribute("msg", "全局数据");  
    }    
    // 全局数据预处理 
    @InitBinder("user")
    public void initBinder(WebDataBinder binder) {
    }    
    
    // 全局异常处理
    @ExceptionHandler(Exception.class)    
    public String handleException(Exception e) {    
        return "error";
    }    
}  

@ControllerAdvice属性

@ControllerAdvice源码如下:

package org.springframework.web.bind.annotation;

import java.lang.annotation.Annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface ControllerAdvice {
    @AliasFor("basePackages")
    String[] value() default {};

    @AliasFor("value")
    String[] basePackages() default {};

    Class<?>[] basePackageClasses() default {};

    Class<?>[] assignableTypes() default {};

    Class<? extends Annotation>[] annotations() default {};
}

可以看到,有几个属性,其中:

1.basePackages

指定一个或多个包,这些包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。

@RestControllerAdvice(basePackages={"com.example.spring"})
@Slf4j
public class ExceptionHandlerAdvice {    
    @ExceptionHandler(Exception.class)    
    public String handleException(Exception e) {    
        return "error";
    }   
} 

2.basePackageClasses

是 basePackages 的一种变形,指定一个或多个 Controller 类,这些类所属的包及其子包下的所有 Controller 都被该 @ControllerAdvice 管理。

@RestControllerAdvice(basePackageClasses={TestController.class})
@Slf4j
public class ExceptionHandlerAdvice {
	@ExceptionHandler(Exception.class)    
    public String handleException(Exception e) {    
        return "error";
    } 
}  

3.assignableTypes

指定一个或多个 Controller 类,这些类被该 @ControllerAdvice 管理。

4.annotations

指定一个或多个注解,被这些注解所标记的 Controller 会被该 @ControllerAdvice 管理。

@ControllerAdvice(annotations = {TestAnnotation.class})
@Slf4j
public class ExceptionHandlerAdvice {
	@ExceptionHandler(Exception.class)    
    public String handleException(Exception e) {    
        return "error";
    } 
} 

参考:https://blog.csdn.net/user2025/article/details/105458842
https://blog.csdn.net/qq_43581790/article/details/123871439

你可能感兴趣的:(#,spring,boot,java,spring)