SpringBoot(12)使用控制器通知
作者:互联网
控制器通知
在编写代码时,需要对异常进行处理。进行异常处理的普通的代码是try-catch结构。但在开发业务时,只想关注业务正常的代码,对于catch语句中的捕获异常,希望交给异常捕获来处理,不单独在每个方法中编写。这样不仅可以减少冗余代码,还可以减少因忘记写catch而岀现错误的概率。Spring正好提供了一个非常方便的异常处理方案——控制器通知@ControllerAdvice或 @RestcontrollerAdvice),它将所有控制器作为一个切面,利用切面技术来实现。通过基于@ControllerAdvice或@RestControllerAdvice的注解可以对异常进行全局统一处理,默认对所有的Controller有效。如果要限定生效范围,则可以使用ContrallerAdvice支持的限定范围方式。
- 按注解:@ControllerAdvice(annotations = RestController.class)
- 按包名:@ControllerAdvice("org.example.controller")
- 按类型:@ControllerAdvice(assignableTypes = {Controllerinterface.class, Abstract- Controller.class})
这是ControllerAdvice进行统一异常处理的优点,它能够细粒度地控制该异常处理器针对娜些 Controller、包或类型有效。
可以利用这一特性在一个系统实现多个异常处理器,然后Controller可以有选择地决定使用哪 个,使得异常处理更加灵活,降低侵入性。
异常处理类会包含以下一个或多个方法。
- @lnitBinder:对表单数据进行绑定,用于定义控制器参数绑定规则。如转换规则、格式化 等。可以通过这个注解的方法得到WebDataBinder对象,它在参数转换之前被执行。
- @ModelAttribute:在控制器方法被执行前,对所有Controller的Model添加属性进行操作。
- @ExceptionHandler:定义控制器发生异常后的操作,可以拦截所有控制器发生的异常。
- @ControllerAdvice:统一异常处理,通过 @ExceptionHandler(value = class) 来指定捕获的异常。"@ControllerAdvice + @ExceptionHandle"可以处理除“404” 以外的运行异常。
实例:自定义错误处理控制器
package com.itheima.controller;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("${server.error.path:${error.path:/error}}")
public class TestErrorController implements ErrorController {
@Override
public String getErrorPath() {
return null;
}
@RequestMapping
public Map<String,Object> handleError(){
Map<String,Object> map = new HashMap<String,Object>();
map.put("code",404);
map.put("msg","不存在");
return map;
}
@RequestMapping("ok")
@ResponseBody
public Map<String,Object> noError(){
Map<String,Object> map = new HashMap<String,Object>();
map.put("code",200);
map.put("msg","正常");
return map;
}
}
启动项目,访问一个不存在的网址,则返回下方信息:
{"msg":"不存在",”code":404}
访问正确定义的映射"http://localhost:8080/error/ok",则返回下方正确信息:
{"msg":"正常","code":200}
实例:自定义业务异常类
(1)自定义异常类
自定义异常类需要继承Exception (异常)类。这里继承RuntimeException,
package com.itheima.exception;
public class BusinessException extends RuntimeException {
private Integer code;
public BusinessException(int code, String msg) {
super(msg);
this.code = code;
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
(2)自定义全局捕获异常
package com.itheima.handler;
import com.itheima.exception.BusinessException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class CustomerBusinessExceptionHandler {
@ResponseBody
@ExceptionHandler(BusinessException.class)
public Map<String,Object> businessExceptionHandler(BusinessException e){
Map<String,Object> map = new HashMap<String,Object>();
map.put("code",e.getCode());
map.put("message",e.getMessage());
return map;
}
}
@ControllerAdvice:
对于@ControllerAdvice,我们比较熟知的用法是结合@ExceptionHandler用于全局异常的处理,但其作用不止于此。ControllerAdvice拆开来就是Controller Advice,关于Advice,在Spring的AOP中,是用来封装一个切面所有属性的,包括切入点和需要织入的切面逻辑。这里ControllerAdvice也可以这么理解,其抽象级别应该是用于对Controller进行切面环绕的,而具体的业务织入方式则是通过结合其他的注解来实现的。@ControllerAdvice是在类上声明的注解,其用法主要有三点:
1.结合方法型注解@ExceptionHandler,用于捕获Controller中抛出的指定类型的异常,从而达到不同类型的异常区别处理的目的。
2.结合方法型注解@InitBinder,用于request中自定义参数解析方式进行注册,从而达到自定义指定格式参数的目的。
3.结合方法型注解@ModelAttribute,表示其注解的方法将会在目标Controller方法执行之前执行。
从上面的讲解可以看出,@ControllerAdvice的用法基本是将其声明在某个bean上,然后在该bean的方法上使用其他的注解来指定不同的织入逻辑。不过这里@ControllerAdvice并不是使用AOP的方式来织入业务逻辑的,而是Spring内置对其各个逻辑的织入方式进行了内置支持。
@Component用于声明@ExceptionHandler 、 @InitBinder或@ModelAttribute方法的类的特化,以便在多个@Controller类之间共享。
使用@ControllerAdvice注释的类可以显式声明为 Spring bean 或通过类路径扫描自动检测。所有此类 bean 都基于Ordered语义或@Order / @Priority声明进行排序, Ordered语义优先于@Order / @Priority声明。然后在运行时按该顺序应用@ControllerAdvice bean。但是请注意,实现PriorityOrdered的@ControllerAdvice bean 的优先级不高于实现Ordered的@ControllerAdvice bean。此外, Ordered不适用于作用域@ControllerAdvice bean — 例如,如果此类 bean 已配置为请求作用域或会话作用域 bean。为了处理异常, @ExceptionHandler将在第一个通知中选择一个匹配的异常处理程序方法。对于模型属性和数据绑定初始化,@ @ModelAttribute和@InitBinder方法将遵循@ControllerAdvice顺序。
注意:对于@ExceptionHandler方法,在特定通知 bean 的处理程序方法中,根异常匹配将优于仅匹配当前异常的原因。但是,高优先级通知上的原因匹配仍将优先于低优先级通知 bean 上的任何匹配(无论是根级别还是原因级别)。因此,请在具有相应顺序的优先通知 bean 上声明您的主根异常映射。
默认情况下, @ControllerAdvice ControllerAdvice 中的方法全局应用于所有控制器。使用诸如annotations 、 basePackageClasses和basePackages (或其别名value )之类的选择器来定义目标控制器的更窄子集。如果声明了多个选择器,则应用布尔OR逻辑,这意味着所选控制器应至少匹配一个选择器。请注意,选择器检查是在运行时执行的,因此添加许多选择器可能会对性能产生负面影响并增加复杂性。
@ExceptionHandler:
用于处理特定处理程序类和/或处理程序方法中的异常的注释。
使用此注释注释的处理程序方法可以具有非常灵活的签名。它们可能具有以下类型的参数,按任意顺序:异常参数:声明为一般异常或更具体的异常。如果注释本身没有通过其value()缩小异常类型,这也可用作映射提示。请求和/或响应对象(通常来自 Servlet API)。您可以选择任何特定的请求/响应类型,例如javax.servlet.ServletRequest / javax.servlet.http.HttpServletRequest 。
会话对象:通常是javax.servlet.http.HttpSession 。这种类型的参数将强制存在相应的会话。因此,这样的论点永远不会是null 。请注意,会话访问可能不是线程安全的,尤其是在 Servlet 环境中:如果允许多个请求同时访问会话,请考虑将"synchronizeOnSession"标志切换为“true”。
org.springframework.web.context.request.WebRequest或org.springframework.web.context.request.NativeWebRequest 。允许通用请求参数访问以及请求/会话属性访问,而不与本机 Servlet API 绑定。
java.util.Locale用于当前请求的语言环境(由可用的最具体的语言环境解析器确定,即在 Servlet 环境中配置的org.springframework.web.servlet.LocaleResolver )。
java.io.InputStream / java.io.Reader用于访问请求的内容。这将是 Servlet API 公开的原始 InputStream/Reader。
java.io.OutputStream / java.io.Writer用于生成响应的内容。这将是 Servlet API 公开的原始 OutputStream/Writer。
org.springframework.ui.Model作为从处理程序方法返回模型映射的替代方法。请注意,提供的模型未预先填充常规模型属性,因此始终为空,以便为特定于异常的视图准备模型。
处理程序方法支持以下返回类型:
一个ModelAndView对象(来自 Servlet MVC)。
一个org.springframework.ui.Model对象,视图名称通过org.springframework.web.servlet.RequestToViewNameTranslator隐式确定。
用于公开模型的java.util.Map对象,视图名称通过org.springframework.web.servlet.RequestToViewNameTranslator隐式确定。
一个org.springframework.web.servlet.View对象。
一个String值,它被解释为视图名称。
@ResponseBody注释方法(仅限 Servlet)来设置响应内容。返回值将使用消息转换器转换为响应流。
用于设置响应标头和内容的HttpEntity<?>或ResponseEntity<?>对象(仅限 Servlet)。 ResponseEntity 正文将使用消息转换器进行转换并写入响应流。
void如果方法本身处理响应(通过直接编写响应内容,为此目的声明javax.servlet.ServletResponse / javax.servlet.http.HttpServletResponse类型的参数)或者视图名称应该通过隐式确定org.springframework.web.servlet.RequestToViewNameTranslator (不在处理程序方法签名中声明响应参数)。
您可以将ExceptionHandler注释与@ResponseStatus结合使用以获取特定的 HTTP 错误状态。
(3)测试自定义异常类
创建控制器,以抛BusinessException的自定义异常
package com.itheima.controller;
import com.itheima.exception.BusinessException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@RequestMapping("BusinessException")
public String testBusinessExceptionStatus(@RequestParam("i") int i){
if (i == 0){
throw new BusinessException(600,"这是自定义异常");
}
return "success";
}
}
启动项目,访问 "http://localhost:8080/BusinessException?i=0" 测试异常处理情况,则抛出下方错误信息:
{"code”:600,"message”:"这是自定义异常"}
标签:web,控制器,12,ControllerAdvice,SpringBoot,springframework,import,org,异常 来源: https://www.cnblogs.com/liwenruo/p/16487913.html