目录
为什么使用?因为它简化了HTTP请求以及处理响应的过程,并且支持REST而且线程安全,无需手动关闭连接;
怎么用?
一、准备
环境: Spring 3.0 (及以上)
测试对象:
//测试对象
public class User {
private String name;
public User() {
}
public User(String name) {
this.name = name;
}
//get set
}
//嵌套对象NestedUser
public class NestedUser {
private List<User> users;
public NestedUser() {
}
public NestedUser(List<User> users) {
this.users = users;
}
//get set
}
二、GET请求
示例1:
RestTemplate restTemplate = new RestTemplate();
//get请求传参方式 占位符
Map<String, String> param = new HashMap<>();
param.put("name", "张三丰");
String url = "http://localhost:8926/demo/test.do";
User forObject = restTemplate.getForObject(url + "?name={name}", User.class, param);
System.out.println(forObject);
示例2:
RestTemplate restTemplate = new RestTemplate();
//get请求传参方式 占位符
Map<String, String> param = new HashMap<>();
param.put("name", "张三丰");
String url = "http://localhost:8926/demo/test.do";
//getForEntity相比getForObject返回的信息内容更加丰富一些
ResponseEntity<User> forEntity = restTemplate.getForEntity(url+"?name={name}",
User.class, param);
System.out.println(forObject);
示例1VS示例2:
示例2的返回类型为ResponseEntity,其中包含了哪些内容呢,我们看下:

