Interface call artifact RestTemplate

1. Overview of RestTemplate

To send http requests, it is estimated that many people have used httpclient and okhttp, which are really easy to use, and the RestTemplate in Spring web is similar to these two functions, and it is also used to send http requests, but the usage is easier than the previous two a lot of.

The RestTemplate class provided by the spring framework can be used to call the rest service in the application. It simplifies the communication method with the http service, unifies the RESTful standard, and encapsulates the http link. We only need to pass in the url and the return value type. Compared with the previously commonly used HttpClient, RestTemplate is a more elegant way to invoke RESTful services.

Accessing third-party REST services in a Spring application is all about using the Spring RestTemplate class. The RestTemplate class is designed on the same principles as many other Spring template classes (eg JdbcTemplate, JmsTemplate), providing a simplified way to perform complex tasks with default behavior.

By default, RestTemplate relies on JDK's ability to provide http connections (HttpURLConnection). If necessary, it can also be replaced with other HTTP libraries such as Apache HttpComponents, Netty or OkHttp through the setRequestFactory method.

Considering that the RestTemplate class is designed for invoking REST services, it's no surprise that its main methods are closely tied to the foundations of REST, which are the methods of the HTTP protocol: HEAD, GET, POST, PUT, DELETE, and OPTIONS. For example, the RestTemplate class has methods such as headForHeaders(), getForObject(), postForObject(), put(), and delete().

The following is a case for everyone. The case is the key point. Through the case, I will list all the usages I know.

2. Case code

img

2.2. Key code location

All the controller code in this article is in RestTemplateTestControllerthe class.

Code for all @Test use cases, at RestTemplateTest.

img

2.3. How to run the test case?

  • pull item
  • Publish the chat16-RestTemplate module to tomcat9
  • Just run the corresponding use case in RestTemplateTest

Let's look at the summary of common usage of RestTemplate.

3. Send Get request

3.1. Common requests

interface code

@GetMapping("/test/get")
@ResponseBody
public BookDto get() {
    
    
    return new BookDto(1, "SpringMVC系列");
}

There are usually two ways to call the above interface using RestTemplate, as follows

@Test
public void test1() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/get";
    //getForObject方法,获取响应体,将其转换为第二个参数指定的类型
    BookDto bookDto = restTemplate.getForObject(url, BookDto.class);
    System.out.println(bookDto);
}

@Test
public void test2() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/get";
    //getForEntity方法,返回值为ResponseEntity类型
    // ResponseEntity中包含了响应结果中的所有信息,比如头、状态、body
    ResponseEntity<BookDto> responseEntity = restTemplate.getForEntity(url, BookDto.class);
    //状态码
    System.out.println(responseEntity.getStatusCode());
    //获取头
    System.out.println("头:" + responseEntity.getHeaders());
    //获取body
    BookDto bookDto = responseEntity.getBody();
    System.out.println(bookDto);
}

test1 output

BookDto{
    
    id=1, name='SpringMVC系列'}

test2 output

200 OK
头:[Content-Type:"application/json;charset=UTF-8", Transfer-Encoding:"chunked", Date:"Sat, 02 Oct 2021 07:05:15 GMT", Keep-Alive:"timeout=20", Connection:"keep-alive"]
BookDto{
    
    id=1, name='SpringMVC系列'}

3.2. URL contains dynamic parameters

interface code

@GetMapping("/test/get/{id}/{name}")
@ResponseBody
public BookDto get(@PathVariable("id") Integer id, @PathVariable("name") String name) {
    
    
    return new BookDto(id, name);
}

There are usually two ways to call the above interface using RestTemplate, as follows

@Test
public void test3() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    //url中有动态参数
    String url = "http://localhost:8080/chat16/test/get/{id}/{name}";
    Map<String, String> uriVariables = new HashMap<>();
    uriVariables.put("id", "1");
    uriVariables.put("name", "SpringMVC系列");
    //使用getForObject或者getForEntity方法
    BookDto bookDto = restTemplate.getForObject(url, BookDto.class, uriVariables);
    System.out.println(bookDto);
}

