Spring Boot中Web应用的统一异常处理

做web项目时,请求处理过程中难免发生错误。在springboot中提供了一个默认的映射:/error,当处理中抛出异常之后,会转到请求中处理,并该请求有一个全局的错误页面用来展示异常内容。

如下面一个controller 是一个不存在的URL,直接抛出异常,代码如下:

@RequestMapping("/hello")
public String hello() throws Exception {
    throw new Exception("发生错误");
}

此时,可以看到显示以下springboot提供默认映射的error报错页面:



在网上学习统一异常处理,把代码整理做份笔记。


一、返回code数据处理


application.yml

server:
  port: 8080

demo:
  name: Candy
  age: 18
  content: "content:${demo.name},age:${demo.age}"

spring:
  profiles:
    active: prod
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/dbdemo?useUnicode=true&characterEncoding=utf-8&useSSL=false
    username: root
    password: 12345
  jpa:
    hibernate:
      ddl-auto: none
    show-sql: true

Result.java

/**
 * http 请求返回的最外层对象
 * @param <T>
 */
public class Result<T> {

    private Integer code;   // 错误码
    private String msg; // 提示信息
    private T data;     // 具体内容

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

ResultUtil.java

public class ResultUtil {

    public static Result success(Object object) {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("请求成功");
        result.setData(object);
        return result;
    }

    public static Result success() {
        return success(null);
    }

    public static Result error(Integer code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

}

Gilr.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;

@Entity
public class Gril {

    @Id
    @GeneratedValue
    private Integer id;

    @NotEmpty(message = "用户名不能为空")
    private String name;

