Spring MVC 统一响应消息体

Spring MVC API 接口响应的消息体最好统一结构,便于前端识别和规范。

方式一

ResponseVO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class ResponseVO<T> {

private int status; // 返回状态
private String message; // 描述信息
private T data; // 数据

public ResponseVO() {}

public ResponseVO(HttpStatusEnum httpStatus) {
this.status = httpStatus.status();
this.message = httpStatus.message();
}
public ResponseVO(HttpStatusEnum httpStatus, T data) {
this.status = httpStatus.status();
this.message = httpStatus.message();
this.data = data;
}

public ResponseVO(int status, String message) {
this.status = status;
this.message = message;
}
public ResponseVO(int status, String message, T data) {
this.status = status;
this.message = message;
this.data = data;
}
public ResponseVO(T data) {
this.status = HttpStatusEnum.SUCCESS.status();
this.message = HttpStatusEnum.SUCCESS.message();
this.data = data;
}

public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}

@Override
public String toString() {
return JSONObject.toJSONString(this);
}
}

ResponseEntity

Spring Http 也提供了响应体类 ResponseEntity,在响应给前端时也可直接使用返回 ResponseEntity 对象,传入数据。

ResponseEntity 扩展自 HttpEntity,增加了 HttpStatus 状态码。可在 RestTemplate 或 @Controller 注解类中的方法中使用。

RestTemplate 的 getForEntity()exchange() 方法返回的就是 ResponseEntity 实例。如下示例

1
2
3
4
ResponseEntity<String> entity = template.getForEntity("http://example.com", String.class);
String body = entity.getBody();
MediaType contentType = entity.getHeaders().getContentType();
HttpStatus statusCode = entity.getStatusCode();

还可以在 Spring MVC 中使用,作为 @Controller 方法的返回值:

1
2
3
4
5
6
7
8
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.setLocation(location);
responseHeaders.set("MyResponseHeader", "MyValue");
return new ResponseEntity&lt;String&gt;("Hello World", responseHeaders, HttpStatus.CREATED);
}

或通过静态方法调用构建器来访问:

1
2
3
4
5
@RequestMapping("/handle")
public ResponseEntity<String> handle() {
URI location = ...;
return ResponseEntity.created(location).header("MyResponseHeader", "MyValue").body("Hello World");
}

ResponseHelper

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
public class ResponseHelper {

public final static void execption(HttpStatusEnum httpStatus) {
throw new RestException(httpStatus);
}
public final static void execption(HttpStatusEnum httpStatus, Object data) {
throw new RestException(httpStatus, data);
}

public final static void execption(int status, String message) {
throw new RestException(status, message);
}
public final static void execption(int status, String message, Object data) {
throw new RestException(status, message, data);
}

/**
* 服务端处理成功
*
* @param <T>
* @return ResponseVO
*/
public final static <T> ResponseVO<T> success(T data) {
return new ResponseVO<T>(data);
}

/**
* 服务端校验失败(请求数据语义有误)
*
* @param <T>
* @return ResponseVO
*/
public final static <T> ResponseVO<T> badRequest(T data) {
return new ResponseVO<T>(HttpStatusEnum.BAD_REQUEST, data);
}

/**
* 服务端校验失败(请求数据语义有误)
*
* @param message
* @return ResponseVO
*/
public final static <T> ResponseVO<T> badRequest(String message) {
return new ResponseVO<T>(HttpStatusEnum.BAD_REQUEST.status(), message);
}

/**
* 服务端校验数据冲突(数据重复...)
*
* @param <T>
* @return ResponseVO
*/
public final static <T> ResponseVO<T> conflict(T data) {
return new ResponseVO<T>(HttpStatusEnum.CONFLICT, data);
}

/**
* 服务端校验数据冲突(数据重复...)
*
* @param message
* @return ResponseVO
*/
public final static <T> ResponseVO<T> conflict(String message) {
return new ResponseVO<T>(HttpStatusEnum.CONFLICT.status(), message);
}

/**
* 服务端内部错误
*
* @param <T>
* @return ResponseVO
*/
public final static <T> ResponseVO<T> error(T data) {
return new ResponseVO<T>(HttpStatusEnum.INTERNAL_SERVER_ERROR, data);
}

/**
* 服务端内部错误
*
* @param message
* @return ResponseVO
*/
public final static <T> ResponseVO<T> error(String message) {
return new ResponseVO<T>(HttpStatusEnum.INTERNAL_SERVER_ERROR.status(), message);
}

/**
* 无权限
*
* @param <T>
* @return ResponseVO
*/
public final static <T> ResponseVO<T> unauthorized(T data) {
return new ResponseVO<T>(HttpStatusEnum.UNAUTHORIZED, data);
}

/**
* 无权限
*
* @param message
* @return ResponseVO
*/
public final static <T> ResponseVO<T> unauthorized(String message) {
return new ResponseVO<T>(HttpStatusEnum.UNAUTHORIZED.status(), message);
}
}

HttpStatusEnum

Http 状态码 及 Spring Http 状态码枚举

统一响应消息体

在使用时,可返回 new ResponseVO(data),也可使用 ResponseHelper 调用静态方法,传入数据。

方式二

ResponseModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
@Data
public class ResponseModel<T> {

@JsonIgnore
public static final int SUCCESS_CODE = 200;

private int code = SUCCESS_CODE;

private String message = "success";

private T result;

@JsonIgnore
public static ResponseModel<?> success() {
return new ResponseModel<>();
}

@JsonIgnore
public static ResponseModel<?> success(String message) {
return new ResponseModel<>(message);
}

@JsonIgnore
public static <T> ResponseModel<T> success(T result) {
return new ResponseModel<>(result);
}

@JsonIgnore
public static <T> ResponseModel<T> success(String message, T result) {
return new ResponseModel<>(message, result);
}

@JsonIgnore
public static ResponseModel<?> fail() {
return new ResponseModel<>(SystemErrorCode.SYS_INTERNAL_ERROR);
}

@JsonIgnore
public static ResponseModel<?> fail(ErrorCode errorCode) {
return new ResponseModel<>(errorCode.getCode(), errorCode.getMessage());
}

@JsonIgnore
public static <T> ResponseModel<T> fail(ErrorCode errorCode, T result) {
return new ResponseModel<>(errorCode, result);
}

@JsonIgnore
public static <T> ResponseModel<T> fail(T result) {
return new ResponseModel<>(SystemErrorCode.SYS_INTERNAL_ERROR, result);
}

@JsonIgnore
public static ResponseModel<?> fail(String message) {
return new ResponseModel<>(SystemErrorCode.SYS_INTERNAL_ERROR.getCode(), message);
}

public static ResponseModel<?> duplicateKey() {
return duplicateKey(SystemErrorCode.REQ_PARAM_DUPLICATE_KEY.getMessage());
}

public static ResponseModel<?> duplicateKey(String message) {
return new ResponseModel<>(SystemErrorCode.REQ_PARAM_DUPLICATE_KEY.getCode(), message);
}


public ResponseModel() {
}

public ResponseModel(T result) {
this.result = result;
}

public ResponseModel(String message, T result) {
this.message = message;
this.result = result;
}

public ResponseModel(ErrorCode errorCode) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
}

public ResponseModel(ErrorCode errorCode, T result) {
this.code = errorCode.getCode();
this.message = errorCode.getMessage();
this.result = result;
}

public ResponseModel(BusinessException ex) {
this.code = ex.getCode();
this.message = ex.getMessage();
}

public ResponseModel(String message) {
this.message = message;
}

public ResponseModel(int code, String message) {
this.code = code;
this.message = message;
}

public ResponseModel(int code, String message, T result) {
this.code = code;
this.message = message;
this.result = result;
}

@JsonIgnore
public boolean isSuccess() {
return this.code == SUCCESS_CODE;
}
}

SystemErrorCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
/**
* Copyright © 2018 深圳市巨鼎医疗设备有限公司
*/
package com.clearofchina.core.model;

/**
* 系统错误码
*
* @author Zhouych
* @date 2020年4月1日 上午10:03:51 <br/>
* @since V1.0.0
*/
public enum SystemErrorCode implements ErrorCode {

SYS_INTERNAL_ERROR(500, "系统异常"),

SYS_REQUEST_PARAM_ERROR(400, "请求参数有误"),

SYS_UNAUTHORIZED(401, "系统未授权"),

SYS_FORBIDDEN(403, "权限不足"),

SYS_UNSUPPORTED_METHOD(405, "不支持的请求方法"),

REQ_URI_NOT_FOUND(404, "请求路径不存在"),

REQ_METHOD_NOT_SUPPORT(405, "请求类型不支持"),

REQ_PARAM_DUPLICATE_KEY(406, "请求参数已存在"),

REQ_PARAM_CANT_BE_EMPTY(407, "必传参数不能为空"),

REQ_PARAM_TYPE_ERROR(408, "请求参数类型错误或必传为空"),

REQ_PARAM_LENGTH_OUT_OF_RANGE(409, "参数长度超出限制"),

REQ_MSG_NOT_READABLE(410, "请求数据不可读(为空或格式异常)"),

REQ_PARAM_ID_CANT_BE_NULL(411, "请求参数 id 不能为空"),

UPLOAD_FILE_SIZE_OUT_OF_MAX_LIMIT(412, "上传文件大小超出最大限制"),

UPLOAD_FILE_FAIL(414, "上传文件失败"),

REQ_BODY_SIZE_OUT_OF_MAX_LIMIT(413, "请求报文大小超出最大限制"),

UPDATE_DATA_NOT_FOUND(430, "要更新的数据不存在"),

DELETE_DATA_NOT_FOUND(431, "要删除的数据不存在");

private int code;

private String message;

private SystemErrorCode(int code, String message) {
this.code = code;
this.message = message;
}

@Override
public int getCode() {
return code;
}

@Override
public String getMessage() {
return message;
}

@Override
public SystemErrorCode parse(int code) {
SystemErrorCode[] values = SystemErrorCode.values();
for (SystemErrorCode value : values) {
if (value.getCode() == code) {
return value;
}
}
return null;
}
}

ErrorCode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface ErrorCode {

/**
* 获取错误码
*
* @return
*/
int getCode();

/**
* 获取错误信息
*
* @return
*/
String getMessage();

/**
* 根据错误码反推错误信息
*
* @param code
* @return
*/
ErrorCode parse(int code);
}
作者

光星

发布于

2019-11-21

更新于

2022-06-17

许可协议

评论