服务器间相互调用的技术HttpClient与RestTemplate

前言

HttpClient与RestTemplate是近期新学的技术,特以笔记写一篇博客,希望对正在学习这项技术的朋友有所帮助

1.什么是HttpClient?

服务器间相互调用的技术,是Apache提供的

2.什么是HttpComponents?

是HttpClient的别名

3.什么是RestTemplate?

是Spring提供的,与HttpClient的作用或者功能都是一样的,两者互为代替,但是restTemplast更为简单


1.HttpClient的使用

1.1.在SpringBoot项目中的pom文件中引入HttpClient的依赖
								<dependency>
                    <groupId>org.apache.httpcomponentsgroupId>
                    <artifactId>httpclientartifactId>
                dependency>

2.HttpClient的入门案例

在SpringBoot项目的测试类中,定义一个测试方法,在这个测试方法中,编写请求百度的请求代码,最后运行测试类,测试类中的请求访问的地址是百度,模拟两个服务器之间的访问(SpringBoot中的测试方法代表一个服务器,百度是一个服务器)

2.1.代码如下
 /**
     * HttpClient入门案例 向百度发起GET请求(不带参)
     * @throws IOException
     */
    @Test
    void httpGet() throws IOException {
        //创建Httpclient,相当于打开了浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //创建HttpGet请求,相当于在浏览器输入地址
        HttpGet httpGet = new HttpGet("http://www.baidu.com/");

        CloseableHttpResponse response = null;


        try {
            //执行请求,相当于敲完地址后按下回车,获取响应
            response = httpClient.execute(httpGet);
            //判断返回状态是否为 200
            if (response.getStatusLine().getStatusCode() == 200) {
                //解析响应,获取数据
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(content);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                //关闭资源
                response.close();
            }
            //关闭浏览器
            httpClient.close();
        }
    }
2.2.请求响应结果

服务器间相互调用的技术HttpClient与RestTemplate_第1张图片

2.3.其他的请求方式代码

HttpGet(携带参数)

 /**
     * 带参数的GET请求
     */
    @Test
    void httpGet_takingGinseng() throws Exception {
        //创建一个HttpClient对象,相当于打开浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();
        //创建URL对象,并设置请求参数
        URI uri = new URIBuilder("http://www.baidu.com/s?").setParameter("wd", "java").build();
        log.info("uri:" + uri);
        //创建http GET请求
        HttpGet httpGet = new HttpGet(uri);

        //带参GET请求也可以这么写
        //HttpGet httpGet = new HttpGet("http://www.baidu.com/s?wd=java");

        CloseableHttpResponse response = null;

        try {
            //执行GET请求
            response = httpClient.execute(httpGet);

            //判断返回状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                //解析响应数据
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                //关闭资源
                response.close();
            }
            //关闭浏览器
            httpClient.close();
        }
    }

HttpPost(不携带参数)

		/**
     * 发起POST请求
     */
    @Test
    void HttpPost () throws IOException, URISyntaxException {

        //创建HttpClient,相当于浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //创建Http Post请求
        HttpPost httpPost = new HttpPost(new URI("http://www.oschina.net/"));

        //把自己伪装成浏览器,否则开源中国会拦截访问

        httpPost.setHeader("User-Agent","Mozilla/5.0 (windows NT10.0;WOW64)AppleWebKit/537.36 (KHTML,like,Gecko) chrome/56.0.2924.87 Safari/537.36");

        CloseableHttpResponse response = null;

        //执行请求
        try {
            response = httpClient.execute(httpPost);
            //判断返回的状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                //解析响应数据
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if (response != null) {
                //关闭资源
                response.close();
            }

            //关闭浏览器
            httpClient.close();
        }
    }

HttpPost(携带参数)