    public Integer getId(Integer id) {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

GrilDemoPepository.java

import com.wyt.demo.Gril;
import org.springframework.data.jpa.repository.JpaRepository;

public interface GrilDemoRepository extends JpaRepository<Gril, Integer> {
}

GrilController.java

@RestController
public class GrilController {

    @Autowired
    private GrilDemoRepository grilDemoRepository;

    //添加女生
    @PostMapping(value = "/grils")
    public Result<Gril> grilAdd(@Valid Gril gril, BindingResult bindingResult) {

        if (bindingResult.hasErrors()) {
            //这个是把gril里面的这个id必传返回给前端
            return ResultUtil.error(1, bindingResult.getFieldError().getDefaultMessage());
        }  gril.setName(gril.getName());return ResultUtil.success(grilDemoRepository.save(gril)); }}


最后,我们使用postman工具测试,输入:http://127.0.0.1:8081/grils


我们给他传个值:




二、统一异常处理

以下面一个ji实例作为参考,从数据库中根据ID查询学生信息,要求学生的年龄在14——20岁之间。小于14岁,提示“你可能在上初中”;大于20岁,提示“你可能在上大学”;。

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>

   <groupId>com.wyt</groupId>
   <artifactId>demo</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <packaging>jar</packaging>

   <name>demo</name>
   <description>Demo project for Spring Boot</description>

   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.0.1.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>

   <repositories><!-- 代码库 -->
      <repository>
         <id>maven-ali</id>
         <url>http://maven.aliyun.com/nexus/content/groups/public//</url>
         <releases>
            <enabled>true</enabled>
         </releases>
         <snapshots>
            <enabled>true</enabled>
            <updatePolicy>always</updatePolicy>
            <checksumPolicy>fail</checksumPolicy>
         </snapshots>
      </repository>
   </repositories>

   <dependencies>
      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-data-jpa</artifactId>
      </dependency>

      <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-aop</artifactId>
      </dependency>

   </dependencies>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>


</project>


目录结构:


Result.java

/**
 * http 请求返回的最外层对象
 * @param <T>
 */
public class Result<T> {

    private Integer code;   // 错误码
    private String msg; // 提示信息
    private T data;     // 具体内容

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg(){
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

Student.java

@Entity
public class Student {

    @Id
    @GeneratedValue
    private Integer id;

    @NotEmpty(message = "用户名不能为空")
    private String name;

    private Integer age;

    public Integer getId(Integer id) {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public Integer getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

ResultEnum.java

public enum ResultEnum {

    UNKONW_ERROR(-1, "未知错误"),
    SUCCESS(0, "成功"),
    PRIMARY_SCHOOL(100, "年龄小于14岁,可能正在上中学"),
    UNIVERSITY(101, "年龄大于20岁,可能正在上大学");

    private Integer code;
    private String msg;

    ResultEnum( Integer code, String msg){
        this.code = code;
        this.msg = msg;
    }

    public Integer getCode(){
        return  this.code;
    }

    public String getMsg(){
        return this.msg;
    }
}

ResultUtil.java

public class ResultUtil {

    public static Result success(Object object) {
        Result result = new Result();
        result.setCode(0);
        result.setMsg("请求成功");
        result.setData(object);
        return result;
    }

    public static Result success() {
        return success(null);
    }

    public static Result error(Integer code, String msg) {
        Result result = new Result();
        result.setCode(code);
        result.setMsg(msg);
        return result;
    }

}

StudentException.java

public class StudentException extends RuntimeException {

    private Integer code;

    public StudentException(ResultEnum resultEnum){
        super(resultEnum.getMsg());
        this.code = resultEnum.getCode();
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public Integer getCode() {
        return code;
    }

}

ExceptionHandle.java

/**
 * 1、通过@ControllerAdvice注解可以将对于控制器的全局配置放在同一个位置。
 * 2、注解了@Controller的类的方法可以使用@ExceptionHandler@InitBinder@ModelAttribute注解到方法上。
 * 3@ControllerAdvice注解将作用在所有注解了@RequestMapping的控制器的方法上。
 * 4@ExceptionHandler:用于全局处理控制器里的异常。
 * 5@InitBinder:用来设置WebDataBinder,用于自动绑定前台请求参数到Model中。
 * 6@ModelAttribute:本来作用是绑定键值对到Model中,此处让全局的@RequestMapping都能获得在此处设置的键值对
 *
 * @author wyt
 * @date 2018-04-22
 */
@ControllerAdvice
public class ExceptionHandle {

    private final static Logger logger =  LoggerFactory.getLogger(ExceptionHandle.class);

    //应用到所有@RequestMapping注解的方法,在其抛出Exception异常时执行  
    //定义全局异常处理,value属性可以过滤拦截条件,此处拦截所有的Exception
    @ExceptionHandler(value = Exception.class)
    @ResponseBody
    public Result handler(Exception e){
        if( e instanceof StudentException){
            StudentException studentException = (StudentException) e;
            return ResultUtil.error( studentException.getCode(), studentException.getMessage());
        }else {
            logger.info("[系统异常] {}",e);
            return ResultUtil.error( -1, "未知错误");
        }
    }
}

StudengRepository.java

public interface StudentRepository extends JpaRepository<Student, Integer>{
}

StudentService.java

@Service
public class StudentService {
    @Autowired
    private StudentRepository studentRepository;

    /**
     * 根据ID查询符合条件的学生
     * @param id
     * @throws Exception
     */
    public Student getStudentById(Integer id) throws Exception{
        Student student = studentRepository.findById(id).orElse(null);
        Integer age = student.getAge();
        if(age < 14){
            throw new StudentException(ResultEnum.PRIMARY_SCHOOL);
        }else if(age > 20){
            throw new StudentException(ResultEnum.UNIVERSITY);
        }

        //进行下面逻辑操作
        return student;
    }
}

StudentController.java

@RestController
public class StudentController {
    @Autowired
    private StudentService studentService;

    /**
     * 根据ID查询学生
     */
    @GetMapping(value = "/student/getage/{id}")
    public Result getStudentById(@PathVariable("id") Integer id) throws Exception{
        return ResultUtil.success(studentService.getStudentById(id));
    }

}

测试结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值