@Test
public void test4() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    //url中有动态参数
    String url = "http://localhost:8080/chat16/test/get/{id}/{name}";
    Map<String, String> uriVariables = new HashMap<>();
    uriVariables.put("id", "1");
    uriVariables.put("name", "SpringMVC系列");
    //getForEntity方法
    ResponseEntity<BookDto> responseEntity = restTemplate.getForEntity(url, BookDto.class, uriVariables);
    BookDto bookDto = responseEntity.getBody();
    System.out.println(bookDto);
}

test3 output

BookDto{
    
    id=1, name='SpringMVC系列'}

test4 output

BookDto{
    
    id=1, name='SpringMVC系列'}

3.3. The return value of the interface is generic

interface code

@GetMapping("/test/getList")
@ResponseBody
public List<BookDto> getList() {
    
    
    return Arrays.asList(
            new BookDto(1, "Spring高手系列"),
            new BookDto(2, "SpringMVC系列")
    );
}

When the return value of the interface is generic, this situation is quite special. Use the RestTemplate to call the above interface. The code is as follows. The method that needs to be used has a restTemplate.exchangeparameter in this method that is a ParameterizedTypeReferencetype. Specify the generic type through this parameter class

@Test
public void test5() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    //返回值为泛型
    String url = "http://localhost:8080/chat16/test/getList";
    //若返回结果是泛型类型的,需要使用到exchange方法,
    //这个方法中有个参数是ParameterizedTypeReference类型,通过这个参数类指定泛型类型
    ResponseEntity<List<BookDto>> responseEntity =
            restTemplate.exchange(url,
                    HttpMethod.GET,
                    null,
                    new ParameterizedTypeReference<List<BookDto>>() {
    
    
                    });
    List<BookDto> bookDtoList = responseEntity.getBody();
    System.out.println(bookDtoList);
}

output

[BookDto{
    
    id=1, name='Spring高手系列'}, BookDto{
    
    id=2, name='SpringMVC系列'}]

3.4. Download small files

The interface code is as follows, this interface will download the 1.txt file on the server side.

/**
 * 下载文件
 *
 * @return
 */
@GetMapping("/test/downFile")
@ResponseBody
public HttpEntity<InputStreamResource> downFile() {
    
    
    //将文件流封装为InputStreamResource对象
    InputStream inputStream = this.getClass().getResourceAsStream("/1.txt");
    InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
    //设置header
    MultiValueMap<String, String> headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=1.txt");
    HttpEntity<InputStreamResource> httpEntity = new HttpEntity<>(inputStreamResource);
    return httpEntity;
}

Use RestTemplate to call this interface, the code is as follows, currently the content of this file is relatively small, you can get an array directly.

@Test
public void test6() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/downFile";
    //文件比较小的情况,直接返回字节数组
    ResponseEntity<byte[]> responseEntity = restTemplate.getForEntity(url, byte[].class);
    //获取文件的内容
    byte[] body = responseEntity.getBody();
    String content = new String(body);
    System.out.println(content);
}

Note: If the file is large, there is a problem with this method, which will cause oom, so the following method should be used.

3.5. Download large files

Interface code, continue to use the code downloaded above 1.txt

/**
 * 下载文件
 *
 * @return
 */
@GetMapping("/test/downFile")
@ResponseBody
public HttpEntity<InputStreamResource> downFile() {
    
    
    //将文件流封装为InputStreamResource对象
    InputStream inputStream = this.getClass().getResourceAsStream("/1.txt");
    InputStreamResource inputStreamResource = new InputStreamResource(inputStream);
    //设置header
    MultiValueMap<String, String> headers = new HttpHeaders();
    headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=1.txt");
    HttpEntity<InputStreamResource> httpEntity = new HttpEntity<>(inputStreamResource);
    return httpEntity;
}

At this time, use RestTemplate to call this interface, the code is as follows

