springboot 详解RestControllerAdvice(ControllerAdvice)拦截异常并统一处理
简介
@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 {}; }
作为特化@Component,允许通过类路径扫描自动检测实现类。
它通常用于定义@ExceptionHandler, @InitBinder 和 @ModelAttribute 适用于所有@RequestMapping方法的方法。
annotations(),basePackageClasses(), basePackages()或它的别名value() 可以被指定,以限定控制器,以协助的特定子集。当应用多个选择器时,应用OR逻辑 - 意味着所选的控制器应匹配至少一个选择器。
默认行为(即,如果没有任何选择器使用),带@ControllerAdvice注释的类将协助所有已知的控制器。
背景
当我们定义了一个自定义返回参数格式时,希望得到统一的返回,如果在运行时发现了异常,也希望将异常统一返回。如
期望返回格式:
{ "msg": "success", "code": 500, "success": false, "message": "id不能为空!" }
抛出异常格式:
{ "timestamp": "2019-04-01T07:17:38.619+0000", "status": 500, "error": "Internal Server Error", "message": "id不能为空!", "path": "/api/myInfo" }
如何让我们的异常得到期望的返回格式,这里就需要用到了@ControllerAdvice或者RestControllerAdvice(如果全部异常处理返回json,那么可以使用 @RestControllerAdvice 代替 @ControllerAdvice ,这样在方法上就可以不需要添加 @ResponseBody。)。下面看一个demo。
准备工作
1.创建一个UnionExceptionHandler类,定义全局异常捕捉处理。
package com.honghh.bootfirst.exception; import com.honghh.bootfirst.utils.R; import lombok.extern.slf4j.Slf4j; import org.springframework.ui.Model; import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RestControllerAdvice; /** * ClassName: UnionExceptionHandler * Description: * * @author honghh * @date 2019/04/01 10:03 */ @Slf4j @RestControllerAdvice public class UnionExceptionHandler { /** * 应用到所有@RequestMapping注解方法,在其执行之前初始化数据绑定器 * * @param binder */ @InitBinder public void initBinder(WebDataBinder binder) { log.info("binder.getFieldDefaultPrefix {}",binder.getFieldDefaultPrefix()); log.info("binder.getFieldMarkerPrefix {}",binder.getFieldMarkerPrefix()); } /** * 把值绑定到Model中,使全局@RequestMapping可以获取到该值 * @param model */ @ModelAttribute public void addAttributes(Model model) { model.addAttribute("author", "harry"); } /** * Description : 全局异常捕捉处理 * Group : * * @author honghh * @date 2019/4/1 0001 10:34 * @param ex * @return */ @ExceptionHandler(RRException.class) public R apiExceptionHandler(RRException ex) { log.error("ApiException 异常抛出:{}", ex); return R.fail(ex); }
/**
* Description : 针对某个异常捕捉处理
* Group :
*
* @author honghh
* @date 2019/4/1 0001 10:34
* @param ex
* @return
*/
@ExceptionHandler(SSException.class)
public R apiExceptionHandler(SSException ex) {
log.error("ApiException 异常抛出:{}", ex);
return R.fail(ex);
}
}
启动应用后,被 @ExceptionHandler、@InitBinder、@ModelAttribute 注解的方法,都会作用在 @RequestMapping 注解的方法上。
@ModelAttribute:在Model上设置的值,对于所有被 @RequestMapping 注解的方法中,都可以通过 ModelMap 获取
2.创建一个RRException 自定义异常。
package com.honghh.bootfirst.exception;
/** * 自定义异常 * * @author harry * @date 2018-07-20 16:30 */ public class RRException extends RuntimeException { private static final long serialVersionUID = 1L; private String msg; private int code = 500; public RRException(String msg) { super(msg); this.msg = msg; } public RRException(String msg, Throwable e) { super(msg, e); this.msg = msg; } public RRException(String msg, int code) { super(msg); this.msg = msg; this.code = code; } public RRException(String msg, int code, Throwable e) { super(msg, e); this.msg = msg; this.code = code; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public int getCode() { return code; } public void setCode(int code) { this.code = code; } }
3.写一个RequestMapping方法,抛出异常进行测试。[spring boot 默认情况下会映射到 /error 进行异常处理,但是提示并不十分友好,下面自定义异常处理,提供友好展示。
@GetMapping("myInfo") public R myInfo(@RequestParam Integer id) { if (id == null) { throw new RRException("id不能为空!"); } MyInfo myInfo = myInfoService.getById(id); return R.ok().put("myInfo", myInfo); } //启动应用,访问:http://127.0.0.1:8080/api/myInfo?id= ,正常显示以下json内容,证明自定义异常已经成功被拦截。 { "msg": "success", "code": 500, "success": false, "message": "id不能为空!" }
代码获取
https://gitee.com/honghh/boot-demo.git
参考文献
https://docs.spring.io/spring-framework/docs/5.0.0.M1/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html
————————————————
版权声明:本文为CSDN博主「AH_HH」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_35098526/article/details/88949425