Резюме использования Spring RestTemplate

задняя часть Spring открытый источник Apache

Резюме использования Spring RestTemplate

Как бэкэнд Java, запрос других сетевых ресурсов через HTTP является относительно распространенным случаем; как это сделать вообще?

Может быть, большинство мелких партнеров напрямую берут HttpClient Apache и начинают его делать, или используют какие-то другие известные библиотеки с открытым исходным кодом, такие как OkHttp, конечно, родной HttpURLConnection также не является проблемой.

Этот пост в блоге в основном посвящен экологии Sprig с использованиемRestTemplateИспользуйте положение для инициирования HTTP-запроса

I. Основное использование RestTempalate

0. Голы

Прежде чем представить, как использовать RestTemplate, давайте закинем несколько небольших целей, по крайней мере, нам нужно знать, что можно сделать с помощью RestTemplate, и что мы можем с ним сделать.

Вот краткий обзор общих проблем

  • Обычный Get запрос на получение возвращаемых данных, как играть?
  • Почта отправляет экспресс-запрос, как с этим справиться
  • Метод запроса RequestBody в почтовом запросе отличается от обычного метода запроса.
  • Как обрабатывать https/http два вида доступа отдельно
  • Как включить указанный заголовок в запрос
  • Есть ли междоменные проблемы? если да то как решить
  • Есть запрос на верификацию логина, что делать и как нести идентификационную информацию
  • Поддерживается ли загрузка файлов?
  • Для http-ресурсов, для доступа к которым требуется прокси-сервер, какова ситуация с добавлением прокси-сервера?

Выше много проблем, и визуальный осмотр не может быть завершен в одном посте в блоге, поэтому давайте разберем это.Эта статья в основном сосредоточена на использовании простых запросов Get/Post RestTemplate

1. Базовый интерфейс

Выньте исходный код и взгляните на некоторые общие интерфейсы, которые он предоставляет, которые можно в основном разделить на следующие типы.

// get 请求
public <T> T getForObject();
public <T> ResponseEntity<T> getForEntity();

// head 请求
public HttpHeaders headForHeaders();

// post 请求
public URI postForLocation();
public <T> T postForObject();
public <T> ResponseEntity<T> postForEntity();

// put 请求
public void put();

// pathch 
public <T> T patchForObject

// delete
public void delete()

// options
public Set<HttpMethod> optionsForAllow

// exchange
public <T> ResponseEntity<T> exchange()

Интерфейсы, предоставленные выше, в основном являются соответствующими методами доступа, предоставляемыми Http, но обмен отличается, что будет подробно описано позже.

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

Из приведенного выше именования интерфейса видно, что есть два способа использованияgetForObjectиgetForEntityТак в чем же разница между этими двумя?

  • Из сигнатуры интерфейса видно, что один должен напрямую возвращать ожидаемый объект, а другой — оборачивать объект вResponseEntityв классе пакетов
  • Если вас интересует только возвращаемый результат, используйтеGetForObjectПросто
  • Если вам нужно получить возвращенный заголовок и другую информацию в дополнение к возвращаемому содержимому объекта, вы можете использоватьgetForEntit

А. Создайте интерфейс Get

Чтобы проверить состояние использования RestTemplate, конечно, сначала должна быть предоставлена ​​внутренняя служба REST, которая напрямую использует внутренний интерфейс одной из моих личных древних поэм в качестве простого теста Get.

Запрос соединения:https://story.hhui.top/detail?id=666106231640

Возвращаемый результат:

{
    "status": {
        "code": 200,
        "msg": "SUCCESS"
    },
    "result": {
        "id": 666106231640,
        "title": "西塞山二首(今谓之道士矶,即兴国军大冶县",
        "author": "王周",
        "content": "西塞名山立翠屏,浓岚横入半江青。\n千寻铁锁无由问,石壁空存道者形。\n匹妇顽然莫问因,匹夫何去望千春。\n翻思岵屺传诗什,举世曾无化石人。",
        "explain": "",
        "theme": "无",
        "dynasty": "唐诗"
    }
}

