Spring 的 RestTemplate 使用
Contents
相关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
这种是纯 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()
这个.