Различные варианты использования RestTemplate.exchange (включая дженерики и т. д. — все)
Различные варианты использования RestTemplate.exchange (включая дженерики и т. д. — все)

Предисловие

В нашем ежедневном развитии,Является ли это вызовом между внутренними службами,Или позвоните в сторонний сервис,Неизбежно инициировать Httpпросить,существоватьJavaНачато вHttpпросить Общие методы включают примерноСобственный HttpURLConnection, HttpClient Apache, RestTemplate Springждать,Если вы основаны на платформе Spring,Тогда настоятельно рекомендуется использовать RestTemplate.,Причина проста: это очень соответствует нашей привычке запускать httpпросить,Точно так же, как использование почтальона,Вам нужно заботиться только о конкретном URL-адресе, заголовке, теле и т. д.,RestTemplate помогает нам четко упорядочить (инкапсулировать) утомительные детали.,Нам не нужно беспокоиться о ненужных деталях! Особенно метод RestTemplate.exchange, можно сказать, что он может превзойти другие методы всего одним ходом. . . Поэтому в этой статье будут подробно представлены различные варианты использования RestTemplate.exchange, стремясь охватить различные сценарии повседневной разработки. start~~

1. Получить запрос

Вот 5 распространенных сценариев: 1.1 Возвращаемый базовый тип 1.2 Возврат типа пользовательского объекта 1.3 возвращатьсяList<T>тип 1.4 возвращатьсяMap<K,V>тип 1.5 становится пользовательским родовым типом

1.1 Возвращаемый базовый тип

Давайте сначала смоделируем самый простойAPI:Получить имя на основе идентификатора пользователя код вызова

Язык кода:javascript
копировать
    // 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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
    @GetMapping("/name/mock")
    public String mockName(@RequestParam("id") Integer id) {
        return "Тяньган" + id;
    }

Проверьте это: Как и ожидалось, я должен сказать, что всё должно быть так просто, хорошо~~

Запрос http://localhost:8080/demo/name?id=123 Возвращение в Тяньган 123

Описание параметров метода обмена: Просто посмотрите комментарии исходного кода, там очень понятно, и это просто лишнее.

1.2 Возврат типа пользовательского объекта

Фактически, пользовательский объект и вызов String — одно и то же.,Просто измените типString.class на DTO.class.,например:Получить информацию о пользователе на основе идентификатора пользователя

Создайте новый объект UserDto:

Язык кода:javascript
копировать
@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;
}

код вызова

Язык кода:javascript
копировать
    // 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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
    @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» }

1.3 возвращатьсяList<T> тип

Для общего типа,нам нужно использоватьexchangeдругогоПерегруженные методы для дженериков,Прямо сейчасЗамените тип ответа на параметризованную ссылку типа.,По-прежнему рекомендуется читать комментарии к исходному коду:

Следующий,Продолжим моделировать распространенный сценарий:Нечеткий поиск всех совпадающих пользователей на основе имени пользователя,появляются Результат множественный,Мы используем Listтип. код вызоваУкажите возвращаемый список через параметризованную ссылку типа.

Язык кода:javascript
копировать
    // 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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
    @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" } ]

1.4 возвращатьсяMap<K,V> тип

Карта также является универсальным типом.,И естьK,Vдватип,Продолжим моделировать распространенный сценарий:Поиск по ключевым словам,Разный типвозвращаться в разных полях,Потому что поле результата не фиксировано,так что мывозвращатьсяMapтип。 код вызоваПо-прежнему укажите возвращаемую карту через параметризованную ссылку типа.

Язык кода:javascript
копировать
    // 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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
    @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.5 становится пользовательским родовым типом

我们существовать1.2 Возврат типа пользовательского объектаИмитацияПолучить информацию о пользователе на основе идентификатора пользователясцена,ноНеурегулированный незаконный просить, исключения и другие ситуации,Итак, далее мы настраиваем общий результат общего пользовательского кода.,верно1.2Сделайте некоторые улучшения:Получить информацию о пользователе на основе идентификатора пользователя,в зависимости от разных ситуацийвозвращатьсядругая кодировка

Давайте создадим новыйResult<T>добрый:

Язык кода:javascript
копировать
@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>

Язык кода:javascript
копировать
    // 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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
	@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 }


2.Отправить запрос

Фактически для обмена,POST и GET используются очень похожим образом.,Так что здесь мы только готовимся2индивидуальныйdemoВ основном демонстрирует, как передавать заголовок и тело2.1 проходитьheader+bodyвозвращатьсяобъекттип 2.2 проходитьheader+bodyстановится пользовательским родовым типом

2.1 проходитьheader+bodyвозвращатьсяобъекттип

код вызова

Язык кода:javascript
копировать
	@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();
    }

Вызывается макетный код

Язык кода:javascript
копировать
    @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” }

2.2 проходитьheader+bodyстановится пользовательским родовым типом