б. Метод getForObject

Первый взгляд на полную сигнатуру интерфейса

@Nullable
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ;

@Nullable
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException ;

@Nullable
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException;

Есть три перегруженных метода, и относительно легко увидеть, как их использовать из интерфейса, один из них немного сбивает с толку, как должны передаваться параметры.

public class RestTestmplateTest {
    private RestTemplate restTemplate;

    @Before
    public void init() {
        restTemplate = new RestTemplate();
    }

    @lombok.Data
    static class InnerRes {
        private Status status;
        private Data result;
    }

    @lombok.Data
    static class Status {
        int code;
        String msg;
    }

    @lombok.Data
    static class Data {
        long id;
        String theme;
        String title;
        String dynasty;
        String explain;
        String content;
        String author;
    }

    @Test
    public void testGet() {
        // 使用方法一,不带参数
        String url = "https://story.hhui.top/detail?id=666106231640";
        InnerRes res = restTemplate.getForObject(url, InnerRes.class);
        System.out.println(res);


        // 使用方法一,传参替换
        url = "https://story.hhui.top/detail?id={?}";
        res = restTemplate.getForObject(url, InnerRes.class, "666106231640");
        System.out.println(res);

        // 使用方法二,map传参
        url = "https://story.hhui.top/detail?id={id}";
        Map<String, Object> params = new HashMap<>();
        params.put("id", 666106231640L);
        res = restTemplate.getForObject(url, InnerRes.class, params);
        System.out.println(res);

        // 使用方法三,URI访问
        URI uri = URI.create("https://story.hhui.top/detail?id=666106231640");
        res = restTemplate.getForObject(uri, InnerRes.class);
        System.out.println(res);
    }
}

Глядя на тестовый пример выше, нечего сказать об использовании последних двух методов, в основном смотрите наorg.springframework.web.client.RestTemplate#getForObject(java.lang.String, java.lang.Class<T>, java.lang.Object...)Использование жестов

  • Замените содержимое в шаблоне URL в соответствии с фактическими параметрами
  • При использовании метода 1 используйте в шаблоне{?}для представления ямы, которая заполняется в соответствии с фактическим порядком параметров.
  • При использовании метода 2 используйте в шаблоне{xx}, и этот xx соответствует ключу в карте

Скриншот после вышеуказанного выполнения выглядит следующим образом

3AD423F4F3C673F2D366772612B4355A.jpg

в. Метод getForEntity

Поскольку у getForObject есть три метода использования, то и у getForEntity теоретически должно быть три соответствующих метода.

public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException ;
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

Поскольку поза такая же, как и выше, для тестирования используется только одна.

@Test
public void testGetForEntity() {
    String url = "https://story.hhui.top/detail?id=666106231640";
    ResponseEntity<InnerRes> res = restTemplate.getForEntity(url, InnerRes.class);
    System.out.println(res);
}

Для этого нас больше всего беспокоит то, что добавляется в пакет ResponseEntity.Скриншоты выглядят следующим образом.

C2D317A154B33CF76F6DB438D1589754.jpg

Как видно из вышеизложенного, есть еще две вещи

  • Возвращаемый код состояния http, например 200 для успешного запроса, 500 для ошибки сервера, 404 не найдено и т. д.
  • заголовок ответа

3. Разместить запрос

Из описания интерфейса выше, в дополнение к foroubject и в преддверии, запрос на почту также имеет выравнивание. Во-вторых, очевидная разница между постом и получением является позором передачи параметров. Параметры получения, как правило, остаются на URL; более распространены через форму

Итак, следующее внимание уделяется тому, что такое forLocation и как передавать параметры.

А. Макет почтового интерфейса

Сначала создайте простую службу REST, которая предоставляет запросы POST, и просто создайте ее на основе Spring-boot, как показано ниже.

@ResponseBody
@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST})
public String post(HttpServletRequest request,
        @RequestParam(value = "email", required = false) String email,
        @RequestParam(value = "nick", required = false) String nick) {
   Map<String, Object> map = new HashMap<>();
   map.put("code", "200");
   map.put("result", "add " + email + " # " + nick + " success!");
   return JSON.toJSONString(map);
}

