Browse Source

spring-boot-demo-exception-handler 完成

pull/1/head
Yangkai.Shen 6 years ago
parent
commit
c9b0e94374
14 changed files with 783 additions and 0 deletions
  1. +25
    -0
      spring-boot-demo-exception-handler/.gitignore
  2. +271
    -0
      spring-boot-demo-exception-handler/README.md
  3. +60
    -0
      spring-boot-demo-exception-handler/pom.xml
  4. +25
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/SpringBootDemoExceptionHandlerApplication.java
  5. +42
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/constant/Status.java
  6. +38
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/controller/TestController.java
  7. +37
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/BaseException.java
  8. +29
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/JsonException.java
  9. +29
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/PageException.java
  10. +57
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/handler/DemoExceptionHandler.java
  11. +132
    -0
      spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/model/ApiResponse.java
  12. +11
    -0
      spring-boot-demo-exception-handler/src/main/resources/application.yml
  13. +11
    -0
      spring-boot-demo-exception-handler/src/main/resources/templates/error.html
  14. +16
    -0
      spring-boot-demo-exception-handler/src/test/java/com/xkcoding/exception/handler/SpringBootDemoExceptionHandlerApplicationTests.java

+ 25
- 0
spring-boot-demo-exception-handler/.gitignore View File

@@ -0,0 +1,25 @@
/target/
!.mvn/wrapper/maven-wrapper.jar

### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache

### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr

### NetBeans ###
/nbproject/private/
/build/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/

+ 271
- 0
spring-boot-demo-exception-handler/README.md View File

@@ -0,0 +1,271 @@
# spring-boot-demo-exception-handler

> 此 demo 演示了如何在Spring Boot中进行统一的异常处理,包括了两种方式的处理:第一种对常见API形式的接口进行异常处理,统一封装返回格式;第二种是对模板页面请求的异常处理,统一处理错误页面。

## pom.xml

```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.xkcoding</groupId>
<artifactId>spring-boot-demo-exception-handler</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-exception-handler</name>
<description>Demo project for Spring Boot</description>

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

<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-exception-handler</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>
```

## ApiResponse.java

> 统一的API格式返回封装,里面涉及到的 `BaseException` 和`Status` 这两个类,具体代码见 demo。

```java
/**
* <p>
* 通用的 API 接口封装
* </p>
*
* @package: com.xkcoding.exception.handler.model
* @description: 通用的 API 接口封装
* @author: yangkai.shen
* @date: Created in 2018/10/2 8:57 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
public class ApiResponse {
/**
* 状态码
*/
private Integer code;

/**
* 返回内容
*/
private String message;

/**
* 返回数据
*/
private Object data;

/**
* 无参构造函数
*/
private ApiResponse() {

}

/**
* 全参构造函数
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
*/
private ApiResponse(Integer code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}

/**
* 构造一个自定义的API返回
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse of(Integer code, String message, Object data) {
return new ApiResponse(code, message, data);
}

/**
* 构造一个成功且带数据的API返回
*
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofSuccess(Object data) {
return ofStatus(Status.OK, data);
}

/**
* 构造一个成功且自定义消息的API返回
*
* @param message 返回内容
* @return ApiResponse
*/
public static ApiResponse ofMessage(String message) {
return of(Status.OK.getCode(), message, null);
}

/**
* 构造一个有状态的API返回
*
* @param status 状态 {@link Status}
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status) {
return ofStatus(status, null);
}

/**
* 构造一个有状态且带数据的API返回
*
* @param status 状态 {@link Status}
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status, Object data) {
return of(status.getCode(), status.getMessage(), data);
}

/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param data 返回数据
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t, Object data) {
return of(t.getCode(), t.getMessage(), data);
}

/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t) {
return ofException(t, null);
}
}
```

## DemoExceptionHandler.java

```java
/**
* <p>
* 统一异常处理
* </p>
*
* @package: com.xkcoding.exception.handler.handler
* @description: 统一异常处理
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:26 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@ControllerAdvice
@Slf4j
public class DemoExceptionHandler {
private static final String DEFAULT_ERROR_VIEW = "error";

/**
* 统一 json 异常处理
*
* @param exception JsonException
* @return 统一返回 json 格式
*/
@ExceptionHandler(value = JsonException.class)
@ResponseBody
public ApiResponse jsonErrorHandler(JsonException exception) {
log.error("【JsonException】:{}", exception.getMessage());
return ApiResponse.ofException(exception);
}

/**
* 统一 页面 异常处理
*
* @param exception PageException
* @return 统一跳转到异常页面
*/
@ExceptionHandler(value = PageException.class)
public ModelAndView pageErrorHandler(PageException exception) {
log.error("【DemoPageException】:{}", exception.getMessage());
ModelAndView view = new ModelAndView();
view.addObject("message", exception.getMessage());
view.setViewName(DEFAULT_ERROR_VIEW);
return view;
}
}
```

