详解RestTemplate 用法

目录
  • 一、简言
  • 二、注入容器
    • 2.1、普通配置
    • 2.2、详细配置
  • 三、GET请求
    • 3.1、getForEntity
    • 3.2、getForObject
  • 四、POST 请求
    • 4.1、postForEntity
    • 4.2、postForObject
    • 4.3、postForLocation
  • 五、PUT请求
  • 六、DELETE请求
  • 七、LinkedMultiValueMap源码分析
  • 八、通用方法 exchange
    • 8.1、用法示例
    • 8.2、封装通用util

一、简言

RestTemplate 是从 Spring3.0 开始支持的一个 HTTP 请求工具,也有的称之为网络框架,说白了就是Java版本的一个postman。专门用于在Java当中服务与服务之间远程调用接口的时候用。

举例A服务,需要从B服务获取到数据,假如不经过前端页面只是后端A服务获取B服务的数据的话,这时候就需要通过Java的HTTP请求工具来远程调用。

类似的还有Apache 的 HttpClient 以及OKHttp3,都是Java当中常用的HTTP 请求工具。

关于HttpClient用法:https://www.jb51.net/article/256131.htm

RestTemplate优点:

  • RestTemplate属于spring的,假如springboot项目的话,完全不用引入任何其他依赖,直接可以用。
  • RestTemplate可以和cloud当中的ribbon进行配合使用,只需要一个注解就可以完成负载均衡调用。

官网api:https://docs.spring.io/spring-framework/docs/5.0.9.RELEASE/javadoc-api/

二、注入容器

既然是远程调用,那么我们系统肯定不会只调用一次,通常情况我们会将RestTemplate注入到容器当中,让他保持单例,当我们哪个类要使用的时候直接从容器里面获取即可。这样可以避免每调用一次创建一个RestTemplate对象。

2.1、普通配置

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

@Configuration
public class ApplicationContextBean {

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

使用的时候直接通过容器注入即可。

@Autowired
private RestTemplate restTemplate;

2.2、详细配置

对于一个请求来说,连接超时时间,请求超时时间等都是可以设置的参数,为了更好的适应业务需求,所以可以自己修改restTemplate的配置。如下利用@Bean注解的参数特性,形成了一个实例化链条。(我实际开发当中一般没有详细设置过,包括我涉及到的项目也是,一般都是直接像上面的简单配置一下就开始使用了)

@Bean注解修饰的方法,假如带有参数,其实就是代表@Bean所标注的对象的实例化依赖于参数中的类,需要先将参数中的类实例化,才能实例化@Bean所标注的对象。

import org.apache.http.Header;
import org.apache.http.client.HttpClient;
import org.apache.http.conn.HttpClientConnectionManager;
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.message.BasicHeader;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.List;

@Configuration
public class RestTemplateConfig {

    /**
     * http连接管理器
     *
     * @return
     */
    @Bean
    public HttpClientConnectionManager poolingHttpClientConnectionManager() {
        /* 注册http和https请求
        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.getSocketFactory())
                .register("https", SSLConnectionSocketFactory.getSocketFactory())
                .build();
        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);*/

        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager();
        // 最大连接数
        poolingHttpClientConnectionManager.setMaxTotal(500);
        // 同路由并发数(每个主机的并发)
        poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100);
        return poolingHttpClientConnectionManager;
    }

    /**
     * HttpClient
     *
     * @param poolingHttpClientConnectionManager
     * @return
     */
    @Bean
    public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {
        HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
        // 设置http连接管理器
        httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);

