Spring Boot自定义全局异常

标签: Springboot 分类: Java 创建时间:2020-03-03 08:28:33 更新时间:2024-11-12 12:53:37

前言

关于如何处理异常,我觉得这篇文章:Spring Boot统一异常处理最佳实践 说的挺好,有两个原则:

  • 不使用随意返回各种数据类型, 要统一返回值规范.
  • 不在业务代码中捕获任何异常, 全部交由 @ControllerAdvice 来处理.

1.自定义全局异常

这里以定义一个404错误异常为例,默认的springboot ,如果没有相应的路由,会抛出一个错误页,比如上面的图示。但是我想要返回一个自定义的错误页,或者是返回一个json字符串怎么办呢?如果想返回自定义的错误页,其实在resources文件夹下新建一个error.html就可以了,就可以覆盖默认的错误页了。如果想返回一个字符串,需要新建一个GlobalExceptionHandler类,加上 @RestControllerAdvice 注解,然后在配置文件中增加

1
2
3
4
5
6
7
8
9
10
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

## 或者
spring:
web:
resources:
add-mappings: false
mvc:
throw-exception-if-no-handler-found: true

GlobalExceptionHandler类中的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.proheng.gis.boot;

import org.omg.CORBA.portable.ResponseHandler;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.NoHandlerFoundException;

@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* @author zlc
* @date 2019-09-12
* @param e 异常
* @description 处理所有不可知的异常
*/
@ExceptionHandler({Exception.class}) //申明捕获那个异常类
public String globalExceptionHandler(Exception e) {
return "服务器错误";
}

//路由不存在的异常
@ExceptionHandler({NoHandlerFoundException.class})
@ResponseBody
public String noHandlerFoundException(Exception e) {
return "路由不存在";
}
}

2.继承ErrorController

如果不想写覆盖配置文件,那么就要继承ErrorController接口,并实现error和getErrorPath方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.phkj.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.servlet.error.ErrorController;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Controller
@RestControllerAdvice
public class GlobalExceptionHandler implements ErrorController {
private final Logger logger= LoggerFactory.getLogger(GlobalExceptionHandler.class);
/**
* @author zlc
* @date 2019-09-12
* @param e 异常
* @description 处理所有不可知的异常
*/
@ExceptionHandler({Exception.class}) //申明捕获那个异常类
// @ResponseStatus(HttpStatus)
@ResponseBody
public String globalExceptionHandler(Exception e) {
logger.error("全局错误",e);
return "服务器错误";
}
// 路由不存在的异常
@ExceptionHandler({NoHandlerFoundException.class})
@ResponseBody
@ResponseStatus(HttpStatus.NOT_FOUND)
public String noHandlerFoundException(Exception e) {
logger.error("路由不存在",e);
return "路由不存在";
}

@Override
public String getErrorPath() {
return "/error";
}

@RequestMapping(value = {"/error"})
@ResponseBody
public Object error(HttpServletRequest request) {
Map<String, Object> body = new HashMap<>();
body.put("error", "not found");
body.put("code", "404");
return body;
}
}

3.servlet中的404错误

我遇到的一个问题是,假如我在application.properties文件中配置了context-path

1
#server.servlet.context-path=/phkj

那么无论我怎么努力使用上面的方法,我都无法捕获到404错误。应用程序已经在运行了,但是总是进入不到springboot的处理流程中,直接就返回了404错误,这个问题估计是servlet的问题暂时还没有解决。

4.自定义全局异常后,无法进行视图映射

问题描述

在配置文件中配置了:spring.resources.add-mappings=false 之后,虽然能正常的拦截全局的异常了,但是在resources目录下的login.html等视图,也无法返回了,总是提示: No handler found for /login.html,比如我的一个方法,想返回login登录页,就没有办法返回了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.phkj.ctrl;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/")
public class LinkCtrl {
@RequestMapping("/login2")
public String login(){
return "login";
}
}

尝试添加Thymeleaf模板引擎

(1) 添加依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

(2) 编写配置文件application.properties

1
2
3
4
5
6
spring.thymeleaf.prefix=classpath:/template/
spring.thymeleaf.check-template-location=true
spring.thymeleaf.suffix=.html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML5
spring.thymeleaf.cache=false

(3) 编写控制类

1
2
3
4
5
6
7
8
9
10
11
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/")
public class LinkCtrl {
@RequestMapping("/login2")
public String login(){
return "login";
}
}

(4) 静态资源
对于静态资源要添加相应的静态资源映射,实现WebMvcConfigurer接口并重写addResourceHandlers方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebMvcCon implements WebMvcConfigurer {

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/static/**").addResourceLocations("classpath:/META-INF/resources/", "classpath:/static","/static", "/public");
}

}

小额赞助
本人提供免费与付费咨询服务,感谢您的支持!赞助请发邮件通知,方便公布您的善意!
**光 3.01 元
Sun 3.00 元
bibichuan 3.00 元
微信公众号
广告位
诚心邀请广大金主爸爸洽谈合作
每日一省
isNaN 和 Number.isNaN 函数的区别?

1.函数 isNaN 接收参数后,会尝试将这个参数转换为数值,任何不能被转换为数值的的值都会返回 true,因此非数字值传入也会返回 true ,会影响 NaN 的判断。

2.函数 Number.isNaN 会首先判断传入参数是否为数字,如果是数字再继续判断是否为 NaN ,不会进行数据类型的转换,这种方法对于 NaN 的判断更为准确。

每日二省
为什么0.1+0.2 ! == 0.3,如何让其相等?

一个直接的解决方法就是设置一个误差范围,通常称为“机器精度”。对JavaScript来说,这个值通常为2-52,在ES6中,提供了Number.EPSILON属性,而它的值就是2-52,只要判断0.1+0.2-0.3是否小于Number.EPSILON,如果小于,就可以判断为0.1+0.2 ===0.3。

每日三省
== 操作符的强制类型转换规则?

1.首先会判断两者类型是否**相同,**相同的话就比较两者的大小。

2.类型不相同的话,就会进行类型转换。

3.会先判断是否在对比 null 和 undefined,是的话就会返回 true。

4.判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number。

5.判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断。

6.判断其中一方是否为 object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断。

每日英语
Happiness is time precipitation, smile is the lonely sad.
幸福是年华的沉淀,微笑是寂寞的悲伤。