When the file is relatively large, such as several gigabytes, the byte array cannot be returned, and the memory will burst, resulting in OOM. The execute method needs to be used. This method has a parameter of type ResponseExtractor. After the restTemplate gets the result, The method {@link ResponseExtractor#extractData} will be called back. In this method, the response stream can be obtained and then processed. This process is read and processed without causing memory overflow.

@Test
public void test7() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/downFile";
    /**
     * 文件比较大的时候,比如好几个G,就不能返回字节数组了,会把内存撑爆,导致OOM
     * 需要这么玩:
     * 需要使用execute方法了,这个方法中有个ResponseExtractor类型的参数,
     * restTemplate拿到结果之后,会回调{@link ResponseExtractor#extractData}这个方法,
     * 在这个方法中可以拿到响应流,然后进行处理,这个过程就是变读边处理,不会导致内存溢出
     */
    String result = restTemplate.execute(url,
            HttpMethod.GET,
            null,
            new ResponseExtractor<String>() {
    
    
                @Override
                public String extractData(ClientHttpResponse response) throws IOException {
    
    
                    System.out.println("状态:"+response.getStatusCode());
                    System.out.println("头:"+response.getHeaders());
                    //获取响应体流
                    InputStream body = response.getBody();
                    //处理响应体流
                    String content = IOUtils.toString(body, "UTF-8");
                    return content;
                }
            }, new HashMap<>());

    System.out.println(result);
}

3.6. Transfer header

interface code

@GetMapping("/test/header")
@ResponseBody
public Map<String, List<String>> header(HttpServletRequest request) {
    
    
    Map<String, List<String>> header = new LinkedHashMap<>();
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
    
    
        String name = headerNames.nextElement();
        Enumeration<String> values = request.getHeaders(name);
        List<String> list = new ArrayList<>();
        while (values.hasMoreElements()) {
    
    
            list.add(values.nextElement());
        }
        header.put(name, list);
    }
    return header;
}

Use the RestTemplate to call the interface, and pass the data in the request header. The code is as follows. Pay attention to the code ①和②. These two places are the key. The HttpHeadersandRequestEntity

  • The request header is placed in the HttpHeaders object
  • RequestEntity: request entity, all requested information can be placed in RequestEntity, such as body part, header, request method, url and other information
@Test
public void test8() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/header";
    //①:请求头放在HttpHeaders对象中
    MultiValueMap<String, String> headers = new HttpHeaders();
    headers.add("header-1", "V1");
    headers.add("header-2", "Spring");
    headers.add("header-2", "SpringBoot");
    //②:RequestEntity:请求实体,请求的所有信息都可以放在RequestEntity中,比如body部分、头、请求方式、url等信息
    RequestEntity requestEntity = new RequestEntity(
            null, //body部分数据
            headers, //头
            HttpMethod.GET,//请求方法
            URI.create(url) //地址
    );
    ResponseEntity<Map<String, List<String>>> responseEntity = restTemplate.exchange(requestEntity,
            new ParameterizedTypeReference<Map<String, List<String>>>() {
    
    
            });
    Map<String, List<String>> result = responseEntity.getBody();
    System.out.println(result);
}

output

