Web开发 之使用Spring提供的RestTemplate访问服务

RestTemplate简介

RestTemplate是Spring3.0后开始提供的用于访问 Rest 服务的轻量级客户端,相较于传统的HttpURLConnection、Apache HttpClient、OkHttp等框架,RestTemplate大大简化了发起HTTP请求以及处理响应的过程。

RestTemplate只是对其它Rest客户端的一个封装,本身并没有自己的实现。
RestTemplate默认实现是HttpURLConnection,这是JDK自带的REST客户端实现。
引入哪种Http客户端的Jar包,就会使用哪种Http客户端的实现。

相关Http客户端Maven依赖

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.4.0</version>
</dependency>

<dependency>
    <groupId>org.apache.httpcomponents</groupId>
    <artifactId>httpclient</artifactId>
    <version>4.5.11</version>
</dependency>

RestTemplate配置

RestTemplate包含以下几个部分:

  • HttpMessageConverter 对象转换器
  • ClientHttpRequestFactory 默认是 JDK的HttpURLConnection
  • ResponseErrorHandler 异常处理
  • ClientHttpRequestInterceptor 请求拦截器

在这里插入图片描述

使用HttpClient作为实现

首先需要引入HttpClient的Maven依赖。

import org.apache.http.client.HttpClient;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.ssl.SSLContextBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestTemplate;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

@Configuration
public class RestClientConfig {

    private static final Logger logger = LoggerFactory.getLogger(RestClientConfig.class);

    // 连接池的最大连接数默认为0
    @Value("${remote.maxTotalConnect:0}")
    private int maxTotalConnect;
    // 单个主机的最大连接数
    @Value("${remote.maxConnectPerRoute:200}")
    private int maxConnectPerRoute;
    // 连接超时默认2s
    @Value("${remote.connectTimeout:2000}")
    private int connectTimeout;
    // 读取超时默认30s
    @Value("${remote.readTimeout:30000}")
    private int readTimeout;

    @Bean
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate();
        restTemplate.setRequestFactory(clientHttpRequestFactory());
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
        // 设置编码格式为UTF-8
        List<HttpMessageConverter<?>> converterList = restTemplate.getMessageConverters();
        HttpMessageConverter<?> converterTarget = null;
        for (HttpMessageConverter<?> item : converterList) {
            if (item.getClass() == StringHttpMessageConverter.class) {
                converterTarget = item;
                break;
            }
        }
        if (converterTarget != null) {
            converterList.remove(converterTarget);
        }
        HttpMessageConverter<?> converter = new StringHttpMessageConverter(StandardCharsets.UTF_8);
        converterList.add(1, converter);
        logger.info("-----restTemplate-----初始化完成");
        return restTemplate;
    }

    @Bean
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        try {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, (arg0, arg1) -> true).build();
            httpClientBuilder.setSSLContext(sslContext);
            HostnameVerifier hostnameVerifier = NoopHostnameVerifier.INSTANCE;
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
            // 注册http和https请求
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();
            // 开始设置连接池
            PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            // 最大连接数
            poolingHttpClientConnectionManager.setMaxTotal(maxTotalConnect);
            // 同路由的并发数,路由是对maxTotal的细分
            poolingHttpClientConnectionManager.setDefaultMaxPerRoute(maxConnectPerRoute);
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)); // 重试次数
            HttpClient httpClient = httpClientBuilder.build();
            // 数据读取超时时间
            HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(httpClient); // httpClient连接配置
            // 连接超时
            clientHttpRequestFactory.setConnectTimeout(connectTimeout);
            // 读取超时
            clientHttpRequestFactory.setReadTimeout(readTimeout);
            // 连接不够用的等待时间
            clientHttpRequestFactory.setConnectionRequestTimeout(20000);
            return clientHttpRequestFactory;
        } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
            logger.error("初始化HTTP连接池出错", e);
        }
        return null;
    }
}

使用OkHttp作为实现

首先需要引入OkHttp的Maven依赖。

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class RestTemplateConfig {

    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory){
        return new RestTemplate(factory);
    }

    @Bean
    public OkHttp3ClientHttpRequestFactory okHttp3ClientHttpRequestFactory(){
        OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory();
        // 单位:毫秒
        factory.setConnectTimeout(10000);
        factory.setReadTimeout(10000);
        factory.setWriteTimeout(10000);
        return factory;
    }
}

发送GET请求

// 1-getForObject()
User user1 = this.restTemplate.getForObject(uri, User.class);

// 2-getForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class);
HttpStatus statusCode = responseEntity1.getStatusCode();
HttpHeaders header = responseEntity1.getHeaders();
User user2 = responseEntity1.getBody();
  
// 3-exchange()
RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
User user3 = responseEntity2.getBody();

发送POST请求

// 1-postForObject()
User user1 = this.restTemplate.postForObject(uri, user, User.class);

// 2-postForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);

// 3-exchange()
RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user);
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);

设置HTTP Header

// 1-Content-Type
RequestEntity<User> requestEntity = RequestEntity
        .post(new URI(uri))
        .contentType(MediaType.APPLICATION_JSON)
        .body(user);

// 2-Accept
RequestEntity<User> requestEntity = RequestEntity
        .post(new URI(uri))
        .accept(MediaType.APPLICATION_JSON)
        .body(user);

// 3-Other
RequestEntity<User> requestEntity = RequestEntity
        .post(new URI(uri))
        .header("Authorization", "Basic " + base64Credentials)
        .body(user);

发送文件

MultiValueMap<String, Object> multiPartBody = new LinkedMultiValueMap<>();
multiPartBody.add("file", new ClassPathResource("/tmp/user.txt"));
RequestEntity<MultiValueMap<String, Object>> requestEntity = RequestEntity
        .post(uri)
        .contentType(MediaType.MULTIPART_FORM_DATA)
        .body(multiPartBody);

下载文件

// 小文件
RequestEntity requestEntity = RequestEntity.get(uri).build();
ResponseEntity<byte[]> responseEntity = restTemplate.exchange(requestEntity, byte[].class);
byte[] downloadContent = responseEntity.getBody();
  
// 大文件  
ResponseExtractor<ResponseEntity<File>> responseExtractor = new ResponseExtractor<ResponseEntity<File>>() {
    @Override
    public ResponseEntity<File> extractData(ClientHttpResponse response) throws IOException {
        File rcvFile = File.createTempFile("rcvFile", "zip");
        FileCopyUtils.copy(response.getBody(), new FileOutputStream(rcvFile));
        return ResponseEntity.status(response.getStatusCode()).headers(response.getHeaders()).body(rcvFile);
    }
};
File getFile = this.restTemplate.execute(targetUri, HttpMethod.GET, null, responseExtractor);

构建测试用的Http服务

import lombok.Data;
@Data
public class User {
    private Long id;
    private String username;
    private Integer age;
}

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/")
@Slf4j
public class DemoController {

    @GetMapping("demo/{id}/{userName}")
    public User get(@PathVariable Long id, @PathVariable String userName, Integer age){
        log.info("id:{}, userName:{}, age:{}", id, userName, age);
        User user = new User();
        user.setId(id);
        user.setUsername(userName);
        user.setAge(age);
        return user;
    }

    @PostMapping("demo")
    public User post(@RequestBody String json){
        log.info("json:{}", json);
        Gson gson = new Gson();
        User user = gson.fromJson(json, User.class);
        return user;
    }
}

RestTemplate使用

GET请求

在RestTemplate中,发送一个GET请求,有两种方式:getForObject()getForEntity()

getForEntity

getForEntity方法的返回值是一个ResponseEntity<T>ResponseEntity<T>是Spring对HTTP请求响应的封装,包括了几个重要的元素,如响应码、contentType、contentLength、响应消息体等。
在这里插入图片描述
示例:

String url = "http://127.0.0.1:8080/demo/{id}/{userName}?age=18";

// 方式一
ResponseEntity<User> userResponseEntity = restTemplate.getForEntity(url, User.class, 1001L, "Tom");
User user = userResponseEntity.getBody();
HttpStatus statusCode = userResponseEntity.getStatusCode();
int statusCodeValue = userResponseEntity.getStatusCodeValue();
HttpHeaders headers = userResponseEntity.getHeaders();
System.out.println("user = " + user + "; statusCode = " + statusCode + "; statusCodeValue = " + statusCodeValue + "; headers = " + headers);

// 方式二
Map<String, Object> urlParams = new HashMap<>();
urlParams.put("id", 1001L);
urlParams.put("userName", "James");
ResponseEntity<User> userResponseEntity2 = restTemplate.getForEntity(url, User.class, urlParams);

// 方式三
UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).build().expand(1001L, "James").encode();
URI uri = uriComponents.toUri();
ResponseEntity<User> entity = restTemplate.getForEntity(uri, User.class);

getForObject

getForObject函数实际上是对getForEntity函数的进一步封装,如果你只关注返回的消息体的内容,对其他信息都不关注,此时可以使用getForObject
在这里插入图片描述
示例:

//URL中的{id}占位符最终将会用方法的id参数来填充
String url = "http://127.0.0.1:8083/demo/{id}/{userName}?age=18";
Long id = 1001L;
String userName = "Tom";

//方式一:最后一个参数是大小可变的参数列表,每个参数都会按出现顺序插入到指定URL的占位符中
User user = restTemplate.getForObject(url, User.class, id, userName);

//方式二:将id参数放到Map中,并以id作为key,然后将这个Map作为最后一个参数
Map<String, Object> urlParams = new HashMap<>();
urlParams.put("id", id);
urlParams.put("userName", userName);
User user2 = restTemplate.getForObject(url, User.class, urlParams);

//方式二:参考getForEntity案例

POST请求

POST请求对应三个方法,postForObject()、postForEntity()和postForLocation(),每个方法同样对应有三个具体的重载方法。postForObject()、postForEntity()类似于getForObject()和postForEntity(),postForLocation()返回的是一个URI对象。

postForEntity

在这里插入图片描述

String url = "http://localhost:8080/demo2/{address}";
// 方式一
User user = new User();
user.setAge(25);
user.setUsername("王五");
// 第4个参数可以是Object... uriVariables 或者 Map<String, ?> uriVariables
ResponseEntity<User> userResponseEntity = restTemplate.postForEntity(url, user, User.class, "SH");
User userBody = userResponseEntity.getBody();
HttpStatus statusCode = userResponseEntity.getStatusCode();
int statusCodeValue = userResponseEntity.getStatusCodeValue();
HttpHeaders headers = userResponseEntity.getHeaders();
System.out.println("user = " + userBody + "; statusCode = " + statusCode + "; statusCodeValue = " + statusCodeValue + "; headers = " + headers);

postForObject

如果你只关注,返回的消息体,可以直接使用postForObject。用法和getForObject一致。
在这里插入图片描述

exchange通用请求

String getUrl = "http://127.0.0.1:8083/demo/{id}/{userName}?age=18";

//GET资源
//参数3是请求头部分;参数4是响应数据要转成对象;最后一个参数用于替换URL中的占位符
ResponseEntity<User> userResponseEntity = restTemplate.exchange(getUrl, HttpMethod.GET, null, User.class, 1001L, "Tom");
System.out.println("exchange = " + userResponseEntity + "; response body = " + userResponseEntity.getBody());

String postUrl = "http://localhost:8083/demo2";

//POST资源
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonParams = "{\"username\":\"123\",\"age\":23}";
HttpEntity<User> httpEntity = new HttpEntity(jsonParams, headers);
ResponseEntity<User> responseEntity = restTemplate.exchange(postUrl, HttpMethod.POST, httpEntity, User.class);
System.out.println("exchange = " + responseEntity + "; response body = " + responseEntity.getBody());

POST请求,from-data传参

String url = "http://localhost:8083/demo2";
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap map = new LinkedMultiValueMap();
map.add("id",1001L);
HttpEntity httpEntity = new HttpEntity(map, headers);
ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, httpEntity, User.class);
System.out.println(responseEntity.getBody());

RestTemplate携带参数和header头信息

String url="http://www.baidu.com";
MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
map.add("id",id);
HttpHeaders header = new HttpHeaders();
// 需求需要传参为form-data格式
header.setContentType(MediaType.MULTIPART_FORM_DATA);
HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(map, header);
JSONObject response = restTemplate.postForObject(url, httpEntity, JSONObject.class);

URI 使用

URI uri = new URIBuilder().setScheme("http").setHost(ip).setPort(port).setPath("/platform/service")
            .addParameter("user", "")
            .addParameter("service", "")
            .build();
            
UriComponents uriComponents = UriComponentsBuilder.fromUriString(url).build().expand(1001L, "James").encode();
URI uri = uriComponents.toUri();

RestTemplate封装

package com.demo.spring;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;

@Component
public class RestUtil {

    @Autowired
    private RestTemplate restTemplate;

    //一些自定义的请求头参数
    public static final String supplierID = "";
    public static final String interfacekey = "";

    /**
     * DLT专用执行方法
     *
     * @param param  请求参数:可以添加一些常量请求值
     * @param url    访问的url
     * @param method 请求的方法
     * @return
     */
    public String execute(Map<String, Object> param, String url, HttpMethod method) {
        HttpHeaders headers = this.getDefaultHeader();
        Map<String, Object> requestor = this.getDefaultParam();
        param.put("requestor", requestor);
        param.put("supplierID", supplierID);
        HttpEntity<Map<String, Object>> requestEntity = new HttpEntity<>(param, headers);
        ResponseEntity<String> response = restTemplate.exchange(url, method, requestEntity, String.class);
        return response.getBody();
    }

    /**
     * 获取默认的头请求信息
     *
     * @return
     */
    public HttpHeaders getDefaultHeader() {
        String timestamp = "" + System.currentTimeMillis();
        String signature = EncoderByMd5(supplierID + timestamp + interfacekey);
        HttpHeaders headers = new HttpHeaders();
        headers.add("signature", signature);
        headers.add("timestamp", timestamp);
        return headers;
    }
    
    /**
     * 获取默认的参数
     *
     * @return
     */
    public Map<String, Object> getDefaultParam() {
        Map<String, Object> defParam = new HashMap<>();
        defParam.put("invoker", "xx");
        defParam.put("operatorName", "xx");
        return defParam;
    }
    
    /**
     * 通过MD5加密
     *
     * @param str
     * @return
     */
    public static String EncoderByMd5(String str) {
        if (str == null) {
            return null;
        }
        try {
            // 确定计算方法
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            BASE64Encoder base64en = new BASE64Encoder();
            // 加密后的字符串
            return base64en.encode(md5.digest(str.getBytes("utf-8"))).toUpperCase();
        } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
            return null;
        }
    }
    
    /**
     * get请求
     *
     * @param url      请求的url
     * @param jsonData 请求的json
     * @return
     */
    public String restGet(String url, String jsonData) {
        return request(url, jsonData, HttpMethod.GET);
    }

    /**
     * @param url        请求的url
     * @param jsonData   json数据
     * @param httpMethod
     * @return
     */
    private String request(String url, String jsonData, HttpMethod httpMethod) {
        ResponseEntity<String> response = null;

        try {
            if (StringUtils.isEmpty(url)) {
                throw new IllegalArgumentException();
            }
            HttpEntity<String> requestEntity = new HttpEntity<String>(jsonData);
            response = restTemplate.exchange(url, httpMethod, requestEntity, String.class);

        } catch (Exception ex) {
            ex.printStackTrace();
            return "";
        }
        return response.getBody();
    }

    /**
     * Get请求获取实体类
     *
     * @param url          请求的url
     * @param responseType 返回的类型
     * @param parms        不限定个数的参数
     * @param <T>          泛型
     * @return
     */
    public <T> T getForEntity(String url, Class<T> responseType, Object... parms) {
        return (T) restTemplate.getForEntity(url, responseType, parms);

    }

    /**
     * Get请求
     *
     * @param url
     * @param parm
     * @return
     */
    public String get(String url, Map<String, Object> parm) {
        return restTemplate.getForEntity(url, String.class, parm).getBody();
    }
}

手动指定转换器(HttpMessageConverter)

调用reseful接口传递的数据内容是json格式的字符串,返回的响应也是json格式的字符串。然而restTemplate.postForObject方法的请求参数RequestBean和返回参数ResponseBean却都是java类。是RestTemplate通过HttpMessageConverter自动帮我们做了转换的操作。

默认情况下RestTemplate自动帮我们注册了一组HttpMessageConverter用来处理一些不同的contentType的请求。

  • StringHttpMessageConverter来处理text/plain
  • MappingJackson2HttpMessageConverter来处理application/json
  • MappingJackson2XmlHttpMessageConverter来处理application/xml

可以在org.springframework.http.converter包下找到所有spring帮我们实现好的转换器。
如果现有的转换器不能满足我们的需求,我们还可以实现org.springframework.http.converter.HttpMessageConverter接口自己写一个。

选好一个HttpMessageConverter后并注册到我们的RestTemplate中:

RestTemplate restTemplate = new RestTemplate();
//获取RestTemplate默认配置好的所有转换器
List<HttpMessageConverter<?>> messageConverters = restTemplate.getMessageConverters();
//默认的MappingJackson2HttpMessageConverter在第7个 先把它移除掉
messageConverters.remove(6);
//添加上GSON的转换器
messageConverters.add(6, new GsonHttpMessageConverter());
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.8.5</version>
</dependency>

上面的例子使用GsonHttpMessageConverter替换掉默认用来处理application/jsonMappingJackson2HttpMessageConverter

设置底层连接方式

创建一个RestTemplate的实例,可以像上述例子中简单地调用默认的无参数构造函数。这将使用java.net包中的标准Java类作为底层实现来创建HTTP请求。
但很多时候我们需要像传统的HttpClient那样设置HTTP请求的一些属性。RestTemplate使用了一种很偷懒的方式实现了这个需求,那就是直接使用一个HttpClient作为底层实现。

//生成一个设置了连接超时时间、请求超时时间、异常最大重试次数的httpClient
RequestConfig config = RequestConfig.custom()
        .setConnectionRequestTimeout(10000)
        .setConnectTimeout(10000)
        .setSocketTimeout(30000).build();
HttpClientBuilder builder = HttpClientBuilder.create()
        .setDefaultRequestConfig(config)
        .setRetryHandler(new DefaultHttpRequestRetryHandler(5, false));
HttpClient httpClient = builder.build();
//使用httpClient创建一个ClientHttpRequestFactory的实现
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
//ClientHttpRequestFactory作为参数构造一个使用作为底层的RestTemplate
RestTemplate restTemplate = new RestTemplate(requestFactory);

设置拦截器(ClientHttpRequestInterceptor)

有时候我们需要对请求做一些通用的拦截设置,这就可以使用拦截器进行处理。拦截器需要我们实现org.springframework.http.client.ClientHttpRequestInterceptor接口自己写。

举个简单的例子,写一个在header中根据请求内容和地址添加令牌的拦截器。

import org.springframework.http.HttpRequest;
import org.springframework.http.client.ClientHttpRequestExecution;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.http.client.ClientHttpResponse;

import java.io.IOException;

public class TokenInterceptor implements ClientHttpRequestInterceptor {
    @Override
    public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
        //请求地址
        String checkTokenUrl = request.getURI().getPath();
        //请求内容
        String requestBody = new String(body);
        //生成令牌
        String token = "token";
        //将令牌放入请求header中
        request.getHeaders().add("X-Auth-Token",token);
        request.getHeaders().add("X-Auth-Token","yq");
        return execution.execute(request, body);
    }
}

RestTemplate原理

参考

Spring RestTemplate中几种常见的请求方式
RestTemplate原理与使用
springboot集成restTemplate,http连接池
如何使用RestTemplate访问restful服务
spring的RestTemplate使用指南

Springboot 使用RestTemplate
SpringBoot——RestTemplate使用指南

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值