        // 设置重试次数
        httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));

        // 设置默认请求头(具体可根据自己业务场景进行设置)
        List<Header> headers = new ArrayList<>();
        headers.add(new BasicHeader("atoken", "WAKJDWAJLDKWAKDLKWALKDALKW"));
        httpClientBuilder.setDefaultHeaders(headers);

        return httpClientBuilder.build();
    }

    /**
     * 请求连接池配置
     *
     * @param httpClient
     * @return
     */
    @Bean
    public ClientHttpRequestFactory clientHttpRequestFactory(HttpClient httpClient) {
        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        // httpClient创建器
        clientHttpRequestFactory.setHttpClient(httpClient);
        // 连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connect timeout)
        clientHttpRequestFactory.setConnectTimeout(5 * 1000);
        // 数据读取超时时间(socketTimeout)/毫秒(务器返回数据(response)的时间,超过抛出read timeout)
        clientHttpRequestFactory.setReadTimeout(10 * 1000);
        // 连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool)
        clientHttpRequestFactory.setConnectionRequestTimeout(10 * 1000);
        return clientHttpRequestFactory;
    }

    /**
     * rest模板
     *
     * @return
     */
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
        // boot中可使用RestTemplateBuilder.build创建
        RestTemplate restTemplate = new RestTemplate();
        // 配置请求工厂
        restTemplate.setRequestFactory(clientHttpRequestFactory);

        // 添加拦截器(这块可以通过拦截器来实现日志打印,既然是拦截器,那肯定会丢失一定的性能,所以可根据情况使用,如果计划在拦截器当中打印request当中的日志,一定要注意request是流,不能读两次,这块要做的话,需要想办法将流取出然后再替换一个新的流)
//        List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
//        interceptors.add(restTemplateLog);
//        restTemplate.setInterceptors(interceptors);
        return restTemplate;
    }

}

三、GET请求

这里的方法一共有两类,getForEntitygetForObject,每一类有三个重载方法,下面我们分别予以介绍,首先我们先了解一下传参:

  • String url:请求接口地址
  • URI url:使用 Uri 对象时,参数可以直接拼接在地址中
  • Class<T> responseType:返回的response当中body的对象类型,相当于只要这块写好了,我们就不用将返回值 再进行序列化成对象了。
  • Map<String,?> uriVariables:map类型的key value参数,这个key需要和地址当中的key相对应的
  • Object... uriVariables:这是一个可变长参数,地址栏当中可以用1,2数字占位符当中参数,传参的时候,只要这块的可变长参数能按顺序和占位符 一 一对上即可。

3.1、getForEntity

把这个接口当做要远程调用的接口:

@GetMapping("/getTest2")
public String getTest2(String name) {
    return "hello " + name + " !";
}

这种写法实际是就相当于是这样的:http://localhost:8006/getTest2?name=222

那么远程调用怎么调用呢?下面一共提供了三种写法!

@GetMapping("/test")
public void test() throws UnsupportedEncodingException {
    // 第一种方案(这种方案有点类似hibernate占位符取值,getForEntity第三个参数就是一个可变长参数,当get请求有多个参数的时候也是可以用这种方式的)
    String url1 = "http://127.0.0.1:8006/getTest2?name={1}";
    // 这块的String.class就是ResponseEntity当中的body要序列化成的java对象类型
    ResponseEntity<String> responseEntity1 = restTemplate.getForEntity(url1, String.class, "aaa");
    System.out.println(responseEntity1.getStatusCode());
    System.out.println(responseEntity1.getBody());
    System.out.println(responseEntity1.getHeaders());

    // 第二种方案,将参数放入到一个 map 中。map 中的 key 和占位符的 key 相对应,map 中的 value 就是参数的具体值
    Map<String, Object> map = new HashMap<>();
    String url2 = "http://127.0.0.1:8006/getTest2?name={name}";
    map.put("name", "bbb");
    ResponseEntity<String> responseEntity2 = restTemplate.getForEntity(url2, String.class, map);
    System.out.println(responseEntity2.getStatusCode());
    System.out.println(responseEntity2.getBody());
    System.out.println(responseEntity2.getHeaders());

    // 第三种方案,使用 Uri 对象时,参数可以直接拼接在地址中
    String url = "http://127.0.0.1:8006/getTest2?name=" + URLEncoder.encode("ccc", "UTF-8");
    URI uri = URI.create(url);
    ResponseEntity<String> responseEntity3 = restTemplate.getForEntity(uri, String.class);
    System.out.println(responseEntity3.getStatusCode());
    System.out.println(responseEntity3.getBody());
    System.out.println(responseEntity3.getHeaders());
}