{
    
    accept=[application/json, application/*+json], header-1=[V1], header-2=[Spring, SpringBoot], user-agent=[Java/1.8.0_121], host=[localhost:8080], connection=[keep-alive]}

3.7. Comprehensive case: dynamic parameters including header and url

interface

@GetMapping("/test/getAll/{path1}/{path2}")
@ResponseBody
public Map<String, Object> getAll(@PathVariable("path1") String path1,
                                  @PathVariable("path2") String path2,
                                  HttpServletRequest request) {
    
    
    Map<String, Object> result = new LinkedHashMap<>();
    result.put("path1", path1);
    result.put("path2", path2);
    //头
    Map<String, List<String>> header = new LinkedHashMap<>();
    Enumeration<String> headerNames = request.getHeaderNames();
    while (headerNames.hasMoreElements()) {
    
    
        String name = headerNames.nextElement();
        Enumeration<String> values = request.getHeaders(name);
        List<String> list = new ArrayList<>();
        while (values.hasMoreElements()) {
    
    
            list.add(values.nextElement());
        }
        header.put(name, list);
    }
    result.put("header", header);
    return result;
}

As follows, use the RestTemplate to call the interface, GET method, pass the dynamic parameters in the header and path.

@Test
public void test9() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/getAll/{path1}/{path2}";
    //①:请求头
    MultiValueMap<String, String> headers = new HttpHeaders();
    headers.add("header-1", "V1");
    headers.add("header-2", "Spring");
    headers.add("header-2", "SpringBoot");
    //②:url中的2个参数
    Map<String, String> uriVariables = new HashMap<>();
    uriVariables.put("path1", "v1");
    uriVariables.put("path2", "v2");
    //③:HttpEntity:HTTP实体,内部包含了请求头和请求体
    HttpEntity requestEntity = new HttpEntity(
        null,//body部分,get请求没有body,所以为null
        headers //头
    );
    //④:使用exchange发送请求
    ResponseEntity<Map<String, Object>> responseEntity = restTemplate.exchange(
        url, //url
        HttpMethod.GET, //请求方式
        requestEntity, //请求实体(头、body)
        new ParameterizedTypeReference<Map<String, Object>>() {
    
    
        },//返回的结果类型
        uriVariables //url中的占位符对应的值
    );
    Map<String, Object> result = responseEntity.getBody();
    System.out.println(result);
}

output

{
    
    path1=v1, path2=v2, header={
    
    accept=[application/json, application/*+json], header-1=[V1], header-2=[Spring, SpringBoot], user-agent=[Java/1.8.0_121], host=[localhost:8080], connection=[keep-alive]}}

4. POST request

4.1. Three common types of post requests

The Content-Type in the http request header is used to specify the type of request, there are 3 common types

Content-Type illustrate
application/x-www-form-urlencoded The common form form on the page is of this type when submitted. The elements in the form will be spliced ​​according to the name and value, and then connected with &, the format is: p1=v1&p2=v2&p3=v3, and then encoded by urlencoded and thrown in the body send in
multipart/form-data This format is used when uploading files in the form on the page
application/json Convert the sent data to json format, throw it in the body of the http request and send it, and the back-end interface usually uses @RequestBody with the object to receive it.

Let's look at the case of this method.

4.2. Ordinary form request

Common forms default to application/x-www-form-urlencoded type requests.

interface code

@PostMapping("/test/form1")
@ResponseBody
public BookDto form1(BookDto bookDto) {
    
    
    return bookDto;
}

Use the RestTemplate to call the interface

@Test
public void test10() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form1";
    //①:表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>
    MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
    //调用add方法填充表单数据(表单名称:值)
    body.add("id","1");
    body.add("name","SpringMVC系列");
    //②:发送请求(url,请求体,返回值需要转换的类型)
    BookDto result = restTemplate.postForObject(url, body, BookDto.class);
    System.out.println(result);
}

If you want to carry header information, the code is as follows

@Test
public void test11() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form1";
    //①:表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>
    MultiValueMap<String, String> body = new LinkedMultiValueMap<>();
    //调用add方法放入表单元素(表单名称:值)
    body.add("id","1");
    body.add("name","SpringMVC系列");
    //②:请求头
    HttpHeaders headers = new HttpHeaders();
    //调用set方法放入请求头
    headers.set(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);
    //③:请求实体:包含了请求体和请求头
    HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(body, headers);
    //④:发送请求(url,请求实体,返回值需要转换的类型)
    BookDto result = restTemplate.postForObject(url, httpEntity, BookDto.class);
    System.out.println(result);
}

4.3. Upload local files

The Content-Type of the uploaded file is multipart/form-data.

The interface is as follows, upload and upload a single file, the return value is a Map type, which is a generic type

@PostMapping(value = "/test/form2")
@ResponseBody
public Map<String, String> form2(@RequestParam("file1") MultipartFile file1) {
    
    
    Map<String, String> fileMetadata = new LinkedHashMap<>();
    fileMetadata.put("文件名", file1.getOriginalFilename());
    fileMetadata.put("文件类型", file1.getContentType());
    fileMetadata.put("文件大小(byte)", String.valueOf(file1.getSize()));
    return fileMetadata;
}

Use RestTemplate to call the interface. The files uploaded by the following code mainly org.springframework.core.io.Resourceneed to be packaged. There are 3 commonly used [FileSystemResource, InputStreamResource, ByteArrayResource]. In this case, we use FileSystemResource to upload local files, and the other 2 types (InputStreamResource, ByteArrayResource) The usage is quite special, see the next case.

@Test
public void test12() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form2";
    //①:表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>
    MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
    //调用add方法放入表单元素(表单名称:值)
    //②:文件对应的类型,需要是org.springframework.core.io.Resource类型的,常见的有[FileSystemResource、InputStreamResource、ByteArrayResource]
    body.add("file1", new FileSystemResource(".\\src\\main\\java\\com\\javacode2018\\springmvc\\chat16\\dto\\UserDto.java"));
    //③:头
    HttpHeaders headers = new HttpHeaders();
    headers.add("header1", "v1");
    headers.add("header2", "v2");
    //④:请求实体
    RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
    //⑤:发送请求(请求实体,返回值需要转换的类型)
    ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange(
        requestEntity,
        new ParameterizedTypeReference<Map<String, String>>() {
    
    
        });
    Map<String, String> result = responseEntity.getBody();
    System.out.println(result);
}

4.4. Upload files by stream or byte array

Sometimes, the uploaded file is in the form of stream or byte array, then InputStreamResource and ByteArrayResource need to be used. **Note:** When using these two methods, you need to rewrite 2 methods, otherwise the upload will fail

  • getFilename: file name
  • contentLength: length
@Test
public void test13() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form2";
    //①:表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>
    MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
    /**
     * ②:通过流的方式上传文件,流的方式需要用到InputStreamResource类,需要重写2个方法
     * getFilename:文件名称
     * contentLength:长度
     */
    InputStream inputStream = RestTemplateTest.class.getResourceAsStream("/1.txt");
    InputStreamResource inputStreamResource = new InputStreamResource(inputStream) {
    
    
        @Override
        public String getFilename() {
    
    
            return "1.txt";
        }

        @Override
        public long contentLength() throws IOException {
    
    
            return inputStream.available();
        }
    };
    body.add("file1", inputStreamResource);
    //③:头
    HttpHeaders headers = new HttpHeaders();
    headers.add("header1", "v1");
    headers.add("header2", "v2");
    //④:请求实体
    RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
    //⑤:发送请求(请求实体,返回值需要转换的类型)
    ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange(
            requestEntity,
            new ParameterizedTypeReference<Map<String, String>>() {
    
    
            });
    Map<String, String> result = responseEntity.getBody();
    System.out.println(result);
}

4.5. Complex forms: multiple common elements + multiple file uploads

interface

/**
 * 复杂的表单:包含了普通元素、多文件
 *
 * @param userDto
 * @return
 */
@PostMapping("/test/form3")
@ResponseBody
public Map<String, String> form3(UserDto userDto) {
    
    
    Map<String, String> result = new LinkedHashMap<>();
    result.put("name", userDto.getName());
    result.put("headImg", userDto.getHeadImg().getOriginalFilename());
    result.put("idImgList", Arrays.toString(userDto.getIdImgList().stream().
                                            map(MultipartFile::getOriginalFilename).toArray()));
    return result;
}

UserDto: Contains multiple elements (name, avatar, multiple ID photos), which can simulate complex forms

public class UserDto {
    
    
    //姓名
    private String name;
    //头像
    private MultipartFile headImg;
    //多张证件照
    private List<MultipartFile> idImgList;

    //get set 省略了...
}

Call this interface with RestTemplate, the code is as follows

@Test
public void test14() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form3";
    //①:表单信息,需要放在MultiValueMap中,MultiValueMap相当于Map<String,List<String>>
    MultiValueMap<String, Object> body = new LinkedMultiValueMap<>();
    body.add("name", "路人");
    body.add("headImg", new FileSystemResource(".\\src\\main\\resources\\1.jpg"));
    //来2张证件照,元素名称一样
    body.add("idImgList", new FileSystemResource(".\\src\\main\\resources\\2.jpg"));
    body.add("idImgList", new FileSystemResource(".\\src\\main\\resources\\3.jpg"));
    //③:头
    HttpHeaders headers = new HttpHeaders();
    headers.add("header1", "v1");
    headers.add("header2", "v2");
    //④:请求实体
    RequestEntity<MultiValueMap<String, Object>> requestEntity = new RequestEntity<>(body, headers, HttpMethod.POST, URI.create(url));
    //⑤:发送请求(请求实体,返回值需要转换的类型)
    ResponseEntity<Map<String, String>> responseEntity = restTemplate.exchange(
            requestEntity,
            new ParameterizedTypeReference<Map<String, String>>() {
    
    
            });
    Map<String, String> result = responseEntity.getBody();
    System.out.println(result);
}