б) метод postForObject

Первый взгляд на сигнатуру интерфейса

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Object... uriVariables) throws RestClientException ;

public <T> T postForObject(String url, @Nullable Object request, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;

public <T> T postForObject(URI url, @Nullable Object request, Class<T> responseType) throws RestClientException ;

Вышеупомянутые три метода вроде бы не сильно отличаются от предыдущих, но есть еще один параметр запроса, так что насчет конкретного использования?

Варианты использования приведены ниже

@Test
public void testPost() {
    String url = "http://localhost:8080/post";
    String email = "test@hhui.top";
    String nick = "一灰灰Blog";

    MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
    request.add("email", email);
    request.add("nick", nick);

    // 使用方法三
    URI uri = URI.create(url);
    String ans = restTemplate.postForObject(uri, request, String.class);
    System.out.println(ans);

    // 使用方法一
    ans = restTemplate.postForObject(url, request, String.class);
    System.out.println(ans);

    // 使用方法一,但是结合表单参数和uri参数的方式,其中uri参数的填充和get请求一致
    request.clear();
    request.add("email", email);
    ans = restTemplate.postForObject(url + "?nick={?}", request, String.class, nick);
    System.out.println(ans);


    // 使用方法二
    Map<String, String> params = new HashMap<>();
    params.put("nick", nick);
    ans = restTemplate.postForObject(url + "?nick={nick}", request, String.class, params);
    System.out.println(ans);
}

Три метода вызова приведены выше.Существует два типа параметров сообщения, один из которых является параметром uri, который вставляется в URL, а другой является параметром формы.

  • Параметр uri, используя ту же позу, что и в запросе на получение, заполняет яму шаблона в uri.
  • параметры формы, поMultiValueMapИнкапсуляция, такая же структура kv

c. postForEntity

Как и предыдущая поза использования, это не более чем дополнительный слой упаковки, пропустите его и не говорите об этом.

d. postForLocation

Это немного отличается от предыдущего.Из определения интерфейса, это в основном

POST-данные на URL-адрес, возвращая URL-адрес вновь созданного ресурса

Он также предоставляет три интерфейса, а именно: Следует отметить, что возвращаемый результат является объектом URI, то есть сетевым ресурсом.

public URI postForLocation(String url, @Nullable Object request, Object... uriVariables)
		throws RestClientException ;

public URI postForLocation(String url, @Nullable Object request, Map<String, ?> uriVariables)
		throws RestClientException ;

public URI postForLocation(URI url, @Nullable Object request) throws RestClientException ;

Итак, какой интерфейс подходит для такого жеста доступа?

Думаете у нас общий вход или регистрация это пост запроса, а после эти операции завершены? Большинство из них переходят на другие страницы. В этом случае вы можете использоватьpostForLocationТеперь отправьте данные и получите возвращенный URI, тест выглядит следующим образом.

Первый макет внутреннего интерфейса

@ResponseBody
@RequestMapping(path = "success")
public String loginSuccess(String email, String nick) {
    return "welcome " + nick;
}

@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST})
public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email,
        @RequestParam(value = "nick", required = false) String nick) {
    return "redirect:/success?email=" + email + "&nick=" + nick + "&status=success";
}

Доступные тестовые случаи, в основном такие же, как и предыдущие, сказать особо нечего

@Test
public void testPostLocation() {
    String url = "http://localhost:8080/post";
    String email = "test@hhui.top";
    String nick = "一灰灰Blog";

    MultiValueMap<String, String> request = new LinkedMultiValueMap<>();
    request.add("email", email);
    request.add("nick", nick);

    // 使用方法三
    URI uri = restTemplate.postForLocation(url, request);
    System.out.println(uri);
}

Результат выполнения следующий

C4272685267804B4A1C1837EAEB76762.jpg

То, что получается, является внутренним URL-адресом перенаправления 302. Внимательные друзья могут увидеть проблему с искаженными китайскими иероглифами выше. Как ее решить?

