В нашем ежедневном развитии,Является ли это вызовом между внутренними службами,Или позвоните в сторонний сервис,Неизбежно инициировать Httpпросить,существоватьJavaНачато вHttpпросить Общие методы включают примерноСобственный HttpURLConnection, HttpClient Apache, RestTemplate Springждать,Если вы основаны на платформе Spring,Тогда настоятельно рекомендуется использовать RestTemplate.,Причина проста: это очень соответствует нашей привычке запускать httpпросить,Точно так же, как использование почтальона,Вам нужно заботиться только о конкретном URL-адресе, заголовке, теле и т. д.,RestTemplate помогает нам четко упорядочить (инкапсулировать) утомительные детали.,Нам не нужно беспокоиться о ненужных деталях! Особенно метод RestTemplate.exchange, можно сказать, что он может превзойти другие методы всего одним ходом. . . Поэтому в этой статье будут подробно представлены различные варианты использования RestTemplate.exchange, стремясь охватить различные сценарии повседневной разработки. start~~
Вот 5 распространенных сценариев: 1.1 Возвращаемый базовый тип 1.2 Возврат типа пользовательского объекта 1.3 возвращатьсяList<T>тип 1.4 возвращатьсяMap<K,V>тип 1.5 становится пользовательским родовым типом
Давайте сначала смоделируем самый простойAPI:Получить имя на основе идентификатора пользователя код вызова:
// 1.1 getпроситьвозвращаться Базовыйтип @GetMapping("/name")
public String getName(@RequestParam("id") Integer id) {
String url = "http://localhost:8080/demo/name/mock?id=" + id;
return restTemplate.exchange(url, HttpMethod.GET, null, String.class).getBody();
}
Вызывается макетный код:
@GetMapping("/name/mock")
public String mockName(@RequestParam("id") Integer id) {
return "Тяньган" + id;
}
Проверьте это: Как и ожидалось, я должен сказать, что всё должно быть так просто, хорошо~~
Запрос http://localhost:8080/demo/name?id=123 Возвращение в Тяньган 123
Описание параметров метода обмена: Просто посмотрите комментарии исходного кода, там очень понятно, и это просто лишнее.
Фактически, пользовательский объект и вызов String — одно и то же.,Просто измените типString.class на DTO.class.
,например:Получить информацию о пользователе на основе идентификатора пользователя
Создайте новый объект UserDto:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class UserDto implements Serializable {
private Integer id;
private String name;
private Integer age;
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private Date birthday;
}
код вызова:
// 1.2 getпроситьвозвращатьсяобъекттип @GetMapping("/user")
public UserDto getUser(@RequestParam("id") Integer id) {
String url = "http://localhost:8080/demo/user/mock?id=" + id;
return restTemplate.exchange(url, HttpMethod.GET, null, UserDto.class).getBody();
}
Вызывается макетный код:
@GetMapping("/user/mock")
public UserDto mockUser(@RequestParam("id") Integer id) {
return UserDto.builder().id(id)
.name("Тяньган" + id)
.age(id + 18)
.birthday(new Date()).build();
}
Проверьте это: ok~~
Запрос http://localhost:8080/demo/user?id=1 возвращаться { "идентификатор": 1, "имя": "Тяньган", «возраст»: 19, «день рождения»: «2022-11-06 05:35:43» }
Для общего типа,нам нужно использоватьexchangeдругогоПерегруженные методы для дженериков,Прямо сейчасЗамените тип ответа на параметризованную ссылку типа.
,По-прежнему рекомендуется читать комментарии к исходному коду:
Следующий,Продолжим моделировать распространенный сценарий:Нечеткий поиск всех совпадающих пользователей на основе имени пользователя,появляются Результат множественный,Мы используем Listтип.
код вызова:
Укажите возвращаемый список через параметризованную ссылку типа.
// 1.3 getпроситьвозвращатьсяList<T>тип
@GetMapping("/user/list")
public List<UserDto> getUserList(@RequestParam("name") String name) {
String url = "http://localhost:8080/demo/user/list/mock?name=" + name;
ParameterizedTypeReference<List<UserDto>> responseBodyType = new ParameterizedTypeReference<List<UserDto>>() {};
return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
}
Вызывается макетный код:
@GetMapping("/user/list/mock")
public List<UserDto> mockUserList(@RequestParam("name") String name) {
List<UserDto> list = new ArrayList<>();
for (int i = 1; i < 3; i++) {
list.add(UserDto.builder().id(i)
.name(name + i)
.age(i + 10)
.birthday(new Date()).build());
}
return list;
}
Проверьте это: ok~~
Запрос http://localhost:8080/demo/user/list?name=Tiangang возвращаться [ { "идентификатор": 1, "name": "Тяньган1", «возраст»: 11, "день рождения": "2022-11-06 21:44:24" }, { «идентификатор»: 2, "name": "Тяньган 2", «возраст»: 12, "день рождения": "2022-11-06 21:44:24" } ]
Карта также является универсальным типом.,И естьK,Vдватип,Продолжим моделировать распространенный сценарий:Поиск по ключевым словам,Разный типвозвращаться в разных полях,Потому что поле результата не фиксировано,так что мывозвращатьсяMapтип。
код вызова:
По-прежнему укажите возвращаемую карту через параметризованную ссылку типа.
// 1.4 getпроситьвозвращатьсяMapтип
@GetMapping("/user/map")
public Map<String, Object> getUserMap(@RequestParam(value = "type", required = true) Integer type, @RequestParam("key") String key) {
String url = "http://localhost:8080/demo/user/map/mock?type=" + type + "&key=" + key;
ParameterizedTypeReference<Map<String, Object>> responseBodyType = new ParameterizedTypeReference<Map<String, Object>>() {};
return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
}
Вызывается макетный код:
@GetMapping("/user/map/mock")
public Map<String, Object> mockUserMap(@RequestParam(value = "type", required = true) Integer type, @RequestParam("key") String key) {
Map<String, Object> map = new HashMap<>();
if (type.equals(1)) {
map.put("id", 1);
map.put("name" + type, "hello" + key);
} else {
map.put("id", 2);
map.put("name" + type, "hello" + key);
}
return map;
}
Проверьте это: Есть разные поля в зависимости от типавозвращаться, красиво~~
просить http://localhost:8080/demo/user/map?type=1&key=123 возвращаться { “id”: 1, “
name1
”: “hello123” }просить http://localhost:8080/demo/user/map?type=2&key=456 возвращаться { “id”: 2, “
name2
”: “hello456” }
我们существовать1.2 Возврат типа пользовательского объектаИмитацияПолучить информацию о пользователе на основе идентификатора пользователясцена,ноНеурегулированный незаконный просить, исключения и другие ситуации
,Итак, далее мы настраиваем общий результат общего пользовательского кода.,верно1.2Сделайте некоторые улучшения:Получить информацию о пользователе на основе идентификатора пользователя,в зависимости от разных ситуацийвозвращатьсядругая кодировка。
Давайте создадим новыйResult<T>добрый:
@Data
public class Result<T extends Serializable> implements Serializable {
private boolean success;
private String code;
private String message;
private T data;
public static <T extends Serializable> Result<T> success(String code, String message, T data) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setData(data);
result.setSuccess(true);
return result;
}
public static <T extends Serializable> Result<T> success(T data) {
return success("200", "успех", data);
}
public static <T extends Serializable> Result<T> fail(String code, String message) {
Result<T> result = new Result<>();
result.setCode(code);
result.setMessage(message);
result.setSuccess(false);
return result;
}
}
код вызова:
Все еще прошлоParameterizedTypeReferenceобозначениевозвращатьсяизResult<T>
// 1.5 getпроситьвозвращаться пользовательского типового типа
@GetMapping("/user/result")
public Result<UserDto> getUserResult(@RequestParam("id") Integer id) {
String url = "http://localhost:8080/demo/user/result/mock?id=" + id;
ParameterizedTypeReference<Result<UserDto>> responseBodyType = new ParameterizedTypeReference<Result<UserDto>>() {};
return restTemplate.exchange(url, HttpMethod.GET, null, responseBodyType).getBody();
}
Вызывается макетный код:
@GetMapping("/user/result/mock")
public Result<UserDto> mockUserResult(@RequestParam("id") Integer id) {
if (id == null || id <= 0) {
return Result.fail("400", «Идентификатор недействителен!»);
}
if (id % 2 == 0) {
// Это просто имитация нестандартных ситуаций.
return Result.fail("500", «Операция не удалась, количество посещений слишком велико!»);
}
UserDto userDto = UserDto.builder().id(id)
.name("Тяньган" + id)
.age(id + 18)
.birthday(new Date()).build();
return Result.success("200", "успех", userDto);
}
Проверьте это: Именно то, что мы хотели и именно так, как ожидалось!
просить http://localhost:8080/demo/user/result?id=0 возвращаться { “success”: false, “code”: “400”, “message”: «Идентификатор недействителен!», “data”: null }
просить http://localhost:8080/demo/user/result?id=1 возвращаться { “success”: true, “code”: “200”, “message”: "успех", “data”: { “id”: 1, “name”: «Тяньган 1», “age”: 19, “birthday”: “2022-11-07 04:03:09” } }
просить http://localhost:8080/demo/user/result?id=2 возвращаться { “success”: false, “code”: “500”, “message”: «Операция не удалась, количество посещений слишком велико!», “data”: null }
Фактически для обмена,POST и GET используются очень похожим образом.,Так что здесь мы только готовимся2индивидуальныйdemoВ основном демонстрирует, как передавать заголовок и тело。 2.1 проходитьheader+bodyвозвращатьсяобъекттип 2.2 проходитьheader+bodyстановится пользовательским родовым типом
код вызова:
@GetMapping("/user/body")
public UserDto postUser(@RequestParam("id") Integer id) {
String url = "http://localhost:8080/demo/user/body/mock";
UserDto body = UserDto.builder().id(id)
.name("body" + id)
.age(id + 18)
.birthday(new Date()).build();
// Заголовок устанавливается в соответствии с реальной ситуацией. В противном случае он останется пустым.
HttpHeaders headers = new HttpHeaders();
headers.add("AccessKey", «Индивидуальный ключ доступа к API»);
headers.add("Content-Type", "application/json");
HttpEntity<?> requestEntity = new HttpEntity<>(body, headers);
return restTemplate.exchange(url, HttpMethod.POST, requestEntity, UserDto.class).getBody();
}
Вызывается макетный код:
@PostMapping("/user/body/mock")
public UserDto mockPostUser(@RequestBody UserDto userParam) {
return userParam;
}
Проверьте это: ok~~
просить http://localhost:8080/demo/user/body?id=1 возвращаться { “id”: 1, “name”: “body1”, “age”: 19, “birthday”: “2022-11-06 21:20:41” }
ивозвращатьсяобычнотипиз区别还是Замените тип ответа на параметризованную ссылку типа.
код вызова:
@GetMapping("/user/result/body")
public Result<UserDto> postUserResult(@RequestParam("id") Integer id) {
String url = "http://localhost:8080/demo/user/result/body/mock";
UserDto body = UserDto.builder().id(id)
.name("body" + id)
.age(id + 10)
.birthday(new Date()).build();
// Заголовок устанавливается в соответствии с реальной ситуацией. В противном случае он останется пустым.
HttpHeaders headers = new HttpHeaders();
headers.add("AccessKey", «Индивидуальный ключ доступа к API»);
headers.add("Content-Type", "application/json");
HttpEntity<?> requestEntity = new HttpEntity<>(body, headers);
ParameterizedTypeReference<Result<UserDto>> responseBodyType = new ParameterizedTypeReference<Result<UserDto>>(){};
return restTemplate.exchange(url, HttpMethod.POST, requestEntity, responseBodyType).getBody();
}
Вызывается макетный код:
@PostMapping("/user/result/body/mock")
public Result<UserDto> mockPostUserResult(@RequestBody UserDto userParam) {
return Result.success("200", "успех", userParam);
}
Проверьте это: ok~~
просить http://localhost:8080/demo/user/body?id=1 возвращаться { “success”: true, “code”: “200”, “message”: "успех", “data”: { “id”: 1, “name”: “body1”, “age”: 11, “birthday”: “2022-11-06 21:25:25” } }
Ничто из написанного выше не обрабатывает исключения. Обычно мы обрабатываем два исключения:
Обычный тип:
public <T> T restForEntity(HttpMethod httpMethod, String url, HttpHeaders headers, Object body
, Class<T> responseType) {
HttpEntity<?> requestEntity = null;
if (headers != null || body != null) {
requestEntity = new HttpEntity<>(body, headers);
}
try {
ResponseEntity<T> responseEntity = restTemplate.exchange(url, httpMethod, requestEntity, responseType);
if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
return responseEntity.getBody();
} else {
// Обработка не равен 200 корпус
System.out.println("возвращаться результат не равен 200: code=" + responseEntity.getStatusCode().value()
+ " reason=" + responseEntity.getStatusCode().getReasonPhrase());
}
} catch (RestClientException e) {
// Обработка исключения RestClientException
e.printStackTrace();
}
return null;
}
Общий тип:
只需要将обычнотипиз入参Class<T>Изменить на ParameterizedTypeReference<T>
public <T> T restForWarpEntity(HttpMethod httpMethod, String url, HttpHeaders headers, Object body
, ParameterizedTypeReference<T> responseBodyType) {
HttpEntity<?> requestEntity = null;
if (headers != null || body != null) {
requestEntity = new HttpEntity<>(body, headers);
}
try {
ResponseEntity<T> responseEntity = restTemplate.exchange(url, httpMethod, requestEntity, responseBodyType);
if (responseEntity.getStatusCode().equals(HttpStatus.OK)) {
return responseEntity.getBody();
} else {
// Обработка не равен 200 корпус, Здесь мы просто печатаем
System.out.println("возвращаться результат не равен 200: code=" + responseEntity.getStatusCode().value()
+ " reason=" + responseEntity.getStatusCode().getReasonPhrase());
}
} catch (RestClientException e) {
// Обработка исключения RestClientException, Здесь мы просто печатаем
e.printStackTrace();
}
return null;
}
@Configuration
public class RestTemplateConfig {
@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
restTemplate.getMessageConverters()
.stream()
.filter(MappingJackson2HttpMessageConverter.class::isInstance)
.map(MappingJackson2HttpMessageConverter.class::cast)
.findFirst()
.map(MappingJackson2HttpMessageConverter::getObjectMapper)
.ifPresent(objectMapper -> {
// Удалить формат метки времени по умолчанию
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
// Расположен в Восточном восьмом округе.
objectMapper.setTimeZone(TimeZone.getTimeZone("GMT+8"));
// Единый формат дат при сериализации
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
// Игнорировать регистр
objectMapper.configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES, true);
});
return restTemplate;
}
@Bean
public ClientHttpRequestFactory clientHttpRequestFactory(){
// Если вы используете okHttpClient, вам необходимо ввести пакет jar: okhttp
// OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory();
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setConnectTimeout(15000);
factory.setReadTimeout(30000);
return factory;
}
}
В реальном развитии,Если вы хотите настроить сериализацию RestTemplate,Или иметь соответствующую обработку результатов,Мы также можем вывести результаты,Затем выполните сериализацию или проверку самостоятельно.,可以参考这位大佬из优质文章:RestTemplate использует реальный метод боевого обмена для объяснения верно于更多原理性分析,可以参考这位大佬из优质文章:RestШаблон Сводка
Помимо Get и Post, мы также часто используем Put и Delete. Поскольку «Delete» может относиться к использованию Get, а «Put» может относиться к использованию Post, мы не будем вдаваться в подробности, если вы считаете, что есть какие-либо сцены. не покрываются, пожалуйста, оставьте сообщение или отправьте личное сообщение~~.
Лучшие отношения – это взаимные достижения,大家из「Три подряд」就是我创作из最大动力!
Примечание. Если в этом блоге есть какие-либо ошибки или предложения, вы можете оставить сообщение!