做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)); } }
测试结果: