• Spring restTemplate


    什么是RestTemplate

    RestTemplate是Spring提供的用于访问Rest服务的客户端,提供了多种便捷访问远程HTTP服务的方法,能够大大提高客户端的编写效率。

     

    项目中注入RestTemplate

    首先在项目中添加依赖:

    <!-- Jackson对自动解析JSON和XML格式的支持 -->
    <dependency>
        <groupId>com.fasterxml.jackson.jaxrs</groupId>
        <artifactId>jackson-jaxrs-json-provider</artifactId>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.dataformat</groupId>
        <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>
     
    <!-- HttpClient -->
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
    </dependency>

    在注入RestTemplate的bean的时候,可以通过ClientHtppRequestFactory指定RestTemplate发起HTTP请求的底层实现所采用的类库。对此,ClientHttpRequestFactory接口主要提供了以下两种方法: 
    一种是SimpleClientHttpRequestFactory,使用J2SE提供的方式(即java.net包提供的方式)创建底层的HTTP请求连接。 
    另一种是使用HttpComponentsClientHttpRequestFactory方式,底层使用HttpClient访问远程的http服务,使用HttpClient可以配置连接池和证书等信息。 
    以下的两个方法都采用线程安全的单例(懒汉模式) 
    (1)SimpleClientHttpRequestFactory

    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.springframework.context.annotation.Lazy;
    import org.springframework.http.client.SimpleClientHttpRequestFactory;
    import org.springframework.http.converter.FormHttpMessageConverter;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.StringHttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
    import org.springframework.stereotype.Component;
    import org.springframework.web.client.DefaultResponseErrorHandler;
    import org.springframework.web.client.RestTemplate;
    
    import javax.annotation.PostConstruct;
    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.List;
    
    @Component
    @Lazy(false)
    public class SimpleRestClient {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SimpleRestClient.class);
    
        private static RestTemplate restTemplate;
    
        static {
            SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory();
            requestFactory.setReadTimeout(5000);
            requestFactory.setConnectTimeout(5000);
    
            // 添加转换器
            List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
            messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
            messageConverters.add(new FormHttpMessageConverter());
            messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
            messageConverters.add(new MappingJackson2HttpMessageConverter());
    
            restTemplate = new RestTemplate(messageConverters);
            restTemplate.setRequestFactory(requestFactory);
            restTemplate.setErrorHandler(new DefaultResponseErrorHandler());
    
            LOGGER.info("SimpleRestClient初始化完成");
        }
    
        private SimpleRestClient() {
    
        }
    
        @PostConstruct
        public static RestTemplate getClient() {
            return restTemplate;
        }
    
    }

    (2)HttpComponentsClientHttpRequestFactory(推荐使用)

    import java.nio.charset.Charset;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
     
    import org.apache.http.Header;
    import org.apache.http.client.HttpClient;
    import org.apache.http.impl.client.DefaultConnectionKeepAliveStrategy;
    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.http.converter.FormHttpMessageConverter;
    import org.springframework.http.converter.HttpMessageConverter;
    import org.springframework.http.converter.StringHttpMessageConverter;
    import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
    import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
    import org.springframework.web.client.RestTemplate;
     
    @Configuration
    public class RestTemplateConfig {
     
        /**
         * 返回RestTemplate
         * @param factory
         * @return
         */
        @Bean
        public RestTemplate restTemplate(ClientHttpRequestFactory factory){
            //消息转换器,Spring Boot环境可省略,只需要添加相关依赖即可
    //        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
    //        messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
    //        messageConverters.add(new FormHttpMessageConverter());
    //        messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
    //        messageConverters.add(new MappingJackson2HttpMessageConverter());
            
            RestTemplate restTemplate = new RestTemplate(factory);
    //        restTemplate.setMessageConverters(messageConverters);
            
            return restTemplate;
        }
        
        /**
         * ClientHttpRequestFactory接口的另一种实现方式(推荐使用),即:
         * HttpComponentsClientHttpRequestFactory:底层使用Httpclient连接池的方式创建Http连接请求
         * @return
         */
        @Bean
        public HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory(){
            //Httpclient连接池,长连接保持30秒
            PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(30, TimeUnit.SECONDS);
            
            //设置总连接数
            connectionManager.setMaxTotal(1000);
            //设置同路由的并发数
            connectionManager.setDefaultMaxPerRoute(1000);
            
            //设置header
            List<Header> headers = new ArrayList<Header>();
            headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.3; rv:36.0) Gecko/20100101 Firefox/36.04"));
            headers.add(new BasicHeader("Accept-Encoding", "gzip, deflate"));
            headers.add(new BasicHeader("Accept-Language", "zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3"));
            headers.add(new BasicHeader("Connection", "keep-alive"));
            
            //创建HttpClient
            HttpClient httpClient = HttpClientBuilder.create()
                    .setConnectionManager(connectionManager)
                    .setDefaultHeaders(headers)
                    .setRetryHandler(new DefaultHttpRequestRetryHandler(3, true)) //设置重试次数
                    .setKeepAliveStrategy(new DefaultConnectionKeepAliveStrategy()) //设置保持长连接
                    .build();
            
            //创建HttpComponentsClientHttpRequestFactory实例
            HttpComponentsClientHttpRequestFactory requestFactory = 
                    new HttpComponentsClientHttpRequestFactory(httpClient);
            
            //设置客户端和服务端建立连接的超时时间
            requestFactory.setConnectTimeout(5000);
            //设置客户端从服务端读取数据的超时时间
            requestFactory.setReadTimeout(5000);
            //设置从连接池获取连接的超时时间,不宜过长
            requestFactory.setConnectionRequestTimeout(200);
            //缓冲请求数据,默认为true。通过POST或者PUT大量发送数据时,建议将此更改为false,以免耗尽内存
            requestFactory.setBufferRequestBody(false);
            
            return requestFactory;
        }
        
    }

    RestTemplate提供了很多方法,可以与HTTP方法对应。

    HTTP方法RestTemplate方法说明
    DELETE delete() 在特定的URL上对资源执行HTTP DELETE操作
    GET

    getForEntity()

    getForObject()

    getForEntity():发送一个HTTP GET请求,返回的ResponseEntity包含了响应体所映射成的对象。 

    getForObject():发送一个HTTP GET请求,返回根据响应体映射形成的对象

    POST

    postForEntity()

    postForLocation() postForObject()

    postForEntity(): POST数据到一个URL,返回的ResponseEntity包含了响应体所映射成的对象。 

    postForLocation(): POST数据到一个URL,返回新创建资源的URL。

    postForObject(): POST数据到一个URL,返回根据响应体映射形成的对象

    PUT put() PUT资源到特定的URL
    HEAD headForHeaders() 发送HTTP HEAD请求,返回包含特定资源URL的HTTP头
    OPTIONS optionsForAllow() 发送HTTP OPTIONS请求,返回对特定URL的Allow头信息
    PATCH and others

    exchange()

    execute()

    exchange(): 在URL上执行特定的HTTP方法,返回的ResponseEntity包含了响应体所映射成的对象

     execute():在URL上执行特定的HTTP方法,返回一个从响应体映射得到的对象

    接下来讲一下RestTemplate的这几个方法如何使用。 

    GET请求方式的两种方法 
    1. getForEntity() 
    三个getForEntity()方法的签名:

    <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Object... uriVariables) throws RestClientException;
     
    <T> ResponseEntity<T> getForEntity(String url, Class<T> responseType, Map<String, ?> uriVariables) throws RestClientException;
     
    <T> ResponseEntity<T> getForEntity(URI url, Class<T> responseType) throws RestClientException;

    示例代码:

        /**
         * 测试Get请求返回详细信息,包括:响应正文、响应状态码、响应Header等
         */
        @Test
        public void testGetMethod3(){
            //第一个参数为要调用的服务的地址,第二个参数为返回值的类型,第三和第四个参数时url中的传参
            ResponseEntity<DemoObj> responseEntity = restTemplate.getForEntity("http://127.0.0.1:9090/rest/testJson2?id={1}&name={2}"
                    , DemoObj.class
                    , 1,"Tom");
            
            DemoObj body = responseEntity.getBody();
            int statusCodeValue = responseEntity.getStatusCodeValue();
            HttpHeaders headers = responseEntity.getHeaders();
            
            System.out.println("responseEntity.getBody():" + body);
            System.out.println("responseEntity.getStatusCodeValue():" + statusCodeValue);
            System.out.println("responseEntity.getHeaders():" + headers);
        }

    结果:

    responseEntity.getBody():DemoObj [id=2, name=Tom Ret]
    responseEntity.getStatusCodeValue():200
    responseEntity.getHeaders():{Date=[Fri, 09 Feb 2018 06:22:28 GMT], Content-Type=[application/json;charset=utf-8], Transfer-Encoding=[chunked]}

    再来看一个Map传参的例子:

    @RequestMapping("/sayhello2")
    public String sayHello2() {
        Map<String, String> map = new HashMap<>();
        map.put("name", "李四");
        ResponseEntity<String> responseEntity = restTemplate.getForEntity("http://HELLO-SERVICE/sayhello?name={name}", String.class, map);
        return responseEntity.getBody();
    }

    当然,第一个参数也可以是URI而不是字符串,可以通过Spring中的UriComponents来构建uri即可。

    @RequestMapping("/sayhello3")
    public String sayHello3() {
        UriComponents uriComponents = UriComponentsBuilder.fromUriString("http://HELLO-SERVICE/sayhello?name={name}").build().expand("王五").encode();
        URI uri = uriComponents.toUri();
        ResponseEntity<String> responseEntity = restTemplate.getForEntity(uri, String.class);
        return responseEntity.getBody();
    }

    2.getForObject() 
    getForObject()实际上是对getForEntity()的进一步封装,用法类似,唯一的区别就是getForObject()方法只返回请求类型的对象,而getForEntity()会返回请求的对象以及响应的Header,响应状态码等额外信息。

    @RequestMapping("/book2")
    public Book book2() {
        Book book = restTemplate.getForObject("http://HELLO-SERVICE/getbook1", Book.class);
        return book;
    }
        @Test
        public void testGetMethod2(){
            Map<String, String> uriVariables = new HashMap<String, String>();
            uriVariables.put("var_id", "1");
            uriVariables.put("var_name", "Tom");
            
            DemoObj obj = restTemplate.getForObject("http://127.0.0.1:9090/rest/testJson2?id={var_id}&name={var_name}"
                    , DemoObj.class
                    , uriVariables);
            
            System.out.println(obj);
        }

    POST请求的三种方法 
    1. postForEntity() 
    POST请求和GET请求类似,也是三种方法:

    <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Object... uriVariables)
                throws RestClientException;
     
    <T> ResponseEntity<T> postForEntity(String url, Object request, Class<T> responseType, Map<String, ?> uriVariables)
                throws RestClientException;
     
    <T> ResponseEntity<T> postForEntity(URI url, Object request, Class<T> responseType) throws RestClientException;

    看个示例:

        @Test
        public void testPostMethod2(){
            DemoObj request = new DemoObj(1l, "Tim");
            
            ResponseEntity<DemoObj> responseEntity = restTemplate.postForEntity("http://127.0.0.1:9090/rest/testJson1"
                    , request, DemoObj.class);
            
            DemoObj body = responseEntity.getBody();
            int statusCodeValue = responseEntity.getStatusCodeValue();
            HttpHeaders headers = responseEntity.getHeaders();
            
            System.out.println("responseEntity.getBody():" + body);
            System.out.println("responseEntity.getStatusCodeValue():" + statusCodeValue);
            System.out.println("responseEntity.getHeaders():" + headers);
        }

    结果:

    responseEntity.getBody():DemoObj [id=2, name=Tim Ret]
    responseEntity.getStatusCodeValue():200
    responseEntity.getHeaders():{Date=[Fri, 09 Feb 2018 06:32:02 GMT], Content-Type=[application/json;charset=utf-8], Transfer-Encoding=[chunked]}

    2.postForObject()

        @Test
        public void testPostMethod1(){
            DemoObj request = new DemoObj(1l, "Tim");
            
            DemoObj obj = restTemplate.postForObject("http://127.0.0.1:9090/rest/testJson1"
                    , request, DemoObj.class);
            
            System.out.println(obj);
        }

    3.postForLocation()
    postForLocation()也是提交新资源,提交成功之后,返回新资源的URI,postForLocation的参数和前面两种的参数基本一致,只不过该方法的返回值为Uri,这个只需要服务提供者返回一个Uri即可,该Uri表示新资源的位置。

    PUT请求 
    在RestTemplate中,PUT请求可以通过put方法调用,put方法的参数和前面介绍的postForEntity方法的参数基本一致,只是put方法没有返回值而已。

    @RequestMapping("/put")
    public void put() {
        Book book = new Book();
        book.setName("红楼梦");
        restTemplate.put("http://HELLO-SERVICE/getbook3/{1}", book, 99);
    }

    DELETE请求

    @RequestMapping("/delete")
    public void delete() {
        restTemplate.delete("http://HELLO-SERVICE/getbook4/{1}", 100);
    }

    exchange()方法执行指定的HTTP请求 
    exchange()方法同上面的很多方法不同的是,它可以指定请求的HTTP方式。

        @Test
        public void testExchange(){
            //设置header
            HttpHeaders headers = new HttpHeaders();
            headers.add("Content-Type", "application/x-zifangsky");
            
            //设置参数
            String requestBody = "1#Converter";
            HttpEntity<String> requestEntity = new HttpEntity<String>(requestBody,headers);
     
            ResponseEntity<String> responseEntity = restTemplate.exchange("http://127.0.0.1:9090/convert"
                    , HttpMethod.POST, requestEntity, String.class);
            
            System.out.println("responseEntity.getBody():" + responseEntity.getBody());
            System.out.println("responseEntity.getHeaders():" + responseEntity.getHeaders());
        }

    手动指定转换器 
    调用restful接口传递的数据是json格式的字符串,返回的响应也是json格式的字符串。

     

  • 相关阅读:
    Node.js入门
    Promise入门
    MongoDB基础
    Express入门
    常用特殊符号HTML代码 (转)
    sqlserver函数简单介绍
    git忽略本地提交命令
    Scrapy入门到放弃05:让Item在Pipeline中飞一会儿
    Scrapy入门到放弃06:Spider中间件
    2022虎年微信红包封面的设计和领取
  • 原文地址:https://www.cnblogs.com/lyy-2016/p/9045531.html
Copyright © 2020-2023  润新知