Spring Boot では、フロントエンド形式に統一して戻すことで、コードの再利用性と保守性を向上させることができます。この記事では、Spring Boot プロジェクトで統一されたレスポンス形式をカプセル化する方法を紹介します。
レスポンシブ フォーマット デザイン
応答フォーマットを設計するときは、RESTful API の設計仕様を参照できます。通常、適切な応答フォーマットには次のフィールドが含まれている必要があります。
code
: リクエストの処理結果を示すために使用されるレスポンスステータスコード。通常、2xx は成功 (0 は個人的な習慣の成功を意味します)、4xx はクライアント エラー、5xx はサーバー エラーを意味します。message
: 応答メッセージ。応答ステータス コードの特定の意味を説明するために使用されます。data
: 応答データ。要求が正常に処理された後にデータを格納するために使用されます。リクエストが失敗した場合、このフィールドは空または存在しない可能性があります。
特定の実装では、data
フィールドはオブジェクトまたはコレクションにすることができます。また、フロントエンドの解析を容易にするため、レスポンスのフォーマットは通常JSON形式を採用しています。
上記の仕様に基づいて、一般的な応答エンティティ クラスを定義できます。
@Data
public class DataResult <T>{
@ApiModelProperty(value = "响应状态码 code=0代表成功,其它失败")
private int code;
@ApiModelProperty(value = "响应的业务数据")
private T data;
@ApiModelProperty(value = "响应状提示语")
private String message;
/**
* 响应成功的方法
* @param data
* @param <T>
* @return
*/
public static <T> DataResult<T> success(T data){
DataResult<T> result=new DataResult<>();
result.data=data;
result.code= ResponseCode.SUCCESS.getCode();
result.message=ResponseCode.SUCCESS.getMessage();
return result;
}
/**
* 响应失败工具方法
* @param code
* @param message
* @param <T>
* @return
*/
public static <T> DataResult<T> fail(int code ,String message){
DataResult<T> result=new DataResult<>();
result.code= code;
result.message=message;
return result;
}
}
复制代码
統一された応答ステータス コードの列挙を定義します。
public enum ResponseCode {
SUCCESS(0,"响应成功"),
//后端服务异常以500开头
SYSTEM_ERROR(500000,"服务异常,请稍后再试"),
OPERATION_ERROR(500001,"操作失败,请稍后再试"),
//后端服务异常以400开头
DATA_PARAM_ERROR(400000,"传入参数错误"),
ACCOUNT_ALREADY_EXISTS(400001,"账号已存在,请登录"),
ACCOUNT_NOT_FOUND(400002,"账号不存在"),
ACCOUNT_LOCK(400003,"账号已锁定,请联系管理员解锁"),
ACCOUNT_ERROR(400004,"账户密码不匹配"),
TOKEN_ERROR(401000,"token 已失效,请重新登录")
;
private final int code;
private final String message;
ResponseCode(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
}
复制代码
統一された応答形式のカプセル化
Spring が提供するカプセル化を使用して、ResponseBodyAdvice
統一された応答形式を実現できます。具体的には、ResponseBodyAdvice
Controller メソッドの実行後に返される結果を変更および拡張できるインターフェイスです。
まず、一般的な応答フォーマット クラスを定義する必要があります。
@RestControllerAdvice
@Slf4j
public class RestResponseBodyAdviceHandler implements ResponseBodyAdvice<Object> {
@Resource
private ObjectMapper objectMapper;
private final String stringConverter="org.springframework.http.converter.StringHttpMessageConverter";
/**
* true:代表支持我们在响应前端的时候做一些处理(调用beforeBodyWrite方法)
* false:不支持
* @param returnType
* @param converterType
* @return
*/
@Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
log.info("supports:{}",returnType.getDeclaringClass().getName());
/**
* 排除swagger-ui请求返回数据增强
*/
return !returnType.getDeclaringClass().getName().contains("springfox");
}
@SneakyThrows
@Override
public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
/**
* 当接口返回到类型消息转换器是StringHttpMessageConverter
* 我们才需要把它转换成string
*/
if(stringConverter.equalsIgnoreCase(selectedConverterType.getName())){
HttpHeaders headers= response.getHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return objectMapper.writeValueAsString(DataResult.success(body));
}
/**
*
* 如果响应结果已经是DataResult类型,则直接返回
*/
if(body instanceof DataResult){
return body;
}
return DataResult.success(body);
}
}
复制代码
上記のコードでは、ResponseBodyAdvice
インターフェイスを実装し、その中でsupports
sumメソッドを書き直しました。beforeBodyWrite
その中で、supports
メソッドは現在の戻り値の型を処理する必要があるかどうかを判断するために使用され、beforeBodyWrite
メソッドは返された結果をカプセル化するために使用されます
在Spring Boot中,StringHttpMessageConverter
消息转换器已经默认添加到了消息转换器列表中,它会将请求和响应中的字符串类型数据转换成Java中的String
类型,当接口返回类型是字符串类型,则StringHttpMessageConverter
会处理该请求,并将请求中的数据转换成Java中的String
类型,如果我们直接返回到是DataResult 类型就会出现类型转换异常:xxxxx.DataResult cannot be cast to java.lang.String
当接口返回类型为DataResult
时已经是 DataResult
类型了所以我们不需要处理,反之需要使用 DataResult
包装处理统一返回DataResult
类型。
使用ResponseBodyAdvice
的好处是,它可以更加精细地控制响应结果的格式,可以对所有的返回值进行统一的封装,也可以针对某些返回值进行特殊处理,灵活性更高。
测试
@RestController
@Api(tags = "测试模块")
public class TestController {
@GetMapping("/hello")
@ApiOperation(value = "经典hello接口")
public String hello(){
return "Hello World";
}
}
复制代码
结果:
{
"code": 0,
"data": "Hello World",
"message": "响应成功"
}
复制代码