拦截异常
在Spring Boot中,我们可以将异常统一放在全局处理类来处理,创建一个全局异常处理类需要用到@ControllerAdvice和@ExceptionHandler注解。
@ControllerAdvice类似一个增强版的@Controller,用于标注类,表示该类声明了整个项目的全局资源
@ExceptionHandler类似catch语句,标注一个方法,用于处理异常。而这个方法可以有返回值,类似@Controller的返回值
@ExceptionHandler可以传入一个参数,为异常类的Class对象
接下来举个例子:
创建一个exception包,在这个包下面写入一个异常处理类:
package com.example.c0101.exceptionimport org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody@ControllerAdvice
class GlobalExceptionHandle {@ExceptionHandler(NullPointerException::class)@ResponseBodyfun handler(): String{return "参数不能为空"}}
这表示,当遇到空指针异常时,向前端发送消息“参数不能为空”
接下来创建一个controller包。在这个包下面写一个控制器类:
package com.example.c0101.controllerimport org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController@RestController
class TestController {@RequestMapping("/index")fun index(name: String): String{return "您的用户名是$name"}}
在/index的URI下,用户需要传入一个name参数,如果用户没有传入,则会触发空指针异常,调用我们之前写的异常处理类
我们使用postman测试一下:
可以看到,如果我们不传入name参数,则会调用异常处理类,并返回“参数不能为空”
获取异常日志
我们可以使用slf4j打印异常日志:
log.error("参数为空", e)
这里面,log.error可以接受两个参数,第一个是提示字符串,第二个是异常对象
修改异常处理类如下:
package com.example.c0101.exceptionimport org.slf4j.LoggerFactory
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody@ControllerAdvice
class GlobalExceptionHandle {companion object{val log = LoggerFactory.getLogger(GlobalExceptionHandle::class.java)}@ExceptionHandler(NullPointerException::class)@ResponseBodyfun handler(e: NullPointerException): String{log.error("参数为空", e)return "参数不能为空"}}
这样我们就可以在出现异常时,打印异常日志了。用postman不传入参数,发现控制台输出:
说明我们成功的在日志中输出了错误信息
修改异常状态下的响应码
我们可以通过@ResponseStatus注解设置响应码,如:
@ResponseStatus(HttpStatus.BAD_REQUEST)
修改异常处理类,使其能够在出现空指针异常时,返回400(Bad Request)状态码:
package com.example.c0101.exceptionimport org.slf4j.LoggerFactory
import org.springframework.http.HttpStatus
import org.springframework.web.bind.annotation.ControllerAdvice
import org.springframework.web.bind.annotation.ExceptionHandler
import org.springframework.web.bind.annotation.ResponseBody
import org.springframework.web.bind.annotation.ResponseStatus@ControllerAdvice
class GlobalExceptionHandle {companion object{val log = LoggerFactory.getLogger(GlobalExceptionHandle::class.java)}@ExceptionHandler(NullPointerException::class)@ResponseBody@ResponseStatus(HttpStatus.BAD_REQUEST)fun handler(e: NullPointerException): String{log.error("参数为空", e)return "参数不能为空"}}
用postman不加参数,测试一下:
可以看到,服务器最终返回了400状态码
只拦截某个包下发生的异常
我们可以通过@ControllerAdvice的默认属性或basePackages属性只拦截某个包下发生的异常:
@ControllerAdvice("com.example.c0101.controller")
@ControllerAdvice(basePackages = ["com.example.c0101.controller"])
只拦截被某个注解标注的类发生的异常
我们可以通过@ControllerAdvice的annotations属性只拦截某个注解标注的类发生的异常:
@ControllerAdvice(annotations = [RestController::class])
拦截自定义异常
我们可以在exception包下自定义异常,并使用拦截普通异常的方法拦截自定义异常:
package com.example.c0101.exceptionclass MyException(msg: String) : Exception(msg)
在异常处理类里设置要拦截的异常:
@ExceptionHandler(MyException::class)
@ResponseBody
fun handler(e: MyException): String{log.error("自定义异常", e)return "出现自定义异常"
}
这样就可以拦截自定义异常了