/**
     * POST请求携带参数
     * @throws IOException
     */
    @Test
    void httpPost_takingGinseng () throws IOException {
        System.setProperty("http.proxyHost", "myProxyServer.com");System.setProperty("http.proxyPort", "80");
        //创建HttpClient对象,相当于打开浏览器
        CloseableHttpClient httpClient = HttpClients.createDefault();

        //创建Http POST请求,访问开源中国
        HttpPost httpPost = new HttpPost("http://www.oschina.net/seach");
        httpPost.setHeader("User-Agent","Mozilla/5.0 (windows NT10.0;WOW64)AppleWebKit/537.36 (KHTML,like,Gecko) chrome/56.0.2924.87 Safari/537.36");

        //根据开源中国的请求需求,设置post请求参数
        List<NameValuePair> parameters = new ArrayList<>(0);
        parameters.add(new BasicNameValuePair("scope","project"));
        parameters.add(new BasicNameValuePair("q","java"));
        parameters.add(new BasicNameValuePair("fromerr","8bDnUWwC"));

        //构造一个form表单式的实体
        UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(parameters);

        //将请求实体设置到HttpPost对象中
        httpPost.setEntity(formEntity);

        CloseableHttpResponse response = null;

        try {
            //执行post请求
            response = httpClient.execute(httpPost);
            //判断返回的状态是否为200
            if (response.getStatusLine().getStatusCode() == 200) {
                //解析响应体
                String content = EntityUtils.toString(response.getEntity(), "UTF-8");
                System.out.println(content);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                //关闭资源
                response.close();
            }
            //关闭浏览器
            httpClient.close();
        }
    }

4.RestTemplate的使用

1.需要在SpringBoot启动类中或者配置类中将RestTemplate对象交给Spring容器管理

2.在SpringBoot项目中的pom.xml文件中添加spring-boot-starter-web依赖(这个依赖是SpringBoot整合SpringMVC)

 					<dependency>
                <groupId>org.springframework.bootgroupId>
                <artifactId>spring-boot-starter-webartifactId>=
            dependency>
4.1.基本配置

1.在SpringBoot启动类中将RestTemplate交给Spring管理

此中方式解决了Post请求乱码的问题

    /**
     * 注入HttpTemplate
     * @return
     */
    @Bean
    public RestTemplate restTemplate () {
        RestTemplate restTemplate = new RestTemplate();
        List<HttpMessageConverter<?>> list = restTemplate.getMessageConverters();
        for (HttpMessageConverter<?> mc : list) {
            if (mc instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) mc).setDefaultCharset(Charset.forName("UTF-8"));
            }
        }
        return restTemplate;
    }

2.在配置类中将RestTemplate添加到Spring容器中

注意:我这里配置类中需要参数是从application.properties中读取出来的

此中方式解决了Post请求乱码的问题

HttpClientConfig.java

package com.czxy.config;

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.HttpMessageConverter;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.Charset;
import java.util.List;

/**
 * @Author ScholarTang
 * @Date 2019/11/28 3:41 PM
 * @Desc HttpClient配置类
 */

/**
 * HttpClient的配置类
 */
@Configuration
@ConfigurationProperties(prefix = "http", ignoreUnknownFields = true)
public class HttpClientConfig {

    private Integer maxTotal;// 最大连接

    private Integer defaultMaxPerRoute;// 每个host的最大连接

    private Integer connectTimeout;// 连接超时时间

    private Integer connectionRequestTimeout;// 请求超时时间

    private Integer socketTimeout;// 响应超时时间
    /**
     * HttpClient连接池
     * @return
     */
    @Bean
    public HttpClientConnectionManager httpClientConnectionManager() {
        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(maxTotal);
        connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
        return connectionManager;
    }

    /**
     * 注册RequestConfig
     * @return
     */
    @Bean
    public RequestConfig requestConfig() {
        return RequestConfig.custom().setConnectTimeout(connectTimeout)
                .setConnectionRequestTimeout(connectionRequestTimeout).setSocketTimeout(socketTimeout)
                .build();
    }

    /**
     * 注册HttpClient
     * @param manager
     * @param config
     * @return
     */
    @Bean
    public HttpClient httpClient(HttpClientConnectionManager manager, RequestConfig config) {
        return HttpClientBuilder.create().setConnectionManager(manager).setDefaultRequestConfig(config)
                .build();
    }
    /**
     * 使用连接池管理连接
     * @param httpClient
     * @return
     */
    @Bean
    public ClientHttpRequestFactory requestFactory(HttpClient httpClient) {
        return new HttpComponentsClientHttpRequestFactory(httpClient);
    }
    /**
     * 使用HttpClient来初始化一个RestTemplate
     * @param requestFactory
     * @return
     */
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory requestFactory) {
        RestTemplate template = new RestTemplate(requestFactory);

        List<HttpMessageConverter<?>> list = template.getMessageConverters();
        for (HttpMessageConverter<?> mc : list) {
            if (mc instanceof StringHttpMessageConverter) {
                ((StringHttpMessageConverter) mc).setDefaultCharset(Charset.forName("UTF-8"));
            }
        }
        return template;
    }

    public Integer getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(Integer maxTotal) {
        this.maxTotal = maxTotal;
    }

    public Integer getDefaultMaxPerRoute() {
        return defaultMaxPerRoute;
    }

    public void setDefaultMaxPerRoute(Integer defaultMaxPerRoute) {
        this.defaultMaxPerRoute = defaultMaxPerRoute;
    }

    public Integer getConnectTimeout() {
        return connectTimeout;
    }

    public void setConnectTimeout(Integer connectTimeout) {
        this.connectTimeout = connectTimeout;
    }

    public Integer getConnectionRequestTimeout() {
        return connectionRequestTimeout;
    }

    public void setConnectionRequestTimeout(Integer connectionRequestTimeout) {
        this.connectionRequestTimeout = connectionRequestTimeout;
    }

    public Integer getSocketTimeout() {
        return socketTimeout;
    }

    public void setSocketTimeout(Integer socketTimeout) {
        this.socketTimeout = socketTimeout;
    }
}