RestTemplate 发送的是 HTTP 请求,那么在响应的数据中必然也有响应头,如果开发者需要获取响应头的话,那么就需要使用 getForEntity 来发送 HTTP 请求,此时返回的对象是一个 ResponseEntity 的实例。通过ResponseEntity我们可以获取请求的响应详细信息,例如:body请求体,header请求头,status状态码

ResponseEntity对象,他实际上就是包含了例如网页访问时候的响应信息。

3.2、getForObject

getForObject 方法和 getForEntity 方法类似,getForObject 方法也有三个重载的方法,参数和 getForEntity 一样,因此这里我就不重复介绍参数了,这里主要说下 getForObjectgetForEntity 的差异,这两个的差异主要体现在返回值的差异上, getForObject 的返回值就是服务提供者返回的数据,使用 getForObject 无法获取到响应头。

把下面接口当做要远程调用的接口:

// 没有参数的时候调用
@GetMapping("/getTest1")
public String getTest1() {
    return "getTest1";
}

// ?拼接的参数
@GetMapping("/getTest2")
public String getTest2(String name) {
    return "hello " + name + " !";
}

// 斜杠地址栏/ 拼接的参数
@GetMapping("/getTest3/{name}")
public String getTest3(@PathVariable(value = "name") String name) {
    return "hello " + name + " !";
}

那么远程调用怎么调用呢?下面提供多个示例供参考!

@GetMapping("/test1")
public void test1() throws UnsupportedEncodingException {
    // 无参调用
    String result = restTemplate.getForObject("http://127.0.0.1:8006/getTest1", String.class);
    System.out.println(result);

    String url2 = "http://127.0.0.1:8006/getTest2?name={1}";
    String result1 = restTemplate.getForObject(url2, String.class, "aaa");
    System.out.println(result1);

    // 第一种方案 调用地址栏/拼接
    String url3 = "http://127.0.0.1:8006/getTest3/{1}";
    String result2 = restTemplate.getForObject(url3, String.class, "bbb");
    System.out.println(result2);

    // 第二种方案 调用地址栏/拼接
    String url4 = "http://127.0.0.1:8006/getTest3/" + URLEncoder.encode("ccc", "UTF-8");
    URI uri = URI.create(url4);
    String result3 = restTemplate.getForObject(uri, String.class);
    System.out.println(result3);

    // 第三种方案 调用地址栏/拼接
    Map<String, Object> map = new HashMap<>();
    String url5 = "http://127.0.0.1:8006/getTest3/{name}";
    map.put("name", "ddd");
    String result4 = restTemplate.getForObject(url5, String.class, map);
    System.out.println(result4);
}

通过以上练习后会发现一个致命问题,提供的get请求的API当中并没有header传参这一项,假如请求的别的服务接口有认证,那我们该怎么办呢?

我们可以使用RestTemplate 当中的 exchange自定义请求。

四、POST 请求

可以看到,post 请求的方法类型除了 postForEntitypostForObject 之外,还有一个 postForLocation。这里的方法类型虽然有三种,但是这三种方法重载的参数基本是一样的。其余参数都和get一样,就多了一个request参数,如下:

Object request: 该参数可以是一个普通对象, 也可以是一个HttpEntity对象。

  • 如果是一个普通对象, 而非HttpEntity对象的时候, RestTemplate会将请求对象转换为一个HttpEntity对象来处理, 其中Object就是 request请求体(body)的类型, request内容会被视作完整的body来处理;
  • 如果 request 是一个HttpEntity对象, 那么就会被当作一个完成的HTTP请求对象来处理, 这个 request 中不仅包含了body的内容, 也包含了header的内容。

