springBoot2.X配置全局捕获异常的操作

网友投稿 254 2022-12-24

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;

}

这种方法当然可以,但是当我们有很多方法时,需要在每个方法上都加上。

哎,太鸡肋了吧。

那么都没有全局的拦截处理呢?

当然了

方法二:通过@ControllerAdvice注解配置

/**

* @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 errorResult() {

Map 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和全局异常处理类,加上去。

这样当我们在访问的时候,出现的异常提示信息就是我们在全局异常处理中设置的返回值。

springboot2.x 全局异常处理的正确方式

在web项目中,异常堆栈信息是非常敏感的。因此,需要一个全局的异常处理,捕获异常,给客户端以友好的错误信息提示。基于 Spring boot 很容易实现全局异常处理。

相关jar依赖引入

org.springframework.boot

spring-boot-starter-parent

2.1.6.RELEASE

UTF-8

UTF-8

1.8

org.springframework.boot

spring-boot-starter-web

全局异常控制器

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.http://util.StringJoiner;

/**

* 全局异常处理

*

* 规范:流程跳转尽量避免使用抛 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开发过程中,往往会遇到在某些场景下需要终止当前流程,直接返回。那么,通过抛出自定义异常,并在全局异常中捕获,用以友好的提示客户端。

/http://**

* 业务异常跳转。

*

* @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

}

根据阿里巴巴规范,流程控制还是不要通过抛异常的方式。在正常开发过程中,应避免使用这种方式。

【强制】异常不要用来做流程控制,条件控制,因为异常的处理效率比条件分支低。

使用 Spring validation 完成数据后端校验

定义实体类,加上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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Springboot+Redis实现API接口限流的示例代码
下一篇:Java多线程:生产者与消费者案例
相关文章

 发表评论

暂时没有评论,来抢沙发吧~