output

{
    
    name=路人, headImg=1.jpg, idImgList=[2.jpg, 3.jpg]}

4.6. Send data in json format: pass java object

interface

/**
 * body中json格式的数据,返回值非泛型
 *
 * @param bookDto
 * @return
 */
@PostMapping("/test/form4")
@ResponseBody
public BookDto form4(@RequestBody BookDto bookDto) {
    
    
    return bookDto;
}

RestTemplate call interface

@Test
public void test15() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form4";
    BookDto body = new BookDto(1, "SpringMVC系列");
    BookDto result = restTemplate.postForObject(url, body, BookDto.class);
    System.out.println(result);
}

output

BookDto{
    
    id=1, name='SpringMVC系列'}

4.7. Send data in json format: pass java object, return value is generic

interface

/**
 * body中json格式的数据,返回值为泛型
 *
 * @param bookDtoList
 * @return
 */
@PostMapping("/test/form5")
@ResponseBody
public List<BookDto> form5(@RequestBody List<BookDto> bookDtoList) {
    
    
    return bookDtoList;
}

Call this interface with RestTemplate, the code is as follows

@Test
public void test16() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form5";
    //①:请求体,发送的时候会被转换为json格式数据
    List<BookDto> body = Arrays.asList(
            new BookDto(1, "SpringMVC系列"),
            new BookDto(2, "MySQL系列"));
    //②:头
    HttpHeaders headers = new HttpHeaders();
    headers.add("header1", "v1");
    headers.add("header2", "v2");
    //③:请求实体
    RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url));
    //④:发送请求(请求实体,返回值需要转换的类型)
    ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange(
            requestEntity,
            new ParameterizedTypeReference<List<BookDto>>() {
    
    
            });
    //⑤:获取结果
    List<BookDto> result = responseEntity.getBody();
    System.out.println(result);
}