如下源码是对request参数进行转换调用的:

什么情况下要使用HttpEntity?

假如我们远程调用的接口是有token认证的,我们请求的时候就需要在header请求头当中添加token,这时候我们就需要通过HttpEntity对象来携带请求头。

4.1、postForEntity

示例一:下面接口是JSON传参,然后还获取token了,把它当做要远程调用的接口:

@PostMapping("/postTest2")
public User test2(HttpServletRequest request, @RequestBody User user1) {
    System.out.println("接受的参数:" + user1);
    // 正常情况我们是需要通过拦截器来拦截request获取请求头当中的token来进行认证,这块只是演示
    System.out.println("接受的请求头:" + request.getHeader("token"));
    User user = new User();
    user.setId(1);
    user.setName("张三");
    user.setSex("男性");
    return user;
}

那么远程调用怎么调用呢?下面示例供参考!

示例使用的是如下图API,request 可以是一个普通对象,也可以是HttpEntity。

@GetMapping("/hello2")
public User hello5() {
    String url = "http://127.0.0.1:8006/postTest2";

    // 请求示例一:携带token请求头
    // 请求体
    User user = new User();
    user.setId(1);
    user.setName("李四");
    user.setSex("女性");
    // 请求头(这里有一点需要注意,HttpHeaders和HttpEntity都是引入的spring的包)
    HttpHeaders headers = new HttpHeaders();
    headers.add("token", "WDWADAWDWADAWSAXZCXZCXZEDF");
    // 请求
    HttpEntity<User> requst = new HttpEntity<>(user, headers);

    ResponseEntity<User> responseEntity = restTemplate.postForEntity(url, requst, User.class);
    System.out.println("响应的结果:" + responseEntity.getBody());

    // 请求示例二:不携带请求头,直接传普通对象,这里直接传的user,map也是可以的,他都可以转换成json,切记不能使用LinkedMultiValueMap,使用他不会转换成json
    ResponseEntity<User> responseEntity1 = restTemplate.postForEntity(url, user, User.class);
    System.out.println("响应的结果:" + responseEntity1.getBody());

    return responseEntity1.getBody();
}

调用结果:

示例二:下面接口是key/value传参,然后还获取token了,把它当做要远程调用的接口:

@PostMapping("/postTest1")
public String test1(HttpServletRequest request, String name) {
    System.out.println("接受的参数:" + name);
    System.out.println("接受的请求头:" + request.getHeader("token"));
    return "Hello " + name + " !";
}

那么远程调用怎么调用呢?下面示例供参考!

下面每个示例都使用了request参数,正常情况下,假如第三方接口没有token认证,我们是不需要使用request参数的,直接传null即可。

@GetMapping("/hello1")
public void hello1() throws UnsupportedEncodingException {

    // 请求头(这里有一点需要注意,HttpHeaders和HttpEntity都是引入的spring的包)
    HttpHeaders headers = new HttpHeaders();
    headers.add("token", "WDWADAWDWADAWSAXZCXZCXZEDF");
    HttpEntity<Map> requst = new HttpEntity<>(null, headers);

    // 调用方式一,通过map传参
    String url1 = "http://127.0.0.1:8006/postTest1?name={name}";
    Map<String, String> param = new HashMap<>(16);
    param.put("name", "李四");
    ResponseEntity<String> responseEntity1 = restTemplate.postForEntity(url1, requst, String.class, param);
    System.out.println(responseEntity1.getBody());

    // 调用方式二,通过占位符和可变长参数传参
    String url2 = "http://127.0.0.1:8006/postTest1?name={1}";
    ResponseEntity<String> responseEntity2 = restTemplate.postForEntity(url2, requst, String.class, "牛牛");
    System.out.println(responseEntity2.getBody());

    // 调用方式三,正常这块其实都不需要URI对象了,根据地址直接访问就可以。
    String url3 = "http://127.0.0.1:8006/postTest1?name=" + URLEncoder.encode("ccc", "UTF-8");
    URI uri = URI.create(url3);
    ResponseEntity<String> responseEntity3 = restTemplate.postForEntity(uri, requst, String.class);
    System.out.println(responseEntity3.getBody());

	// 调用方式四:这种方式是没有使用请求头的,使用LinkedMultiValueMap,切记不能使用hashmap和java实体类,不然就转换成json了,将LinkedMultiValueMap放到HttpEntity的body当中其实也是可以的,然后就可以携带token了。
    String url4 = "http://127.0.0.1:8006/postTest1";
    MultiValueMap map = new LinkedMultiValueMap();
    map.add("name", "萨瓦迪卡");
    ResponseEntity<String> responseEntity4 = restTemplate.postForEntity(url4, map, String.class);
    System.out.println(responseEntity4.getBody());
}

