前言
在springboot项目中,一般我们访问不存在的资源或内部服务报错,会报下面的异常页面,这是springboot为我们定制的异常页面,
定义一个项目,加入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
定义一个Controller类,
package com.zhihao.miao.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class UserController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/user/home")
public String index(){
logger.info("user home");
return "user home";
}
@GetMapping("/user/help")
public String help(){
logger.info("user help");
throw new IllegalArgumentException("args is empty");
}
}
启动类启动:
package com.zhihao.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
访问不存在的资源
访问内部资源报错的资源
如何去掉springboot默认的异常处理逻辑
查看org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration类,
发现org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration类就是springboot默认的异常处理逻辑,我们在springboot应用容器中去除这个类即可去掉springboot默认的异常处理逻辑。
修改启动类,排除ErrorMvcAutoConfiguration类
package com.zhihao.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
@SpringBootApplication(exclude =ErrorMvcAutoConfiguration.class)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
再次访问上面的资源就出现经典的tomcat异常
如何定制自己的异常页面
使用ErrorPageRegistrar方法
写一个类,实现ErrorPageRegistrar接口,然后实现registerErrorPages方法,在该方法里面,添加具体的错误处理逻辑(类似web.xml里面配置错误处理方式),这一种也是全局的异常处理。
定义一个MyErrorPageRegistrar实现ErrorPageRegistrar接口
package com.zhihao.miao.bean;
import org.springframework.boot.web.servlet.ErrorPage;
import org.springframework.boot.web.servlet.ErrorPageRegistrar;
import org.springframework.boot.web.servlet.ErrorPageRegistry;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
@Component
public class MyErrorPageRegistrar implements ErrorPageRegistrar {
@Override
public void registerErrorPages(ErrorPageRegistry registry) {
//具体的错误码错误异常页面
ErrorPage e404 = new ErrorPage(HttpStatus.NOT_FOUND,"/404.html");
ErrorPage e500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/500.html");
//指定具体异常的错误定制页面
ErrorPage argspage = new ErrorPage(IllegalArgumentException.class,"/argsException.html");
registry.addErrorPages(e404,e500,argspage);
}
}
定义的3个错误页面,
404.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>404 not found</h1>
</body>
</html>
500.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>500 server error</h1>
</body>
</html>
argsException.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>args is empty</h1>
</body>
</html>
启动类,可以不指定排除默认的springboot异常处理,因为新定义的全局异常处理springboot的就不执行了
package com.zhihao.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
//@SpringBootApplication(exclude =ErrorMvcAutoConfiguration.class)
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
再去访问之前的资源
资源不存在
发现具体异常定义的异常处理优于状态码异常处理。
使用@ExceptionHandler注解
新建一个项目,定义一个Controller进行测试,
package com.zhihao.miao.controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.FileNotFoundException;
@RestController
public class BookController {
//对异常进行处理,这种方式只能处理当前类中的异常,也就是局部异常处理
@ExceptionHandler(value=FileNotFoundException.class)
public String error(){
return "file is not found exception";
}
@ExceptionHandler(value=Exception.class)
public String excep(Exception e){
return "not found exception: "+e.getMessage();
}
@GetMapping("/book/error1")
public String error1() throws FileNotFoundException {
throw new FileNotFoundException("book.txt not found");
}
@GetMapping("/book/error2")
public String error2() throws ClassNotFoundException {
throw new ClassNotFoundException("Book class not found");
}
}
启动类启动:
package com.zhihao.miao;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.ErrorMvcAutoConfiguration;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class);
}
}
访问http://localhost:8080/book/error1,抛出FileNotFoundException异常,被当前类的@ExceptionHandler注解给捕获到进行异常逻辑处理。定义在其他Controller类中的此种异常不会被其捕获,所以此种异常处理也是局部异常处理。
使用@ControllerAdvice注解定义全局异常
定义GlobalExceptionHandler标记注解@ControllerAdvice
package com.zhihao.miao.bean;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 可以在全局异常处理的类中进行具体的异常处理,也可以在全局异常类中进行所有异常的处理,
* @ExceptionHandler的value值不同。
*/
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ArithmeticException.class)
@ResponseBody
public String ArithmeticHandler(Exception e){
return "global error " + e.getClass().getName();
}
@ExceptionHandler(Exception.class)
@ResponseBody
public String error(Exception e){
return "global error" + e.getMessage();
}
}
定义Controller
@RestController
public class UserController {
private Logger logger = LoggerFactory.getLogger(getClass());
@GetMapping("/user/home")
public String index(){
logger.info("user home");
return "user home";
}
@GetMapping("/user/help")
public String help(){
logger.info("user help");
throw new IllegalArgumentException("args is empty");
}
}
访问http://localhost:8080/user/help
这个处理异常的方法必须要求本身的方法返回参数和@ExceptionHandler(***Exception.class)异常修饰的方法必须要一样的。
总结这种异常处理的步骤:
写一个类,需要加上@ControllerAdvice注解,然后使用@ExceptionHandler异常进行异常定位。
如果一个Controller类中定义了@ExceptionHandler注解修饰的方法,那么当前类中异常捕获优先于全局定义的异常。