«Это третий день моего участия в ноябрьском испытании обновлений. Подробную информацию об этом событии см.:Вызов последнего обновления 2021 г."
Привет, я смотрю на гору.
Сегодня поговорим о том, как Spring Boot обеспечивает элегантный ответ данных: унифицированный формат ответа результата, простая инкапсуляция данных.
помещение
Независимо от размера системы, большинство проектов Spring Boot предоставляют интерфейсы Restful + json для интерфейсных или других сервисных вызовов.Формат унифицирован и стандартизирован.Это символ доброжелательного отношения программистов друг к другу, а также базовый гарантия уменьшения совместной отладки и ругани.
Обычно результат ответа должен включать код бизнес-статуса, описание ответа, отметку времени ответа и содержание ответа, например:
{
"code": 200,
"desc": "查询成功",
"timestamp": "2020-08-12 14:37:11",
"data": {
"uid": "1597242780874",
"name": "测试 1"
}
}
Для кода государства дорожного движения делится на две фракции: рекомендуется использовать код ответа HTTP-адреса для использования службы возврата интерфейса; другой - вернуть весь HTTP-ответ 200, в ответ на указанный орган отдельным состоянием отклика. Два метода имеют преимущества и недостатки, лично я рекомендую использовать секунду, потому что есть много функций обработки веб-серверов для перехвата кода состояния HTTP, а также ограниченное количество кодов государства, не достаточно гибким. Такие, как процесс возврата, прошел успешно, и интерфейс 200 представляет собой нормальный ответ, теперь необходимо использовать код состояния обработки интерфейса, указывает на успех и нормальный ответ, но не запрашивает состояние данных, может вернуть 2001, Рис.
пользовательское тело ответа
定义一个数据响应体是返回统一响应格式的第一步,无论接口正常返回,还是发生异常,返回给调用方的结构格式都应该不变。 Привести пример:
@ApiModel
@Data
public class Response<T> {
@ApiModelProperty(value = "返回码", example = "200")
private Integer code;
@ApiModelProperty(value = "返回码描述", example = "ok")
private String desc;
@ApiModelProperty(value = "响应时间戳", example = "2020-08-12 14:37:11")
private Date timestamp = new Date();
@ApiModelProperty(value = "返回结果")
private T data;
}
Таким образом, пока метод контроллера возвращаетResponse
Вот и все, ответ интерфейса будет таким же, но при этом будет формироваться множество шаблонов кода с фиксированными форматами, например такие:
@RequestMapping("hello1")
public Response<String> hello1() {
final Response<String> response = new Response<>();
response.setCode(200);
response.setDesc("返回成功");
response.setData("Hello, World!");
return response;
}
Результат вызова ответа интерфейса:
{
"code": 200,
"desc": "返回成功",
"timestamp": "2020-08-12 14:37:11",
"data": "Hello, World!"
}
Как может такой повторяющийся и нетехнический код быть достойным такого существа, как программист? Лучше всего вычесть повторяющийся код при условии возврата результата ответа, например:
@RequestMapping("hello2")
public String hello2() {
return "Hello, World!";
}
Для этого требуется помощь SpringResponseBodyAdvice
сбываться.
Глобальная обработка данных ответов
Сначала в коде:
/**
* <br>created at 2020/8/12
*
* @author www.howardliu.cn
* @since 1.0.0
*/
@RestControllerAdvice
public class ResultResponseAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
return !returnType.getGenericParameterType().equals(Response.class);// 1
}
@Override
public Object beforeBodyWrite(final Object body, final MethodParameter returnType, final MediaType selectedContentType,
final Class<? extends HttpMessageConverter<?>> selectedConverterType,
final ServerHttpRequest request, final ServerHttpResponse response) {
if (body == null || body instanceof Response) {
return body;
}
final Response<Object> result = new Response<>();
result.setCode(200);
result.setDesc("查询成功");
result.setData(body);
if (returnType.getGenericParameterType().equals(String.class)) {// 2
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.writeValueAsString(result);
} catch (JsonProcessingException e) {
throw new RuntimeException("将 Response 对象序列化为 json 字符串时发生异常", e);
}
}
return result;
}
}
/**
* <br>created at 2020/8/12
*
* @author www.howardliu.cn
* @since 1.0.0
*/
@RestController
public class HelloWorldController {
@RequestMapping("hello2")
public String hello2() {
return "Hello, World!";
}
@RequestMapping("user1")
public User user1() {
User u = new User();
u.setUid(System.currentTimeMillis() + "");
u.setName("测试1");
return u;
}
}
Приведенный выше код реализует SpringResponseBodyAdvice
Шаблонный метод класса может быть реализован в соответствии с требованиями Spring. Есть только два места, которые требуют особого внимания, это места, отмеченные в коде 1 и 2.
Во-первых, давайте поговорим о строке 1, котораяsupports
метод, этот метод должен проверить, нужно ли его вызыватьbeforeBodyWrite
Предварительное суждение метода, возвращениеtrue
затем выполнитьbeforeBodyWrite
метод, здесь судят, нужно ли его выполнять по возвращаемому типу метода ControllerbeforeBodyWrite
, или всегда возвращатьсяtrue
, а затем определите, требуется ли преобразование типов.
Затем сосредоточьтесь на следующей строке 2. Эта строка — яма, большая яма.Если вы не знакомы со структурой Spring, вы точно задержитесь здесь надолго, и тут нет никакого фокуса.
Код 2 Эта строка является суждениемController
метод возвращаетString
Результат типа, если да, возвращает возвращенную сериализацию объекта.
Это потому чтоSpring
правильноString
Тип типа ответа обрабатывается отдельно, используйтеStringHttpMessageConverter
класс для преобразования данных. При обработке результата ответа он будет находиться в методеgetContentLength
Рассчитайте размер тела ответа в , его определение метода родительского класса:protected Long getContentLength(T t, @Nullable MediaType contentType)
,иStringHttpMessageConverter
переписать метод какprotected Long getContentLength(String str, @Nullable MediaType contentType)
, первый параметр — объект ответа, фиксированная запись —String
типа, если мы форсируем возвратResponse
объект, сообщуClassCastException
.
Конечно, вернуться напрямуюString
Сцен не так много, и эта яма может внезапно появиться в специальном интерфейсе в один прекрасный день.
Дополнительные инструкции
Выше только что показаноResponseBodyAdvice
Самое простое приложение класса, мы также можем реализовать больше расширений. Например:
-
Верните идентификатор запроса: его необходимо объединить с
RequestBodyAdvice
Связывание, после получения идентификатора запроса ответ помещается в тело ответа; -
Шифрование данных результата: пройти
ResponseBodyAdvice
Реализуйте шифрование данных ответа без вторжения в бизнес-код и гибко управляйте уровнем шифрования интерфейса с помощью аннотаций; -
При желании оберните тело ответа: например, определите аннотации
IgnoreResponseWrap
В ответ на интерфейс не требуется, чтобы корпус пакета определен, тоsupports
О методе можно судить по аннотации метода, например:
@Override
public boolean supports(final MethodParameter returnType, final Class<? extends HttpMessageConverter<?>> converterType) {
final IgnoreResponseWrap[] declaredAnnotationsByType = returnType.getExecutable().getDeclaredAnnotationsByType(IgnoreResponseWrap.class);
return !(declaredAnnotationsByType.length > 0 || returnType.getGenericParameterType().equals(Response.class));
}
Многие другие игры не перечислены одна за другой.
Суммировать
Данные нормального ответа, упомянутые выше, лишь немного элегантны.Если вы хотите быть полным, вам также необходимо учитывать ненормальную ситуацию интерфейса.Вы не можете прийти к большому.try/catch/finally
Оберните бизнес-логику, это слишком уродливо. Позже будет еще одна статья, в которой основное внимание будет уделено тому, как интерфейс может возвращать ответ с унифицированным результатом при возникновении исключения.
Рекомендуемое чтение
Привет, я смотрю на гору. Плавайте в мире кода, играйте и наслаждайтесь жизнью. Если статья была вам полезна, ставьте лайк, добавляйте в закладки и подписывайтесь. Приглашаем обратить внимание на паблик-аккаунт «Глядя на горную хижину» и открыть для себя другой мир.