application.properties

#The config for HttpClient
http.maxTotal=300
http.defaultMaxPerRoute=50
http.connectTimeout=1000
http.connectionRequestTimeout=500
http.socketTimeout=5000
http.staleConnectionCheckEnabled=true

注意:在配置类中进行配置时idea会有如下图所示的提醒

在这里插入图片描述

原因:是因为在配置类中使用类@ConfigurationProperties(prefix = “http”, ignoreUnknownFields = true)注解,该注解的作用是从application.properties文件中读取对应的数据(该注解中的属性和属性值只是对针对与该配置类有用)

解决方案:在pom.xml文件中添加下面这个依赖

  			 				<dependency>
                    <groupId>org.springframework.bootgroupId>
                    <artifactId>spring-boot-configuration-processorartifactId>
                    <optional>trueoptional>
                dependency>
4.2.使用的参考代码(这里的请求我是在SprigBoot中的测试类中完成的)
code

Get请求

 /**
     * 模拟Get请求,请求另一个服务器的接口的数据(携带参数:分页 + 多条件模糊查询的参数)
     * @throws URISyntaxException
     */
    @Test
    void selectLike() throws URISyntaxException {
        URI uri = new URIBuilder("http://localhost:8023/pageListProducts").setParameter("page", "1").setParameter("rows", "3").setParameter("productName", null).setParameter("low", "0").setParameter("tall", "0").build();
        String jsonData = this.restTemplate.getForObject(uri,String.class);
        log.info("jsonData:"+jsonData);
    }

Post请求

/**
     * 模拟Post请求,这里是一个添加的操作,从服务器1将数据传到服务器2,然后服务器2接收数据,并储存
     */
    @Test
    void addProduct() {
        TbProduct product = new TbProduct(null,"iPhoneXS",12999.0,new Date(),1,3);

        Map<String, Object> map = new HashMap<>();
        map.put("productid", null);
        map.put("productName", "爱的魔力转圈圈");
        map.put("productPrice", 9999.0);
        map.put("productTime", new Date());
        map.put("brandid", 1);
        map.put("categoryid",3);
        //TODO 方法 传对象传集合都可以
        String jsonData = this.restTemplate.postForObject("http://localhost:8023/addProduct",map,String.class);
        log.info("jsonData:"+jsonData);
    }

Put请求

/**
     * 模拟Put请求,这里是一个修改的操作,也是从服务器1将数据传到服务器2,然后服务器2接收数据,对根据数据对表中的记录进行修改
     */
    @Test
    void updateProduct () {
        TbProduct product = new TbProduct(1,"RestTemplate",29999.0,new Date(),2,3);

        Map<String, Object> map = new HashMap<>();
        map.put("productid", 1);
        map.put("productName", "爱的魔力转圈圈");
        map.put("productPrice", 9999.0);
        map.put("productTime", new Date());
        map.put("brandid", 1);
        map.put("categoryid",3);
        //TODO 传对象传集合都可以
        this.restTemplate.put("http://localhost:8023/updateProductById",map);
    }

Delete请求

/**
     * 模拟delete请求,将记录的主键通过服务器1的接口(我这里使用的SpringBoot的测试类)请求服务器2,服务器2根据ID删除记录
     */
    @Test
    void deletedProduct () {
        this.restTemplate.delete("http://localhost:8023delAllByIds/"+1);
    }

你可能感兴趣的:(服务器间相互调用的技术HttpClient与RestTemplate)