示例3:
String url = "http://localhost:8926/demo/test.do";
Map<String, String> param = new HashMap<>();
param.put("name", "张三丰");
HttpEntity<Map> entity= new HttpEntity<>(null);
//get请求传参方式 占位符
ResponseEntity<User> exchange = restTemplate.exchange(url + "?name={name}", HttpMethod.GET, entity, User.class,param);
System.out.println(exchange)
小结:
1.示例3与1、2相比,它可以指定请求方式,请求头
2.GET请求的参数传递除了可以在MAP中之外 ,还可以这样:
String url = "http://localhost:8926/demo/test.do";
User forObject = restTemplate.getForObject(url + "?name={name}", User.class, "张三丰");
//或者
String uri= URI.create("http://localhost:8926/demo/test.do?name=张三丰").toString();
ResponseEntity<User> forEntity = restTemplate.getForEntity(uri, User.class);
三、POST请求
示例1:
//Client:注意这里是LinkedMultiValueMap
String url = "http://localhost:8926/demo/test.do";
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("name", "john");
ResponseEntity<User> userResponseEntity1 = restTemplate.postForEntity(url, map, User.class);
System.out.println(userResponseEntity1);
//Server:
@RequestMapping("test")
public User test(User user, HttpServletRequest request){
return user;
}
示例2:
//注意:这种方式Content-Type是application/json;charset=UTF-8,所以在服务端接收的时候
//必须要以JSON接收,否则无法接收到参数值,以Spring-MVC为例,可以在接收参数时以@RequestBody修饰
//Client:
String url = "http://localhost:8926/demo/test.do";
User user = new User();
user.setName("john");
ResponseEntity<User> userResponseEntity = restTemplate.postForEntity(url, user, User.class);
//Server:
@RequestMapping("test")
public User test(@RequestBody User user, HttpServletRequest request){
return user;
}
关于postForLocation:
该方法返回重定向后的路径:
示例3:
//Client:得到的uri为querySup.do?name=john
String url = "http://localhost:8926/demo/test.do";
URI uri = restTemplate.postForLocation(url, null);
//Server:
@RequestMapping("test")
public String test(HttpServletRequest request){
return "redirect:querySup.do?name=john";
}
Post的postObject、exchange的使用与GET方式没有太大差异,就不再举例了;
四、向服务器发送List对象
方式1:
//Client:发送List,会以JSON传到Server
String url = "http://localhost:8926/demo/test.do";
List<User> users = Arrays.asList(new User("张三丰"), new User("猪小明"));
ResponseEntity<NestedUser> nested = restTemplate.postForEntity(url, users, NestedUser.class);
System.out.println(nested);
//Server:需要@RequestBody修饰,否则无法接收到参数
@RequestMapping("test")
public NestedUser test(@RequestBody ArrayList<User> uesr, HttpServletRequest request){
return new NestedUser(uesr);
}
五、接收复杂返回值
普通POJO对象在上文中已经介绍过了,如果是一些复杂的对象怎么办呢?
A.接收服务端的List对象
//Client:
//接收List<User> 注意map类型
String url = "http://localhost:8926/demo/test.do";
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("name", "john");
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<>(map);
ResponseEntity<List<User>> userResponseEntity = restTemplate.exchange(url, HttpMethod.POST, entity, new ParameterizedTypeReference<List<User>>() {});
System.out.println(userResponseEntity);
//Server:
@RequestMapping("test")
public List<User> test(User uesr, HttpServletRequest request){
return Arrays.asList(uesr);
}
B.嵌套对象
//Client:接收 注意map类型
String url = "http://localhost:8926/demo/test.do";
LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("name", "john");
HttpEntity<LinkedMultiValueMap<String, Object>> entity = new HttpEntity<>(map);
ResponseEntity<NestedUser> nestedUser = restTemplate.exchange(url, HttpMethod.POST, entity, NestedUser.class);
System.out.println(nestedUser);
//或者简洁一些
NestedUser nestedUser = restTemplate.postForObject(url,map, NestedUser.class);
System.out.println(nestedUser);
//Server:
@RequestMapping("test")
public List<User> test(User uesr, HttpServletRequest request){
return Arrays.asList(uesr);
}
六、两个连接工厂
RestTemplate 还有一个连接工厂是HttpComponentsClientHttpRequestFactory与SimpleClientHttpRequestFactory 不同的是该连接工厂内部维护了一个连接池,套用其他的一些说法"它不仅可以控制能够建立的连接数还能细粒度的控制到某个 server 的连接数,非常方便",因此在功能上可能比SimpleClientHttpRequestFactory 更加强大一些,所以一般来说使用HttpComponentsClientHttpRequestFactory就可以了;
七、设置超时
关于超时:RestTemplate默认使用的连接工厂是 SimpleClientHttpRequestFactory,其默认的配置由HttpURLConnection决定
我们可以通过
-Dsun.net.client.defaultConnectTimeout=TimeoutInMiliSec
-Dsun.net.client.defaultReadTimeout=TimeoutInMiliSec
来更改默认设置,如图:
以上只是修改默认的超时配置,在代码中如何设置呢?
//超时时间设置
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(30 * 1000);
factory.setConnectTimeout(30 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
HttpComponentsClientHttpRequestFactory的超时的设置方法与其类似
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(30 * 1000);
factory.setConnectTimeout(30 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
八、设置编码
关于编码的设置有许多方法,我只取了其中的一种:
List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> httpMessageConverter : list) {
if (httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(charSet));
break;
}
}
九、设置代理
SimpleClientHttpRequestFactory的设置方法:
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
RestTemplate restTemplate = new RestTemplate(factory);
String proxyPort = "8888";
String proxyHost = "127.0.0.1";
InetSocketAddress address = new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort));
Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
factory.setProxy(proxy);
restTemplate.setRequestFactory(factory);
HttpComponentsClientHttpRequestFactory的设置方法:
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
RestTemplate restTemplate = new RestTemplate(factory);
String proxyPort = "8888";
String proxyHost = "127.0.0.1";
String proxyUser = "";
String proxyPassword = "";
final int proxyPortNum = Integer.parseInt(proxyPort);
final CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxyHost, proxyPortNum),
new UsernamePasswordCredentials(proxyUser, proxyPassword));
final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder.useSystemProperties();
clientBuilder.setProxy(new HttpHost(proxyHost, proxyPortNum));
clientBuilder.setDefaultCredentialsProvider(credsProvider);
clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
final CloseableHttpClient client = clientBuilder.build();
factory.setHttpClient(client);
restTemplate.setRequestFactory(factory);
十、完整设置
private RestTemplate templateCommon(String charSet) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(30 * 1000);
factory.setConnectTimeout(30 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
//设置编码
List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> httpMessageConverter : list) {
if (httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(charSet));
break;
}
}
return restTemplate;
}
private RestTemplate templateProxy(String charSet) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setReadTimeout(30 * 1000);
factory.setConnectTimeout(30 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
//设置编码
List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> httpMessageConverter : list) {
if (httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(charSet));
break;
}
}
//设置代理
String proxyPort = "8888";
String proxyHost = "127.0.0.1";
String proxyUser = "";
String proxyPassword = "";
final int proxyPortNum = Integer.parseInt(proxyPort);
final CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(proxyHost, proxyPortNum), new UsernamePasswordCredentials(proxyUser, proxyPassword));
final HttpClientBuilder clientBuilder = HttpClientBuilder.create();
clientBuilder.useSystemProperties();
clientBuilder.setProxy(new HttpHost(proxyHost, proxyPortNum));
clientBuilder.setDefaultCredentialsProvider(credsProvider);
clientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
final CloseableHttpClient client = clientBuilder.build();
factory.setHttpClient(client);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
private RestTemplate templateSimple(String charSet) {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
factory.setReadTimeout(30 * 1000);
factory.setConnectTimeout(30 * 1000);
RestTemplate restTemplate = new RestTemplate(factory);
//设置编码
List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
for (HttpMessageConverter<?> httpMessageConverter : list) {
if (httpMessageConverter instanceof StringHttpMessageConverter) {
((StringHttpMessageConverter) httpMessageConverter).setDefaultCharset(Charset.forName(charSet));
break;
}
}
String proxyPort = "8888";
String proxyHost = "127.0.0.1";
InetSocketAddress address = new InetSocketAddress(proxyHost, Integer.parseInt(proxyPort));
Proxy proxy = new Proxy(Proxy.Type.HTTP, address);
factory.setProxy(proxy);
restTemplate.setRequestFactory(factory);
return restTemplate;
}
十一、官方说明
As of 5.0, the non-blocking, reactive
org.springframework.web.reactive.client.WebClient
offers a modern alternative to theRestTemplate
with efficient support for both sync and async, as well as streaming scenarios. TheRestTemplate
will be deprecated in a future version and will not have major new features added going forward. See the WebClient section of the Spring Framework reference documentation for more details and example code.
就是说从Spring 5.0起,非阻塞、响应式的WebClient为RestTemplate
提供了一个新颖的替代选择,它同时对异步、同步以及流场景的应用提供了高效的支持。RestTemplate在未来的版本中会被废弃并且以后不会再增加重要的特性。
参考资料
Get and Post Lists of Objects with RestTemplate
Java RestTemplate post请求传递参数遇到的坑
RestTemplate and Proxy Authentication explained