本篇内容主要讲解“springBoot2.X配置全局捕获异常的方法”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“springBoot2.X配置全局捕获异常的方法”吧!
先来看一段代码:当传入的id是0的时候,就会报异常。
@RestController
public class HelloController {
@GetMapping("/getUser")
public String getUser(int id) {
int j = 1 / id;
return "SUCCESS" + j;
}
}
访问时:
我们知道这个页面要是给用户看到,用户可能不知道这是什么。
@GetMapping("/getUser")
public String getUser(int id) {
int j;
try {
j = 1 / id;
} catch (Exception e) {
return "系统异常";
}
return "SUCCESS" + j;
}
这种方法当然可以,但是当我们有很多方法时,需要在每个方法上都加上。
哎,太鸡肋了吧。
那么都没有全局的拦截处理呢?
当然了
/**
* @Author 刘翊扬
* @Date 2020/9/30 11:39 下午
* @Version 1.0
*/
@ControllerAdvice(basePackages = "com.yiyang.myfirstspringdemo.controller")
public class GlobalExceptionHandler {
@ExceptionHandler(RuntimeException.class)
@ResponseBody
public Map<String,Object> errorResult() {
Map<String, Object> map = new HashMap<>();
map.put("errorCode", "500");
map.put("errorMsg", "全局捕获异常");
return map;
}
}
@ExceptionHandler
表示拦截异常
@ControllerAdvice
是 controller 的一个辅助类,最常用的就是作为全局异常处理的切面类
@ControllerAdvice
可以指定扫描范围
注意:下面还需要在启动类上加上,否则诶呦效果
package com.yiyang.myfirstspringdemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication(scanBasePackages = {"com.yiyang.myfirstspringdemo.error", "com.yiyang.myfirstspringdemo.controller"})
public class MyFirstSpringDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MyFirstSpringDemoApplication.class, args);
}
}
在启动类上,将扫描包范围controller和全局异常处理类,加上去。
这样当我们在访问的时候,出现的异常提示信息就是我们在全局异常处理中设置的返回值。
在web项目中,异常堆栈信息是非常敏感的。因此,需要一个全局的异常处理,捕获异常,给客户端以友好的错误信息提示。基于 Spring boot 很容易实现全局异常处理。
<!-- Spring Boot 启动父依赖 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!-- Spring Boot Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
package com.yb.demo.common.handler;
import com.yb.demo.common.enums.CodeEnum;
import com.yb.demo.common.exception.BizException;
import com.yb.demo.pojo.response.Result;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.BindException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.validation.ValidationException;
import java.util.StringJoiner;
/**
* 全局异常处理
* <p>
* 规范:流程跳转尽量避免使用抛 BizException 来做控制。
*
* @author daoshenzzg@163.com
* @date 2019-09-06 18:02
*/
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
* 处理自定义异常
*
* @param ex
* @return
*/
@ExceptionHandler(BizException.class)
public Result handleBizException(BizException ex) {
Result result = Result.renderErr(ex.getCode());
if (StringUtils.isNotBlank(ex.getRemark())) {
result.withRemark(ex.getRemark());
}
return result;
}
/**
* 参数绑定错误
*
* @param ex
* @return
*/
@ExceptionHandler(BindException.class)
public Result handleBindException(BindException ex) {
StringJoiner sj = new StringJoiner(";");
ex.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getDefaultMessage()));
return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(sj.toString());
}
/**
* 参数校验错误
*
* @param ex
* @return
*/
@ExceptionHandler(ValidationException.class)
public Result handleValidationException(ValidationException ex) {
return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(ex.getCause().getMessage());
}
/**
* 字段校验不通过异常
*
* @param ex
* @return
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
StringJoiner sj = new StringJoiner(";");
ex.getBindingResult().getFieldErrors().forEach(x -> sj.add(x.getDefaultMessage()));
return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(sj.toString());
}
/**
* Controller参数绑定错误
*
* @param ex
* @return
*/
@ExceptionHandler(MissingServletRequestParameterException.class)
public Result handleMissingServletRequestParameterException(MissingServletRequestParameterException ex) {
return Result.renderErr(CodeEnum.REQUEST_ERR).withRemark(ex.getMessage());
}
/**
* 处理方法不支持异常
*
* @param ex
* @return
*/
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
public Result handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException ex) {
return Result.renderErr(CodeEnum.METHOD_NOT_ALLOWED);
}
/**
* 其他未知异常
*
* @param ex
* @return
*/
@ExceptionHandler(value = Exception.class)
public Result handleException(Exception ex) {
log.error(ex.getMessage(), ex);
return Result.renderErr(CodeEnum.SERVER_ERR);
}
}
自定义异常
在实际web开发过程中,往往会遇到在某些场景下需要终止当前流程,直接返回。那么,通过抛出自定义异常,并在全局异常中捕获,用以友好的提示客户端。
/**
* 业务异常跳转。
*
* @author daoshenzzg@163.com
* @date 2019-09-09 14:57
*/
@Data
public class BizException extends RuntimeException {
private static final long serialVersionUID = 1L;
private CodeEnum code;
private String remark;
public BizException(CodeEnum code) {
super(code.getMessage());
this.code = code;
}
public BizException withRemark(String remark) {
this.remark = remark;
return this;
}
}
使用方式如下:
/**
* 添加学生
*
* @param student
* @return
*/
public Student1DO addStudent(Student1DO student) {
if (StringUtils.isNotBlank(student.getStudName())) {
// 举例扔个业务异常,实际使用过程中,应该避免扔异常
throw new BizException(CodeEnum.REQUEST_ERR).withRemark("studName不能为空");
}
student1Mapper.insert(student);
return student;
}
返回效果如下:
{
"code": -400,
"msg": "请求错误(studName不能为空)",
"data": {},
"ttl": 0
}
根据阿里巴巴规范,流程控制还是不要通过抛异常的方式。在正常开发过程中,应避免使用这种方式。
【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。
定义实体类,加上validation相关注解
package com.yb.demo.pojo.model.db1;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import javax.validation.constraints.Min;
import javax.validation.constraints.Size;
/**
* @author daoshenzzg@163.com
* @date 2019-08-05 17:58
*/
@Data
@TableName("student")
public class Student1DO {
private Long id;
@Size(max = 8, message = "studName长度不能超过8")
private String studName;
@Min(value = 12, message = "年龄不能低于12岁")
private Integer studAge;
private String studSex;
@TableField(fill = FieldFill.INSERT)
private Integer createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private Integer updateTime;
}
在Controller 方法上加上 @Validated 注解
@PostMapping("/student/add")
public Result addStudent(@Validated @RequestBody Student1DO student) {
student = studentService.addStudent(student);
return Result.renderOk(student);
}
实际效果如下:
{
"code": -400,
"msg": "请求错误(年龄不能低于12岁)",
"data": {},
"ttl": 0
}
具体代码见:https://github.com/daoshenzzg/springboot2.x-example
到此,相信大家对“springBoot2.X配置全局捕获异常的方法”有了更深的了解,不妨来实际操作一番吧!这里是亿速云网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
亿速云「云服务器」,即开即用、新一代英特尔至强铂金CPU、三副本存储NVMe SSD云盘,价格低至29元/月。点击查看>>
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。