output

[BookDto{
    
    id=1, name='SpringMVC系列'}, BookDto{
    
    id=2, name='MySQL系列'}]

4.8. Send data in json string format

The bodies of the above two json cases are all java objects, and the RestTemplate is automatically equipped with Content-Type=application/json by default

But if the value of the body is a json format string, you need to specify Content-Type=application/json in the header when calling, as follows:

@Test
public void test17() {
    
    
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://localhost:8080/chat16/test/form5";
    //①:请求体为一个json格式的字符串
    String body = "[{\"id\":1,\"name\":\"SpringMVC系列\"},{\"id\":2,\"name\":\"MySQL系列\"}]";
    /**
     * ②:若请求体为json字符串的时候,需要在头中设置Content-Type=application/json;
     * 若body是普通的java类的时候,无需指定这个,RestTemplate默认自动配上Content-Type=application/json
     */
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_JSON);
    //③:请求实体(body,头、请求方式,uri)
    RequestEntity requestEntity = new RequestEntity(body, headers, HttpMethod.POST, URI.create(url));
    //④:发送请求(请求实体,返回值需要转换的类型)
    ResponseEntity<List<BookDto>> responseEntity = restTemplate.exchange(
            requestEntity,
            new ParameterizedTypeReference<List<BookDto>>() {
    
    
            });
    //⑤:获取结果
    List<BookDto> result = responseEntity.getBody();
    System.out.println(result);
}