Простое решение - закодировать URL

@RequestMapping(path = "post", method = {RequestMethod.GET, RequestMethod.OPTIONS, RequestMethod.POST},
            produces = "charset/utf8")
public String post(HttpServletRequest request, @RequestParam(value = "email", required = false) String email,
        @RequestParam(value = "nick", required = false) String nick) throws UnsupportedEncodingException {
    return "redirect:/success?email=" + email + "&nick=" + URLEncoder.encode(nick, "UTF-8") + "&status=success";
}

II. Резюме

Вышеприведенное дает только базовое использование двух методов запроса Get/Post и не включает более продвинутые, такие как добавление заголовков запросов, добавление сертификатов, установка прокси и т. д. Расширенное использование ожидает выпуска следующего метода. Вышеупомянутая поза

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

В запросе на получение параметры обычно передаются в URL-адресе. Существует два способа заполнения параметров. Та же идея заключается в том, чтобы заполнить содержимое заполнителя в URL-адресе в соответствии с фактическими параметрами, в соответствии с возвращаемым результатом также два способа. , один заботится только о возвращаемом объекте, а другой содержит уверенность в возвращении заголовков

заполнение параметра

  1. В формеhttp://story.hhui.top?id={0}URL-адрес
  • перечислитьgetForObject(String url, Class<T> responseType, Object... uriVariables)
  • 0 в шаблоне означает 0-е место в массиве uriVariables, i означает i-е
  • Если нет параметра url, этот метод тоже рекомендуется, только не передавайте uriVariables
  1. В формеhttp://story.hhui.top?id={id}URL-адрес
  • перечислитьgetForObject(String url, Class<T> responseType, Map<String, ?> uriVariables)
  • Ключом в параметре карты является содержимое {} в параметре URL.

На самом деле есть еще один способ передачи параметров, то есть параметр пути.Способ заполнения тот же, что и выше, и особого способа воспроизведения нет.Выше специально не указан.

вернуть результат

  1. Получить возвращенные данные напрямуюgetForObject
  2. Получить данные, которые будут responseHeadergetForEntity

2. Разместить запрос

  • Также существует два типа возврата почтового запроса, как указано выше.
  • Для почтового запроса параметры можно разделить на отправку формы и параметры URL, где параметр URL соответствует предыдущей логике.
  • параметры почтовой формы, пожалуйста, завернитеMultiValueMap, как второй параметрRequestпредставить
  • почтовый метод и другоеpostForLocation, который возвращает объект URI, то есть метод запроса, подходящий для возврата сетевых ресурсов

3. Другое

В начале я упомянул много общих случаев с сетевыми запросами, но приведенное выше введение, очевидно, только в основах, нам все еще нужно обратить внимание на

  • Как установить заголовки запроса?
  • Как передать идентификационную информацию при запросе аутентификации?
  • настройки прокси
  • Что я могу сделать с загрузкой файла?
  • Как опубликовать строку отправки json (т.е. RequestBody)

Вышеупомянутое может все еще оставаться в главе приложения.Если вас интересуют исходный код и реализация, проблема придет.

  • Каков принцип реализации RestTemplaet
  • Является ли реализация логики заполнения предыдущих параметров URL элегантной?
  • Как анализируется возвращаемый объект
  • ....

Небольшой класс инструментов, на самом деле там довольно много всего.Следующая небольшая цель - изучить пункты, упомянутые выше, один за другим.

III. Другое

1. Серый блог:liuyueyi.github.io/hexblog

Серый личный блог, записывающий все посты блога по учебе и работе, приглашаю всех в гости

2. Заявление

Это не так хорошо, как письмо веры.Контент уже был размещен, и это чисто из семьи.Из-за ограниченных личных возможностей неизбежно будут упущения и ошибки.Если вы найдете ошибки или лучше предложения, вы можете критиковать и исправлять их.

3. Сканируйте внимание

Блог Little Grey и общедоступный номер

QrCode

планета знаний

zhishi