调用示例:

前三种方式都是携带了header,最后一种没有带。

4.2、postForObject

postForObject 和 postForEntity 基本一致,就是返回类型不同而已,这里不再赘述。

4.3、postForLocation

postForLocation 方法的返回值是一个 Uri 对象,因为 POST 请求一般用来添加数据,有的时候需要将刚刚添加成功的数据的 URL 返回来,此时就可以使用这个方法,一个常见的使用场景如用户注册功能,用户注册成功之后,可能就自动跳转到登录页面了,此时就可以使用该方法。例如在 provider 中提供一个用户注册接口,再提供一个用户登录接口,如下:

@RequestMapping("/register")
public String register(User user) throws UnsupportedEncodingException {
    return "redirect:/loginPage?username=" + URLEncoder.encode(user.getUsername(),"UTF-8") + "&address=" + URLEncoder.encode(user.getAddress(),"UTF-8");
}
@GetMapping("/loginPage")
@ResponseBody
public String loginPage(User user) {
    return "loginPage:" + user.getUsername() + ":" + user.getAddress();
}

这里一个注册接口,一个是登录页面,不过这里的登录页面我就简单用一个字符串代替了。然后在 consumer 中来调用注册接口,如下:

@GetMapping("/hello8")
public String hello8() {
    List<ServiceInstance> list = discoveryClient.getInstances("provider");
    ServiceInstance instance = list.get(0);
    String host = instance.getHost();
    int port = instance.getPort();
    String url = "http://" + host + ":" + port + "/register";
    MultiValueMap map = new LinkedMultiValueMap();
    map.add("username", "牧码小子");
    map.add("address", "深圳");
    URI uri = restTemplate.postForLocation(url, map);
    String s = restTemplate.getForObject(uri, String.class);
    return s;
}

注意: postForLocation 方法返回的 Uri 实际上是指响应头的 Location 字段,所以,provider 中 register 接口的响应头必须要有 Location 字段(即请求的接口实际上是一个重定向的接口),否则 postForLocation 方法的返回值为null,初学者很容易犯这个错误。

五、PUT请求

PUT 请求和POST请求传参基本上一模一样,他也有request参数,唯一区别就是PUT请求是没有返回值的,PUT 请求本身方法也比较少,只有三个,如下:

六、DELETE请求

DELETE 请求和GET请求传参基本上一模一样,同样都没有request参数,唯一区别就是DELETE 请求是没有返回值的,DELETE 请求本身方法也比较少,只有三个,如下:

七、LinkedMultiValueMap源码分析

1、项目中在使用RestTemplate进行http请求时,会用到LinkedMultiValueMap,现在简单分析一下LinkedMultiValueMap的数据结构。

2、打开LinkedMultiValueMap的源码,可以看到里面封装的是一个Map,再看构造方法,最终创建的是一个LinkedHashMap。这个Map的value有点特别,他不能放任何值,必须是一个List。
其实LinkedMultiValueMap可以看作是一个表单,在表单中,一个name可以对应很多值,比如根据id批量删除,一个key需要对应很多需要删除的id