ивозвращатьсяобычнотипиз区别还是Замените тип ответа на параметризованную ссылку типа. код вызова

Язык кода:javascript
копировать
@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();
}

Вызывается макетный код

Язык кода:javascript
копировать
    @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” } }


3. Обработка исключений

Ничто из написанного выше не обрабатывает исключения. Обычно мы обрабатываем два исключения:

  1. бросил сам по себе throws RestClientException
  2. возвращатьсяизResponseEntityизКод не равен 200

Обычный тип:

Язык кода:javascript
копировать
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>

Язык кода:javascript
копировать
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;
}

4. RestTemplateКонфигурация@Bean

Язык кода:javascript
копировать
@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, мы не будем вдаваться в подробности, если вы считаете, что есть какие-либо сцены. не покрываются, пожалуйста, оставьте сообщение или отправьте личное сообщение~~.

Лучшие отношения – это взаимные достижения,大家из「Три подряд」就是我创作из最大动力!

Примечание. Если в этом блоге есть какие-либо ошибки или предложения, вы можете оставить сообщение!


boy illustration
Неразрушающее увеличение изображений одним щелчком мыши, чтобы сделать их более четкими артефактами искусственного интеллекта, включая руководства по установке и использованию.
boy illustration
Копикодер: этот инструмент отлично работает с Cursor, Bolt и V0! Предоставьте более качественные подсказки для разработки интерфейса (создание навигационного веб-сайта с использованием искусственного интеллекта).
boy illustration
Новый бесплатный RooCline превосходит Cline v3.1? ! Быстрее, умнее и лучше вилка Cline! (Независимое программирование AI, порог 0)
boy illustration
Разработав более 10 проектов с помощью Cursor, я собрал 10 примеров и 60 подсказок.
boy illustration
Я потратил 72 часа на изучение курсорных агентов, и вот неоспоримые факты, которыми я должен поделиться!
boy illustration
Идеальная интеграция Cursor и DeepSeek API
boy illustration
DeepSeek V3 снижает затраты на обучение больших моделей
boy illustration
Артефакт, увеличивающий количество очков: на основе улучшения характеристик препятствия малым целям Yolov8 (SEAM, MultiSEAM).
boy illustration
DeepSeek V3 раскручивался уже три дня. Сегодня я попробовал самопровозглашенную модель «ChatGPT».
boy illustration
Open Devin — инженер-программист искусственного интеллекта с открытым исходным кодом, который меньше программирует и больше создает.
boy illustration
Эксклюзивное оригинальное улучшение YOLOv8: собственная разработка SPPF | SPPF сочетается с воспринимаемой большой сверткой ядра UniRepLK, а свертка с большим ядром + без расширения улучшает восприимчивое поле
boy illustration
Популярное и подробное объяснение DeepSeek-V3: от его появления до преимуществ и сравнения с GPT-4o.
boy illustration
9 основных словесных инструкций по доработке академических работ с помощью ChatGPT, эффективных и практичных, которые стоит собрать
boy illustration
Вызовите deepseek в vscode для реализации программирования с помощью искусственного интеллекта.
boy illustration
Познакомьтесь с принципами сверточных нейронных сетей (CNN) в одной статье (суперподробно)
boy illustration
50,3 тыс. звезд! Immich: автономное решение для резервного копирования фотографий и видео, которое экономит деньги и избавляет от беспокойства.
boy illustration
Cloud Native|Практика: установка Dashbaord для K8s, графика неплохая
boy illustration
Краткий обзор статьи — использование синтетических данных при обучении больших моделей и оптимизации производительности
boy illustration
MiniPerplx: новая поисковая система искусственного интеллекта с открытым исходным кодом, спонсируемая xAI и Vercel.
boy illustration
Конструкция сервиса Synology Drive сочетает проникновение в интрасеть и синхронизацию папок заметок Obsidian в облаке.
boy illustration
Центр конфигурации————Накос
boy illustration
Начинаем с нуля при разработке в облаке Copilot: начать разработку с минимальным использованием кода стало проще
boy illustration
[Серия Docker] Docker создает мультиплатформенные образы: практика архитектуры Arm64
boy illustration
Обновление новых возможностей coze | Я использовал coze для создания апплета помощника по исправлению домашних заданий по математике
boy illustration
Советы по развертыванию Nginx: практическое создание статических веб-сайтов на облачных серверах
boy illustration
Feiniu fnos использует Docker для развертывания личного блокнота Notepad
boy illustration
Сверточная нейронная сеть VGG реализует классификацию изображений Cifar10 — практический опыт Pytorch
boy illustration
Начало работы с EdgeonePages — новым недорогим решением для хостинга веб-сайтов
boy illustration
[Зона легкого облачного игрового сервера] Управление игровыми архивами
boy illustration
Развертывание SpringCloud-проекта на базе Docker и Docker-Compose