相关POM依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.apache.httpcomponents</groupId>
  <artifactId>httpclient</artifactId>
  <version>4.5.1</version>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-annotations</artifactId>
</dependency>
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.5</version>
</dependency>

创建 Bean 及相关设置

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate(getClientHttpRequestFactory());
      	// 处理中文
        restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        restTemplate.getMessageConverters().add(new FormHttpMessageConverter());
        restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
      	restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(new Gson()));
        log.info("message converters {}", restTemplate.getMessageConverters());
        return restTemplate;
    }

    private ClientHttpRequestFactory getClientHttpRequestFactory() {
        int timeout = 5000;
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(timeout);
        return clientHttpRequestFactory;
    }

GET

        String body;
        if (value != null) {
            body = value.toString();
        } else {
            body = restTemplate.getForObject("https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={ID}&corpsecret={SECRECT}", String.class, request.getCorpid(), request.getCorpsecret());
            log.info("send token http response {}", body);
        }

后面的是 url 的参数. url 中的变量使用 {}, {} 的形式表示.

注: 名字不影响, 只是 {} 中间是一个占位符而已.

POST BODY

String body = restTemplate.postForObject("https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={ACCESS_TOKEN}", jsonBody, String.class, token);

POST JSON BODY

        final TextMsg textMsg = new TextMsg();
        textMsg.setAgentid(agentid);
        TextMsg.TextBean textBean = new TextMsg.TextBean();
        textBean.setContent(text);
        textMsg.setText(textBean);

        final String sendMsgUrl = String.format(SEND_MSG_URL, accessToken.getAccessToken());

        // set headers
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        final HttpEntity<String> entity = new HttpEntity<>(GsonKit.toJSON(textMsg), headers);
        // send request and parse result
        ResponseEntity<String> response = restTemplate.exchange(sendMsgUrl, HttpMethod.POST, entity, String.class);

POST file

https://stackoverflow.com/questions/14738394/making-a-multipart-post-request-with-compressed-jpeg-byte-array-with-spring-for

这种是纯 bytes 内存的方式

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        Resource res = new ByteArrayResource(request.getStream().toByteArray()) {
            @Override
            public String getFilename() throws IllegalStateException {
                return "hello.jpg";
            }
        };
        HttpHeaders imageHeaders = new HttpHeaders();
        imageHeaders.setContentType(MediaType.IMAGE_JPEG);
        HttpEntity<Resource> imageEntity = new HttpEntity<>(res, imageHeaders);
        map.add("file", imageEntity);

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, httpHeaders);
        ResponseEntity<String> result = restTemplate.exchange("http://127.0.0.1:8888/upload", HttpMethod.POST, httpEntity, String.class);

如果直接是文件系统中的文件的方式的话, 则直接提交即可:

        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("file", new FileSystemResource("/tmp/hello.jpg"));

        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
        HttpEntity<MultiValueMap<String, Object>> httpEntity = new HttpEntity<>(map, httpHeaders);
        ResponseEntity<String> result = restTemplate.exchange("http://127.0.0.1:8888/upload", HttpMethod.POST, httpEntity, String.class);

        final String body = result.getBody();

Post Form

    public void sendText(final int agentId, final String content) {
        final HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        final MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("agentId", agentId+"");
        map.add("content", content);

        final HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
        ResponseEntity<String> response = restTemplate.postForEntity(host + textContext, request, String.class);
        if (response.getStatusCode() == HttpStatus.OK) {
            log.info("send ok {} => {}, {}", agentId, content, response);
        } else {
            log.error("send error {} => {}, {}", agentId, content, response);
        }
    }

注意, 是用: MultiValueMap . 看源码可知:

    @Override
    @SuppressWarnings("unchecked")
    public void write(MultiValueMap<String, ?> map, @Nullable MediaType contentType, HttpOutputMessage outputMessage)
            throws IOException, HttpMessageNotWritableException {

        if (!isMultipart(map, contentType)) {
            writeForm((MultiValueMap<String, String>) map, contentType, outputMessage);
        }
        else {
            writeMultipart((MultiValueMap<String, Object>) map, outputMessage);
        }
    }

当不是 multipart 时, 是 <String, String>.

URL Encode

默认已经处理了. 所以不用特别再处理. 直接传中文字符过去即可.

手动构建 URL

        try {
            String url = UriComponentsBuilder.fromUriString("http://localhost:8080/t99")
                    .queryParam("hello", "world")
                    .queryParam("data", "你好")
                    .build(false).toUriString();
            System.out.println("real url => " + url);
            String body = rest.getForObject(url, String.class, param);
            System.out.println(body);
        } catch (Exception e) {
            e.printStackTrace();
        }

注意, 因为 rest.getForObject 等方法中, 会自动对 URL 进行 encode, 所以, 在我们构建的时候, 应该是 raw 原始的字符串. 即 .build(false).toUriString() 这个.

参考

Using-RestTemplate