3、add、put、set

public static void main(String[] args) {
    MultiValueMap params = new LinkedMultiValueMap();

    params.add("username", "张三");
    params.add("username", "李四");
    System.out.println(params);

    params.put("password", Arrays.asList("1234"));
    System.out.println(params);

    params.set("username", "王五");
    System.out.println(params);
}

运行结果:

4、通过源码分析

add是把值放到list中,若map中没有key对应的list,先new一个LinkedList。

put直接接收list

set不管原来怎么样,都会重新new一个LinkedList,再把值放进去

5、什么时候使用LinkedMultiValueMap,答案就是模拟普通的表单提交时。

HttpEntity的body里面使用LinkedMultiValueMap,那么就是key/value传参,如果是其他的bean类型,就会格式化成json。

八、通用方法 exchange

为什么说它通用呢?因为这个方法需要你在调用的时候去指定请求类型,即它既能做 GET 请求,也能做 POST 请求,也能做其它各种类型的请求。如果开发者需要对请求进行封装,使用它再合适不过了。这个方法重载的方法非常多,其中参数也多了很多个,如下:

  • HttpMethod method:请求的方法(GET、POST、PUT等)
  • HttpEntity<?> requestEntity:HttpEntity对象,封装了请求头和请求体,在上面post的时候应该掌握的差不多了。

8.1、用法示例

使用如下API演示两个示例:

  • post的key/value传参
  • post的json传参

示例一:post的key/value传参

@PostMapping("/exchangeTest1")
public String test1(HttpServletRequest request, String name) {
    System.out.println("接受的参数:" + name);
    System.out.println("接受的请求头:" + request.getHeader("token"));
    return "Hello " + name + " !";
}

调用示例:

@GetMapping("/exchange1")
public void hello1() {
    String url = "http://127.0.0.1:8006/exchangeTest1";

    // 请求体,一定要用LinkedMultiValueMap,用hashmap或者javabean会直接转换成json的
    MultiValueMap map = new LinkedMultiValueMap();
    map.add("name", "萨瓦迪卡");
    // 请求头(这里有一点需要注意,HttpHeaders和HttpEntity都是引入的spring的包)
    HttpHeaders headers = new HttpHeaders();
    headers.add("token", "WDWADAWDWADAWSAXZCXZCXZEDF");
    // 请求
    HttpEntity<Map> requst = new HttpEntity<>(map, headers);
    ResponseEntity<String> exchange = restTemplate.exchange(url, HttpMethod.POST, requst, String.class);
    System.out.println("响应的结果:" + exchange.getBody());
}

调用结果:

示例二:post的json传参

@PostMapping("/postTest2")
public User test2(HttpServletRequest request, @RequestBody User user1) {
    System.out.println("接受的参数:" + user1);
    System.out.println("接受的请求头:" + request.getHeader("token"));
    User user = new User();
    user.setId(1);
    user.setName("张三");
    user.setSex("男性");
    return user;
}

调用示例:

@GetMapping("/exchange2")
public void hello2() {
    String url = "http://127.0.0.1:8006/postTest2";

    // 请求体,不要用LinkedMultiValueMap,否则会变成key/value传参
    User user = new User();
    user.setId(1);
    user.setName("李四");
    user.setSex("女性");
    // 请求头(这里有一点需要注意,HttpHeaders和HttpEntity都是引入的spring的包)
    HttpHeaders headers = new HttpHeaders();
    headers.add("token", "WDWADAWDWADAWSAXZCXZCXZEDF");
    // 请求
    HttpEntity<User> requst = new HttpEntity<>(user, headers);
    ResponseEntity<User> exchange = restTemplate.exchange(url, HttpMethod.POST, requst, User.class);
    System.out.println("响应的结果:" + exchange.getBody());
}

