SpringBoot-自定义错误页面以及自定义异常的处理
1、自定义错误页面默认读取的静态资源位置:
默认读取的静态资源位置:classpath:/META-INF/resources/","classpath:/resources/","classpath:/static/","classpath:/public/"
写一个controller,代码如下:
package com.boot.exception.demo.bootex.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PageController {
@GetMapping("/e500")
public String e500(){
throw new RuntimeException("runtime-exception");
}
}
启动项目运行的结果如下:
当输入一个不存在的路径的话会报404
上面显示的结果是springBoot项目自带给提供的样式。
而当你启动一个springBoot项目的时候,它会有一个默认的错误路径
比如当出现错误的时候,想要给做一个友好的提示的话:
首先看一个类:ResourceProperties,这个类里面定义了一个静态资源路径的classpath,默认的只能读取下面的classpath里的路径的。但是也可以通过配置项的方式去改变这些的路径,但是这样的配置一般在开发中是不怎么会去改变的。
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"};
一般的错误页面会分两种:
2、非模板的:
一般非模板的时候把错误页面放到resources下的public文件夹下的:public是一个静态的资源路径,相当于这个路径不会作为访问的一部分。意思是说它直接会从classpath:/public/下面去找,找的时候会把/public/给你加上。因为在springMVC中的映射的/error。所以在public下新建个error的目录,有了它才能够映射下面的处理。
2.1、在error目录下建两个页面,404,500:
2.2、再次重启下项目访问下:
这就是自定义的错误页面,不需要去做任何的配置,它已经做到了这个效果了。
3、模板的:
模板的错误页面默认在resources下的templates文件下的,一样在templates目录下有一个error的文件夹,一样去映射。参看官网看的时候可以看到如果是500的错误,如果是freemarker模板的话:文件的名字可以为5xx.ftl来映射。如果是404的错误的话可以定义文件夹的名字为4xx.ftl来映射。
3.1、现在引入一个thymeleaf的静态模板的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
3.2、在templates/error目录下新建两个thymeleaf的文件:4xx.html,5xx.html:
加入了模板之后,再次运行下项目:
首先它会从静态资源里面去找,如果没有找到再去模板里面去找,这时把public/error改为public/erro1,然后再重新启动下项目访问下:
这时如果在templates目录下有一个明确的文件的时候比如404.html的话,这时如果路径不存在的话会映射到404.html的页面。
然后启动项目访问下:这时找的文件是/templates/error/404.html的文件了。
上面的就是简单的自定义的错误页面,一旦出现错误的话,会从上面的路径去找这些页面的。tomcat定制的时候也可以定制错误页面的。
抛出问题:那么如何去定制如果报404的话就会往404的页面去跳呢?比如说报404或者500的话可以去找这样的错误页面,但是如果想要去定制业务的异常该怎么办呢?
在spring中有一个注解:@ExceptionHandler:用来把这个方法交给异常的框架去处理它。代码如下:
@ExceptionHandler
public String exPage(Exception ex){
return "/error/404.html";
}
这就是不管出现404的错误也好,还是出现500的错误也好,统统会交给这个exPage的方法来处理:测试一波:
我们可以通过上面的方式来去定义它,一般情况下404或者是500,我们有的时候不一定会跳转到这些页面,会有自己的异常处理的页面。比如在做项目的时候:会有对应的业务异常的处理:
1、比如建个BizException的类,代码如下:
package com.boot.exception.demo.bootex.exception;
/**
* 自定义的业务异常
*/
public class BizException extends RuntimeException {
public BizException() {
super();
}
public BizException(String message) {
super(message);
}
public BizException(String message, Throwable cause) {
super(message, cause);
}
public BizException(Throwable cause) {
super(cause);
}
protected BizException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
2、比如在添加的时候会出现错误了,代码如下:
@GetMapping("/add")
public String add(){
throw new BizException("添加出现异常");
}
3、然后在/templates/error下新建一个biz.html的文件:
在项目开发中一般的出现404异常或者500的异常的话会交给全局的异常来处理,业务异常的话会交给业务异常来处理。在spring4的时候出现了一个注解:@ControllerAdvice。全局处理的异常的注解,代码如下:
package com.boot.exception.demo.bootex.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler
public String e404(){
return "error/404.html";
}
@ExceptionHandler
public String e500(){
return "error/500.html";
}
}
然后运行下:这时会报错,但是在springmvc中是不会报错的,在boot中会报错
异常的错误信息:叫做一个状态的异常,没有找到指定的异常解析器。一般的服务器的内部异常是RuntimeException,报404的错误一般是Exception,更改的代码如下:
package com.boot.exception.demo.bootex.exception;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public String e404(){
return "error/404.html";
}
@ExceptionHandler(RuntimeException.class)
public String e500(){
return "error/500.html";
}
}
而在pageController做的局部的业务异常,更改的代码如下:
package com.boot.exception.demo.bootex.controller;
import com.boot.exception.demo.bootex.exception.BizException;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PageController {
@GetMapping("/e500")
public String e500(){
throw new RuntimeException("runtime-exception");
}
@ExceptionHandler(BizException.class)
public String exPage(Exception ex){
return "/error/biz.html";
}
@GetMapping("/add")
public String add(){
throw new BizException("添加出现异常");
}
}
测试下:
也可以在方法指定具体的状态码:这里可以指定各种状态的异常就比较细化了。
总结,这时异常处理的思路就清晰了。限制业务异常只能处理自己的异常,只能在本模块里处理自己的异常,而其他的异常统统的交给全局异常来处理。上面的就是自定义的异常和自定义处理的页面的思路,一般的业务异常会继承RuntimeException,系统的系统会继承Exception,框架的构建的异常可能会继承Exception,但是很多的时候抛出的时候是Exception,但是捕获的时候是自定义的异常。