前言
如今web項目的接口大都是 RESTful 的,響應體中包含了一些接口執行的信息,比如返回的數據(data)、響應碼(code)、是否成功(success)和響應描述(message)。每個接口都需要封裝成這種格式,這樣每次都需要留意。
下面來介紹一種方法,是 Spring 的 web 模塊提供的功能。
統一響應體
pom依賴了web模塊和lombok
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.6</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
首先創建枚舉類ResultMessage,定義一些響應碼
public enum ResultMessage {
/** 成功 */
SUCCESS(200, "Success"),
/** 請求錯誤 */
BAD_REQUEST(400, "Bad request"),
/** 未經授權 */
UNAUTHORIZED(401, "Unauthorized"),
/** 目標不存在 */
NOT_FOUND(404, "Not found"),
/** 服務內部錯誤 */
SERVER_ERROR(500, "Server Error");
private int code;
private String message;
ResultMessage(int code, String message) {
this.code = code;
this.message = message;
}
public int code() {
return code;
}
public String message() {
return message;
}
}
創建 Result 類,代表接口的響應體
@Getter
public class Result<T> {
/**
* 狀態碼
*/
private int code = -1;
/**
* 提示信息
*/
private String message;
/**
* 響應數據
*/
private T data;
private Result(int code, String message, T data) {
this.code = code;
this.message = message;
this.data = data;
}
public static <T> Result<T> data(T data) {
return new Result<>(ResultMessage.SUCCESS.code(), ResultMessage.SUCCESS.message(), data);
}
public static <T> Result<T> err() {
return new Result<>(ResultMessage.SERVER_ERROR.code(), ResultMessage.SERVER_ERROR.message(), null);
}
public static <T> Result<T> err(String message) {
return new Result<>(ResultMessage.SERVER_ERROR.code(), message, null);
}
}
接着創建,HelloController類
@RestController
public class HelloController {
@GetMapping("/hello")
public Result<String> hello() {
return Result.data("hello");
}
}
使用postman訪問 http://localhost:8080/hello
{
"code": 200,
"message": "Success",
"data": "hello"
}
創建註解 OriginalBody,代表原始響應頭。
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface OriginalBody {
}
創建 ResultBodyAdvice 類,實現 ResponseBodyAdvice 接口,重寫兩個方法:
@ControllerAdvice
public class ResultBodyAdvice implements ResponseBodyAdvice {
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
Annotation[] methodAnnotations = methodParameter.getMethodAnnotations();
for (Annotation methodAnnotation : methodAnnotations) {
if (methodAnnotation instanceof OriginalBody) {
return false;
}
}
Annotation[] classAnnotations = methodParameter.getMethod().getDeclaringClass().getAnnotations();
for (Annotation classAnnotation : classAnnotations) {
if (classAnnotation instanceof OriginalBody) {
return false;
}
}
return true;
}
@Override
public Object beforeBodyWrite(Object result, MethodParameter methodParameter, MediaType mediaType, Class aClass, ServerHttpRequest serverHttpRequest, ServerHttpResponse response) {
if (result instanceof Result) {
return result;
}
response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
String type = mediaType.getType();
if ("text".equals(type)) {
return JSON.toJSONString(Result.data(result), SerializerFeature.PrettyFormat);
}
return Result.data(result);
}
}
在 HelloController 新增兩個方法,用來測試
@GetMapping("/hello2")
public String hello2() {
return "hello2";
}
@OriginalBody
@GetMapping("/hello3")
public String hello3() {
return "hello3";
}
使用Postman分別調用 hello2:
{
"code": 200,
"data": "hello2",
"message": "Success"
}
調用 hello3 :
hello3
統一異常響應體
新增一個方法,如果接口出現異常,則響應成了醬紫:
@GetMapping("/hello4")
public String hello4(@RequestParam Integer code) {
if (code != null && code.equals(1)) {
throw new RuntimeException();
}
return "hello4";
}
{
"code": 200,
"message": "Success",
"data": {
"timestamp": "2020-04-10T11:06:45.299+0000",
"status": 500,
"error": "Internal Server Error",
"message": "No message available",
"path": "/hello4"
}
}
這種方法使用 @ExceptionHandler 註解來解決。
創建
@ControllerAdvice
@Slf4j
@ResponseBody
public class ExceptionHandlerAdvice {
@ExceptionHandler(Exception.class)
public Result<Object> handleException(Exception e){
log.error(e.getMessage(), e);
return Result.err();
}
}
請求結果:
{
"code": 500,
"message": "Server Error",
"data": null
}