output

[BookDto{
    
    id=1, name='SpringMVC系列'}, BookDto{
    
    id=2, name='MySQL系列'}]

5. DELETE, PUT, OPTION requests

5.1. DELETE request

public void delete(String url, Object... uriVariables);
public void delete(String url, Map<String, ?> uriVariables);
public void delete(URI url);

5.2. PUT request

The PUT request is similar to the POST request, just change the type to PUT.

5.3. OPTIONS request

The OPTIONS request is used to detect which http methods the interface supports

public Set<HttpMethod> optionsForAllow(String url, Object... uriVariables);
public Set<HttpMethod> optionsForAllow(String url, Map<String, ?> uriVariables);
public Set<HttpMethod> optionsForAllow(URI url);

6. Integrated HttpClient

RestTemplate internally uses the HttpURLConnection that comes with jdk to send requests by default, and its performance is not too prominent. It can be replaced by httpclient or okhttp. Let's first look at how to replace it with HttpClient.

Import maven configuration

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.7</version>
</dependency>

Specify HttpClient configuration when creating RestTemplate, the code is as follows

public HttpClient httpClient() {
    
    
    HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
    try {
    
    
        //设置信任ssl访问
        SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
        httpClientBuilder.setSSLContext(sslContext);
        HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
        SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                // 注册http和https请求
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", sslConnectionSocketFactory).build();

        //使用Httpclient连接池的方式配置(推荐),同时支持netty,okHttp以及其他http框架
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        // 最大连接数
        poolingHttpClientConnectionManager.setMaxTotal(1000);
        // 同路由并发数
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
        //配置连接池
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
        // 重试次数
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(0, true));
        //设置默认请求头
        List<Header> headers = new ArrayList<>();
        httpClientBuilder.setDefaultHeaders(headers);
        return httpClientBuilder.build();
    } catch (Exception e) {
    
    
        throw new RuntimeException(e);
    }
}

public ClientHttpRequestFactory clientHttpRequestFactory() {
    
    
    HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient());
    // 连接超时(毫秒),这里设置10秒
    clientHttpRequestFactory.setConnectTimeout(10 * 1000);
    // 数据读取超时时间(毫秒),这里设置60秒
    clientHttpRequestFactory.setReadTimeout(60 * 1000);
    // 从连接池获取请求连接的超时时间(毫秒),不宜过长,必须设置,比如连接不够用时,时间过长将是灾难性的
    clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
    return clientHttpRequestFactory;
}

public RestTemplate restTemplate(){
    
    
    //创建RestTemplate的时候,指定ClientHttpRequestFactory
    return new RestTemplate(this.clientHttpRequestFactory());
}

@Test
public void test18() {
    
    
    RestTemplate restTemplate = this.restTemplate();
    String url = "http://localhost:8080/chat16/test/get";
    //getForObject方法,获取响应体,将其转换为第二个参数指定的类型
    BookDto bookDto = restTemplate.getForObject(url, BookDto.class);
    System.out.println(bookDto);
}

7. Integrated okhttp

Import maven configuration

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.3.1</version>
</dependency>

Create RestTemplate

new RestTemplate(new OkHttp3ClientHttpRequestFactory());

Guess you like

Origin blog.csdn.net/ximaiyao1984/article/details/132257845