一、什么是RestTemplate?
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。
调用RestTemplate的默认构造函数,RestTemplate对象在底层通过使用java.net包下的实现创建HTTP 请求,可以通过使用ClientHttpRequestFactory指定不同的HTTP请求方式。
ClientHttpRequestFactory接口主要提供了两种实现方式
一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(既java.net包提供的方式)创建底层的Http请求连接。
一种方式是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的Http服务,使用HttpClient可以配置连接池和证书等信息。
通过使用RestTemplate仅仅只需要写几行代码,就可以完成直接使用httpclient很多行代码的事情,具体见:https://spring.io/blog/2009/03/27/rest-in-spring-3-resttemplate
二、RestTemplate 构造
RestTemplate有三个构造函数:
1.默认构造函数,默认使用SimpleClientHttpRequestFactory,使用JDK自带的java.net包进行网络传输。
2.public RestTemplate(ClientHttpRequestFactory requestFactory)。传入一个ClientHttpRequestFactory,ClientHttpRequestFactory在Spring中的实现有很多个,如HttpComponentsClientHttpRequestFactory,Netty4ClientHttpRequestFactory等,ClientHttpRequestFactory接口的实现类中存在timeout属性等等
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(1000);
requestFactory.setReadTimeout(1000);
RestTemplate restTemplate = new RestTemplate(requestFactory);
可以在springboot的某个自定义的configure类中的restTemplate 构造方法上添加
@Bean
RestTemplate restTemplate(){
SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
requestFactory.setConnectTimeout(1000);
requestFactory.setReadTimeout(1000);
RestTemplate restTemplate = new RestTemplate(requestFactory);
return restTemplate;
}
将RestTemplate 实例注入spring容器中。
调用时可以通过:
@Autowired
private RestTemplate restTemplate;
来使用。
3.public RestTemplate(List> messageConverters),使用SpringMvc的应该对HttpMessageConverter很熟悉了,RestTemplate默认会给我们设置好常用的HttpMessageConverter,一般很少使用到这个构造方法。
三、RestTemplate 对HTTP Method的支持
四、RestTemplate 使用实例
4.1、GET请求:
public <T> T getForObject(String url, Class<T> responseType, Object... urlVariables) throws RestClientException
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> urlVariables) throws RestClientException
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException
使用RestTemplate,对GET请求可以通过如下下面的二种方法实现:
(一)、getForEntity函数
该方法返回ResponseEntity,该对象是Spring对Http请求响应的封装,其中主要存储了HTTP的几个重要元素,比如说HTTP请求码的枚举对象HttpStatus(404,405,500等错误码),它的父类事HttpEntity中还存储着HTTP请求的头信息对象HttpHeaders以及泛型类型的请求体对象。
getForEntity有三种重载的方法:
第一种方式:
@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
该方法提供了三个参数,url就是请求的地址,responseType返回的数据类型,uriVariables为url中参数绑定。会顺序对应url中占位符定义的数字顺序。
第二种方式:
@Override
public <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
url参数和responseType和上面一致,只有第三个参数uriVariables是不同的类型,这里使用了Map<String, ?>类型,所以使用该方法进行参数绑定时需要在占位符中指定Map中参数的key值,我们需要向map中put
一个key为id和name的值来对应{id}和{name}
第三种方式:
@Override
public <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}
该方法使用URI对象来替代之前的url和urlVariables参数来指定访问地址和参数来指定访问地址和参数绑定。URI是JDK java.net包下的一个类,它表示一个统一的资源标识符引用.
示例:
Controller类:
/**
* projectName: quna-app
* fileName: UserController.java
* packageName: com.mongodb.fendo.controller
* date: 2018-04-13 13:16
* copyright(c) 上海xxxxx有限公司
*/
package com.mongodb.fendo.controller;
import com.mongodb.fendo.entity.UserEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @version: V1.0
* @author: fendo
* @className: UserController
* @packageName: com.mongodb.fendo.controller
* @description: 用户Controller
* @data: 2018-04-13 13:16
**/
@Controller
@RequestMapping(value = "/user")
public class UserController {
@GetMapping("getNameById")
@ResponseBody
public String getNameById(@RequestParam int id, @RequestParam String name){
if(1==id && "fendo".equals(name)){
return "name="+name+",age="+27;
}else {
return "name="+name;
}
}
@GetMapping("/getUserById")
@ResponseBody
public UserEntity getUserEntityById(@RequestParam int id,@RequestParam String name){
UserEntity user = new UserEntity();
if(id == 1 && "fendo".equals(name)){
user.setId("1");
user.setName("fendo");
user.setAge("21");
}
if(id ==2 && "arm".equals(name)){
user.setId("2");
user.setName("arm");
user.setAge("24");
}
return user;
}
@GetMapping("/getUserByname")
@ResponseBody
public String getUserByname(@RequestParam String name){
if("fendo".equals(name)){
return "123456798";
}else{
return "哈哈";
}
}
}
测试类:
package com.mongodb.fendo;
import com.alibaba.fastjson.JSONObject;
import com.mongodb.fendo.entity.UserEntity;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponents;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import java.util.HashMap;
import java.util.Map;
/**
* @version V1.0
* @Author fendo
* @ClassName RestTemplateTest
* @PackageName com.mongodb.fendo
* @Description RestTemplate测试类
* @Data 2018-04-15 0:07
**/
@RunWith(SpringRunner.class)
@SpringBootTest
public class RestTemplateTest {
@Autowired
RestTemplate restTemplate;
@Test
public void getNameById(){
int id = 2;
String name = "qqqqq";
String username = restTemplate.getForEntity("http://localhost:8088/user/getNameById?id={1}&name={2}",String.class,new Object[]{id,name}).getBody();
System.out.println(username);
}
@Test
public void getUserEntityById(){
Map<String,Object> params = new HashMap<>();
params.put("id",1);
params.put("name","fendo");
UserEntity user = restTemplate.getForEntity("http://localhost:8088/user/getUserById?id={id}&name={name}",UserEntity.class,params).getBody();
System.out.println(user.toString());
}
@Test
public void getUserByname(){
String name = "fendo";
UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://localhost:8088/user/getUserByname?name={name}").build().expand(name).encode();
URI uri = uriComponents.toUri();
String response = restTemplate.getForEntity(uri,String.class).getBody();
System.out.println(response);
}
}
(二)、getForObject函数
该方法可以理解对getForEntity的进一步封装,它通过HttpMessageConverterExtractor对http的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。
@Override
public <T> T getForObject(String url, Class<T> responseType, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> T getForObject(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> T getForObject(URI url, Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = acceptHeaderRequestCallback(responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.GET, requestCallback, responseExtractor);
}
测试类:
@Test
public void Test(){
String name = "fendo";
String userEntity = restTemplate.getForObject("http://localhost:8088/user/getUserByname?name={name}",String.class,new Object[]{name});
System.out.println(userEntity);
Map<String,Object> params = new HashMap<>();
params.put("id",1);
params.put("name",name);
UserEntity user = restTemplate.getForObject("http://localhost:8088/user/getUserById?id={id}&name={name}",UserEntity.class,params);
System.out.println(user.toString());
UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://localhost:8088/user/getUserByname?name={name}").build().expand(name).encode();
URI uri = uriComponents.toUri();
String response = restTemplate.getForObject(uri,String.class);
System.out.println(response);
}
4.2、POST请求
public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException
public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException
在RestTemplate中,对post请求时可以通过如下三个方法进行调用实现:
第一种:postForEntity函数
其包含三种重载的方法。第一个重载方法和第二个重载函数的uriVariables参数都用来对url中的参数进行绑定使用,responseType是返回对象的类型定义。增加的request参数,该参数可以是一个普通对象,也可以是一个HttpEntity对象。如果是一个普通对象,而非HttpEntity对象的时候,RestTemplate会将普通对象转换成HttpEntity对象。其中Object中不仅包含了body内容,也包含了header的内容。
@Override
public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
ResponseExtractor<ResponseEntity<T>> responseExtractor = responseEntityExtractor(responseType);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}
@PostMapping("/queryUser1")
@ResponseBody
public List<String> queryUser1(@RequestBody UserEntity user){
String id = user.getId();
if("1".equals(id)){
return Arrays.asList("fendo,arm".split(","));
}else{
return Arrays.asList("admin.sfe".split(","));
}
}
@PostMapping("/queryUser2")
@ResponseBody
public String queryUser2(@RequestParam String id,@RequestParam String name){
if("1".equals(id)){
return "user is " + name;
}
return "user is not exist";
}
@Test
public void TEST_POST(){
UserEntity userEntity = new UserEntity();
userEntity.setName("fendo");
userEntity.setAddress("北京");
userEntity.setAge("23");
userEntity.setCreate_date(new Date());
userEntity.setEmail("2312892206");
userEntity.setSex(1);
userEntity.setUser_id("123456789" + Math.random());
UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://localhost:8088/user/queryUser1").build();
URI uri = uriComponents.toUri();
List<String> stringList = restTemplate.postForEntity(uri,userEntity,List.class).getBody();
for (int i = 0; i < stringList.size(); i++) {
System.out.println(stringList);
}
HttpHeaders headers = new HttpHeaders();
MultiValueMap<String, Object> parammap = new LinkedMultiValueMap<>();
parammap.add("id","1");
parammap.add("name","fendo");
HttpEntity<Map> entity = new HttpEntity<>(parammap,headers);
String result = restTemplate.postForEntity("http://localhost:8088/user/queryUser2",entity,String.class).getBody();
System.out.println(result);
}
第二种:getForObject函数
该方法可以理解为对getForEntity的进一步封装,它通过org.springframework.web.client.HttpMessageConverterExtractor对HTTP的请求响应体body内容进行对象转换,实现请求直接返回包装好的对象内容。
@PostMapping("/getUserEntity")
@ResponseBody
public UserEntity getUserEntity(UserEntity userEntity){
System.out.println(userEntity.toString());
UserEntity user = new UserEntity();
user.setId("1");
user.setName("fendo");
user.setAge("21");
return user;
}
@Test
public void Test_m(){
HttpHeaders headers = new HttpHeaders();
MultiValueMap<String, Object> parammap = new LinkedMultiValueMap<>();
parammap.add("id", 1);
parammap.add("name","fendo");
HttpEntity<Map> entity = new HttpEntity<>(parammap,headers);
UserEntity user = restTemplate.postForObject("http://localhost:8088/user/getUserEntity",entity,UserEntity.class);
System.out.println(user.toString());
}
postForObject函数也提供了三个重载的方法
@Override
public <T> T postForObject(String url, Object request, Class<T> responseType, Object... uriVariables)
throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> T postForObject(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters(), logger);
return execute(url, HttpMethod.POST, requestCallback, responseExtractor, uriVariables);
}
@Override
public <T> T postForObject(URI url, Object request, Class<T> responseType) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request, responseType);
HttpMessageConverterExtractor<T> responseExtractor =
new HttpMessageConverterExtractor<T>(responseType, getMessageConverters());
return execute(url, HttpMethod.POST, requestCallback, responseExtractor);
}
第三种: 使用postForLocation函数
URI uri = restTemplate.postForLocation("http://localhost:8080/xxxx",user);
System.out.println("uri=="+uri);
@Override
public URI postForLocation(String url, Object request, Object... uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request);
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
return headers.getLocation();
}
@Override
public URI postForLocation(String url, Object request, Map<String, ?> uriVariables) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request);
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor(), uriVariables);
return headers.getLocation();
}
@Override
public URI postForLocation(URI url, Object request) throws RestClientException {
RequestCallback requestCallback = httpEntityCallback(request);
HttpHeaders headers = execute(url, HttpMethod.POST, requestCallback, headersExtractor());
return headers.getLocation();
}
postForEntity返回ResponseEntity,与getForEntity相同
postForLocation返回URI,返回的是response header中的location信息,一般用于资源定位。