## error.html

> 位于 `src/main/resources/template` 目录下

```html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8"/>
<title>统一页面异常处理</title>
</head>
<body>
<h1>统一页面异常处理</h1>
<div th:text="${message}"></div>
</body>
</html>
```


+ 60
- 0
spring-boot-demo-exception-handler/pom.xml View File

@@ -0,0 +1,60 @@
<?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.xkcoding</groupId>
<artifactId>spring-boot-demo-exception-handler</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-demo-exception-handler</name>
<description>Demo project for Spring Boot</description>

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

<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.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>

<build>
<finalName>spring-boot-demo-exception-handler</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

+ 25
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/SpringBootDemoExceptionHandlerApplication.java View File

@@ -0,0 +1,25 @@
package com.xkcoding.exception.handler;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* <p>
* 启动类
* </p>
*
* @package: com.xkcoding.exception.handler
* @description: 启动类
* @author: yangkai.shen
* @date: Created in 2018/10/2 8:49 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@SpringBootApplication
public class SpringBootDemoExceptionHandlerApplication {

public static void main(String[] args) {
SpringApplication.run(SpringBootDemoExceptionHandlerApplication.class, args);
}
}

+ 42
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/constant/Status.java View File

@@ -0,0 +1,42 @@
package com.xkcoding.exception.handler.constant;

import lombok.Getter;

/**
* <p>
* 状态码封装
* </p>
*
* @package: com.xkcoding.exception.handler.constant
* @description: 状态码封装
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:02 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Getter
public enum Status {
/**
* 操作成功
*/
OK(200, "操作成功"),
/**
* 未知异常
*/
UNKNOWN_ERROR(500, "服务器出错啦");
/**
* 状态码
*/
private Integer code;
/**
* 内容
*/
private String message;

Status(Integer code, String message) {
this.code = code;
this.message = message;
}
}

+ 38
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/controller/TestController.java View File

@@ -0,0 +1,38 @@
package com.xkcoding.exception.handler.controller;

import com.xkcoding.exception.handler.constant.Status;
import com.xkcoding.exception.handler.exception.JsonException;
import com.xkcoding.exception.handler.exception.PageException;
import com.xkcoding.exception.handler.model.ApiResponse;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
* <p>
* 测试Controller
* </p>
*
* @package: com.xkcoding.exception.handler.controller
* @description: 测试Controller
* @author: yangkai.shen
* @date: Created in 2018/10/2 8:49 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Controller
public class TestController {

@GetMapping("/json")
@ResponseBody
public ApiResponse jsonException() {
throw new JsonException(Status.UNKNOWN_ERROR);
}

@GetMapping("/page")
public ModelAndView pageException() {
throw new PageException(Status.UNKNOWN_ERROR);
}
}

+ 37
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/BaseException.java View File

@@ -0,0 +1,37 @@
package com.xkcoding.exception.handler.exception;

import com.xkcoding.exception.handler.constant.Status;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
* <p>
* 异常基类
* </p>
*
* @package: com.xkcoding.exception.handler.exception
* @description: 异常基类
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:31 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
@EqualsAndHashCode(callSuper = true)
public class BaseException extends RuntimeException {
private Integer code;
private String message;

public BaseException(Status status) {
super(status.getMessage());
this.code = status.getCode();
this.message = status.getMessage();
}

public BaseException(Integer code, String message) {
super(message);
this.code = code;
this.message = message;
}
}

+ 29
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/JsonException.java View File

@@ -0,0 +1,29 @@
package com.xkcoding.exception.handler.exception;

import com.xkcoding.exception.handler.constant.Status;
import lombok.Getter;

/**
* <p>
* JSON异常
* </p>
*
* @package: com.xkcoding.exception.handler.exception
* @description: JSON异常
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:18 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Getter
public class JsonException extends BaseException {

public JsonException(Status status) {
super(status);
}

public JsonException(Integer code, String message) {
super(code, message);
}
}

+ 29
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/exception/PageException.java View File

@@ -0,0 +1,29 @@
package com.xkcoding.exception.handler.exception;

import com.xkcoding.exception.handler.constant.Status;
import lombok.Getter;

/**
* <p>
* 页面异常
* </p>
*
* @package: com.xkcoding.exception.handler.exception
* @description: 页面异常
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:18 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Getter
public class PageException extends BaseException {

public PageException(Status status) {
super(status);
}

public PageException(Integer code, String message) {
super(code, message);
}
}

+ 57
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/handler/DemoExceptionHandler.java View File

@@ -0,0 +1,57 @@
package com.xkcoding.exception.handler.handler;

import com.xkcoding.exception.handler.exception.JsonException;
import com.xkcoding.exception.handler.exception.PageException;
import com.xkcoding.exception.handler.model.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

/**
* <p>
* 统一异常处理
* </p>
*
* @package: com.xkcoding.exception.handler.handler
* @description: 统一异常处理
* @author: yangkai.shen
* @date: Created in 2018/10/2 9:26 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@ControllerAdvice
@Slf4j
public class DemoExceptionHandler {
private static final String DEFAULT_ERROR_VIEW = "error";

/**
* 统一 json 异常处理
*
* @param exception JsonException
* @return 统一返回 json 格式
*/
@ExceptionHandler(value = JsonException.class)
@ResponseBody
public ApiResponse jsonErrorHandler(JsonException exception) {
log.error("【JsonException】:{}", exception.getMessage());
return ApiResponse.ofException(exception);
}

