RestTemplate使用初探

本文介绍了Spring RestTemplate的使用,它简化HTTP请求及响应处理,支持REST且线程安全。详细说明了准备工作、GET和POST请求、发送List对象、接收复杂返回值等操作,还提及连接工厂、超时、编码、代理设置,最后指出Spring 5.0起WebClient是新颖替代选择。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

目录

一、准备

二、GET请求

三、POST请求

四、向服务器发送List对象

五、接收复杂返回值 

六、两个连接工厂

七、设置超时

八、设置编码

九、设置代理

十、完整设置

十一、官方说明

参考资料


为什么使用?因为它简化了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,其中包含了哪些内容呢,我们看下:

forEntity包含的内容
forEntity返回的内容

示例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

来更改默认设置,如图:

VM设置

 

以上只是修改默认的超时配置,在代码中如何设置呢?

//超时时间设置
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 the RestTemplate with efficient support for both sync and async, as well as streaming scenarios. The RestTemplate 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在未来的版本中会被废弃并且以后不会再增加重要的特性。

参考资料

The Guide to RestTemplate

Get and Post Lists of Objects with RestTemplate

谁说 HTTP GET 就不能通过 Body 来发送数据呢

Content-Type 详解

Java RestTemplate post请求传递参数遇到的坑

RestTemplate and Proxy Authentication explained

Tip:通过Fiddler抓取Java HttpClient的HTTP包

为什么要进行URL编码

中文乱码的种类

如何在HttpServletRequest中取body

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值