调用结果:

8.2、封装通用util

可以写一个通用的工具类,根据传入的参数来确定请求的路径和内容。工具类肯定是想通过静态方式来直接调用,而不是通过new Util()的方式来使用。但是静态变量/类变量不是对象的属性,而是一个类的属性,spring则是基于对象层面上的依赖注入。所以我们不能@Autowired或者@resource一个静态变量。但是静态方法又不能调用非静态的属性,那么我们该怎么办呢?

@PostContruct是Java自带的注解,在方法上加该注解会在项目启动的时候执行该方法,也可以理解为在spring容器初始化的时候执行该方法。

@Component
public class HttpUtil {

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

    @Resource
    private RestTemplate restTemplate;

    private static HttpUtil httpUtil;

    @PostConstruct
    public void init(){
        httpUtil = this;
        httpUtil.restTemplate = this.restTemplate;
    }

    public static <T> String httpRequest(String url, HttpMethod method, HttpEntity<T> entity,Class<T> responseType){
        try {
            //发起一个POST请求
            ResponseEntity<String> result = httpUtil.restTemplate.exchange(url, method, entity, responseType);
           return result.getBody();
        } catch (Exception e) {
            logger.error("请求失败: " + e.getMessage());
        }
        return null;
    }

}

这个时候我们就需要维护一个工具类的静态实例,初始化的时候把restTemplate传进来,这样就可以直接调用HttpUtil.httpRequest()方法。