/**
* 统一 页面 异常处理
*
* @param exception PageException
* @return 统一跳转到异常页面
*/
@ExceptionHandler(value = PageException.class)
public ModelAndView pageErrorHandler(PageException exception) {
log.error("【DemoPageException】:{}", exception.getMessage());
ModelAndView view = new ModelAndView();
view.addObject("message", exception.getMessage());
view.setViewName(DEFAULT_ERROR_VIEW);
return view;
}
}

+ 132
- 0
spring-boot-demo-exception-handler/src/main/java/com/xkcoding/exception/handler/model/ApiResponse.java View File

@@ -0,0 +1,132 @@
package com.xkcoding.exception.handler.model;

import com.xkcoding.exception.handler.constant.Status;
import com.xkcoding.exception.handler.exception.BaseException;
import lombok.Data;

/**
* <p>
* 通用的 API 接口封装
* </p>
*
* @package: com.xkcoding.exception.handler.model
* @description: 通用的 API 接口封装
* @author: yangkai.shen
* @date: Created in 2018/10/2 8:57 PM
* @copyright: Copyright (c) 2018
* @version: V1.0
* @modified: yangkai.shen
*/
@Data
public class ApiResponse {
/**
* 状态码
*/
private Integer code;

/**
* 返回内容
*/
private String message;

/**
* 返回数据
*/
private Object data;

/**
* 无参构造函数
*/
private ApiResponse() {

}

/**
* 全参构造函数
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
*/
private ApiResponse(Integer code, String message, Object data) {
this.code = code;
this.message = message;
this.data = data;
}

/**
* 构造一个自定义的API返回
*
* @param code 状态码
* @param message 返回内容
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse of(Integer code, String message, Object data) {
return new ApiResponse(code, message, data);
}

/**
* 构造一个成功且带数据的API返回
*
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofSuccess(Object data) {
return ofStatus(Status.OK, data);
}

/**
* 构造一个成功且自定义消息的API返回
*
* @param message 返回内容
* @return ApiResponse
*/
public static ApiResponse ofMessage(String message) {
return of(Status.OK.getCode(), message, null);
}

/**
* 构造一个有状态的API返回
*
* @param status 状态 {@link Status}
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status) {
return ofStatus(status, null);
}

/**
* 构造一个有状态且带数据的API返回
*
* @param status 状态 {@link Status}
* @param data 返回数据
* @return ApiResponse
*/
public static ApiResponse ofStatus(Status status, Object data) {
return of(status.getCode(), status.getMessage(), data);
}

/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param data 返回数据
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t, Object data) {
return of(t.getCode(), t.getMessage(), data);
}

/**
* 构造一个异常且带数据的API返回
*
* @param t 异常
* @param <T> {@link BaseException} 的子类
* @return ApiResponse
*/
public static <T extends BaseException> ApiResponse ofException(T t) {
return ofException(t, null);
}
}

+ 11
- 0
spring-boot-demo-exception-handler/src/main/resources/application.yml View File

@@ -0,0 +1,11 @@
server:
port: 8080
servlet:
context-path: /demo
spring:
thymeleaf:
cache: false
mode: HTML
encoding: UTF-8
servlet:
content-type: text/html

+ 11
- 0
spring-boot-demo-exception-handler/src/main/resources/templates/error.html View File

@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head lang="en">
<meta charset="UTF-8"/>
<title>统一页面异常处理</title>
</head>
<body>
<h1>统一页面异常处理</h1>
<div th:text="${message}"></div>
</body>
</html>

+ 16
- 0
spring-boot-demo-exception-handler/src/test/java/com/xkcoding/exception/handler/SpringBootDemoExceptionHandlerApplicationTests.java View File

@@ -0,0 +1,16 @@
package com.xkcoding.exception.handler;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringBootDemoExceptionHandlerApplicationTests {

@Test
public void contextLoads() {
}

}

Loading…
Cancel
Save