到此这篇关于详解RestTemplate 用法的文章就介绍到这了,更多相关RestTemplate 用法内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • springboot集成RestTemplate及常见的用法说明

    目录 一.背景介绍 1.什么是RestTemplate? 2.RestTemplate的优缺点 二.配置RestTemplate 1.引入依赖 2.连接池配置 3.初始化连接池 4.使用示例 三.RestTemplate常用方法 1.getForEntity 2.getForObject 3.postForEntity 4.postForObject 5.postForLocation 6.PUT请求 7.DELETE请求 一.背景介绍 在微服务都是以HTTP接口的形式暴露自身服务的,因此在调用

  • RestTemplate实现多种底层HTTP客户端类库的切换用法

    本文是精讲RestTemplate第2篇,前篇的blog访问地址如下: 精讲RestTemplate第1篇-在Spring或非Spring环境下如何使用 RestTemplate只是对其他的HTTP客户端的封装,其本身并没有实现HTTP相关的基础功能.其底层实现是可以配置切换的,我们本小节就带着大家来看一下RestTemplate底层实现,及如何实现底层基础HTTP库的切换. 一.源码分析 RestTemplate有一个非常重要的类叫做HttpAccessor,可以理解为用于HTTP接触访问的基

  • 详解RestTemplate 用法

    目录 一.简言 二.注入容器 2.1.普通配置 2.2.详细配置 三.GET请求 3.1.getForEntity 3.2.getForObject 四.POST 请求 4.1.postForEntity 4.2.postForObject 4.3.postForLocation 五.PUT请求 六.DELETE请求 七.LinkedMultiValueMap源码分析 八.通用方法 exchange 8.1.用法示例 8.2.封装通用util 一.简言 RestTemplate 是从 Sprin

  • C语言指针详解及用法示例

    新手在C语言的学习过程中遇到的最头疼的知识点应该就是指针了,指针在C语言中有非常大的用处.下面我就带着问题来写下我对于指针的一些理解. 指针是什么? 指针本身是一个变量,它存储的是数据在内存中的地址而不是数据本身的值.它的定义如下: int a=10,*p; p=&a int a=10; int *p=&a; 首先我们可以理解 int* 这个是要定义一个指针p,然后因为这个指针存储的是地址所以要对a取地址(&)将值赋给指针p,也就是说这个指针p指向a. 很多新手都会对这两种定义方法

  • python中的 zip函数详解及用法举例

    python中zip()函数用法举例 定义:zip([iterable, ...]) zip()是Python的一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后返回由这些tuples组成的list(列表).若传入参数的长度不等,则返回list的长度和参数中长度最短的对象相同.利用*号操作符,可以将list unzip(解压),看下面的例子就明白了: 示例1 x = [1, 2, 3] y = [4, 5, 6] z = [7, 8, 9] x

  • 详解HttpClient用法

    上篇文章给大家介绍了HttpClient详细使用示例详解,喜欢的朋友可以点击查看,今天继续给大家介绍HttpClient用法,具体内容如下所示: 1.简介 HttpClient是Apache Jakarta Common下的子项目,用来提供高效的.最新的.功能丰富的支持HTTP协议的客户端编程工具包,并且它支持HTTP协议最新的版本和建议.HttpClient已经应用在很多的项目中,比如Apache Jakarta上很著名的另外两个开源项目Cactus和HTMLUnit都使用了HttpClien

  • javascript 实例详解循环用法

    闲来无聊,整理了几道有关循环的简单练习题,希望对初学JS的小伙伴有所帮助. 1.打印1-100之间所有7的倍数的个数及总和 var sum=0; var n=0; for(var i=1;i<=100;i++){ if(i%7==0){ sum+=i; ++n; } } console.log("个数为:"+n+",总和为:"+sum); 运行结果: 2.假设投资的年利率为5%,从1000增到5000需要多少年? var money=1000; var i=0

  • Java 多态中继承的转型详解与用法分析

    目录 一.前言 二.转型 向上转型 向下转型 三.instanceof运算符 instanceof的用处 instanceof的使用格式: 一.前言 前面我们学习了多态的概述和使用,现在我们来学习前面剩下的转型问题. 二.转型

  • Python中np.random.randint()参数详解及用法实例

    目录 可实现功能: np.random.randint() 根据参数中所指定的范围生成随机 整数. 参数 一.基础用法 二.高级用法 总结 可实现功能: 1.随机生成一个整数. 2.随机生成任意范围内的一个整数. 3.随机生成指定长度的整数组 4.随机生成指定长度的任意范围的整数组 5.随机生成指定长度的多维整数组 6.随机生成指定长度的任意范围的多维整数组 np.random.randint() 根据参数中所指定的范围生成随机 整数. numpy.random.randint(low, hig

  • linux touch,chattr指令详解及用法

     linux touch,chattr指令详解 man touch NAME touch - 更改文件的时间戳 SYNOPSIS touch [OPTION]... FILE... DESCRIPTION 更新文件的atime和mtime为现在的时间 -a 仅修文件被取用的时间 -c, --no-create 文件不存在是不建立新的档案 -d, --date=STRING 使用STRING的设定而不使用现在的时间 -m 仅修改文件内容变更的时间 -t STAMP 使用[[CC]YY]MMDDhh

  • Java中finalize()详解及用法

     Java中finalize()详解 在程序设计中,我们有时可能希望某些数据是不能够改变的,这个时候final就有用武之地了.final是Java的关键字,它所表示的是"这部分是无法修改的".不想被改变的原因有两个:效率.设计.使用到final的有三种情况:数据.方法.类.        一. final数据 有时候数据的恒定不变是很有用的,它能够减轻系统运行时的负担.对于这些恒定不变的数据我可以叫做"常量"."常量"主要应用与以下两个地方: 1

  • java 关键字super详解及用法

    java 关键字super详解 一.super关键字 在JAVA类中使用super来引用父类的成分,用this来引用当前对象,如果一个类从另外一个类继承,我们new这个子类的实例对象的时候,这个子类对象里面会有一个父类对象.怎么去引用里面的父类对象呢?使用super来引用,this指的是当前对象的引用,super是当前对象里面的父对象的引用. 1.1.super关键字测试 package cn.galc.test; /** * 父类 * @author gacl * */ class Fathe

随机推荐