• Springcloud学习笔记42利用HttpClient实现服务A向服务B发送Http请求


    1.服务A发送Http请求

    1.1 在yml文件中配置Http的相关参数

    http:
      maxTotal: 100
      defaultMaxPerRoute: 20
      connectTimeout: 1000
      connectionRequestTimeout: 500
      socketTimeout: 10000
      staleConnectionCheckEnable: true

    1.2 编写HttpClient的相关配置类

    1.2.1  @Configuration

    @Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。

    • @Configuration配置spring并启动spring容器
    • @Configuration启动容器+@Bean注册Bean
    • @Configuration启动容器+@Component注册Bean

    使用 AnnotationConfigApplicationContext 注册 AppContext 类的两种方法
    配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)

    注意:@Configuration注解的类在springboot启动时就会加载;

    2022-03-25 15:15:51.116 | INFO  | main | org.springframework.web.context.ContextLoader:283 | [] - Root WebApplicationContext: initialization completed in 1270 ms
    //此时,进入断点
    2022-03-25 15:41:08.945 | INFO  | main | com.ttbank.flep.core.FileFlepApplication:59 | [] - Started FileFlepApplication in 238.843 seconds (JVM running for 240.545)

    在Root WebApplicationContext: initialization completed启动完成之后,会进入debug状态;

    1.3.2 @Component和@Bean注解

    @Component注解表明一个类会作为组件类,并告知Spring要为这个类创建bean。

    @Bean注解告诉Spring这个方法将会返回一个对象,这个对象要注册为Spring应用上下文中的bean。通常方法体中包含了最终产生bean实例的逻辑。

    两者的目的是一样的,都是注册bean到Spring容器中。

    package com.ttbank.flep.core.config;
    
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    import org.springframework.beans.factory.annotation.Qualifier;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    import java.util.concurrent.TimeUnit;
    
    @Configuration
    public class HttpClientConfig {
        @Value("${http.maxTotal}")
        private Integer maxTotal;
    
        @Value("${http.defaultMaxPerRoute}")
        private Integer defaultMaxPerRoute;
    
        @Value("${http.connectTimeout}")
        private Integer connectTimeout;
    
        @Value("${http.connectionRequestTimeout}")
        private Integer connectionRequestTimeout;
    
        @Value("${http.socketTimeout}")
        private Integer socketTimeout;
    
        @Value("${http.staleConnectionCheckEnable}")
        private boolean staleConnectionCheckEnable;
    
        /**
         * 首先实例化一个连接管理器,设置最大连接数,并发数
         */
        @Bean(name="httpClientConnectionManager")
        public PoolingHttpClientConnectionManager getHttpClientConnectionManager(){
            PoolingHttpClientConnectionManager httpClientConnectionManager=new PoolingHttpClientConnectionManager();
            //最大连接数
            httpClientConnectionManager.setMaxTotal(maxTotal);
            //并发数
            httpClientConnectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute);
            return httpClientConnectionManager;
    
        }
    
        /**
         * 实例化连接池
         */
        @Bean(name="httpClientBuilder")
        public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){
            HttpClientBuilder httpClientBuilder=HttpClientBuilder.create();
            httpClientBuilder.setConnectionManager(httpClientConnectionManager);
            //以下可不设置,如果指定了要清理的过期连接,才会启动清理线程,默认不启动。会有一个单独的线程来扫描连接池中的连接,发现离最近一次使用超时设置后,就会清理。
            //设置是否清理过期连接
            httpClientBuilder.evictExpiredConnections();
            //连接存活时间
            httpClientBuilder.setConnectionTimeToLive(10000, TimeUnit.SECONDS);
            //设置清理空闲连接的时间
            httpClientBuilder.evictIdleConnections(60000, TimeUnit.MILLISECONDS);
            return httpClientBuilder;
        }
    
    
        /**
         * 注入连接池,用于获取httpclient
         */
        @Bean
        public CloseableHttpClient getCloseableHttpClient(@Qualifier("httpClientBuilder")HttpClientBuilder httpClientBuilder){
            return httpClientBuilder.build();
        }
    
        /**
         * Builder是RequestConfig的一个内部类,利用custom方法可获取一个Builder对象
         * 设置builder的连接信息
         */
        @Bean(name="builder")
        public RequestConfig.Builder getBuilder(){
            RequestConfig.Builder builder = RequestConfig.custom();
            return builder.setConnectTimeout(connectTimeout)
                    .setConnectionRequestTimeout(connectionRequestTimeout)
                    .setSocketTimeout(socketTimeout);
        }
    
        /**
         * 使用builder构建一个RequestConfig对象
         */
        @Bean
        public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
            return builder.build();
        }
    }

    1.3 HttpClientUtil

    采用@Component注解将这个类交给spring容器管理;因此,HttpClientUtil类中的两个成员变量httpClient,requestConfig可以由spring完成对象的注入;

    注意:使用HttpClientUtil类,必须采用@autowired注解进行注入,不能采用new 对象的方式;

    package com.ttbank.flep.core.util;
    
    import com.ttbank.flep.core.dto.Result;
    import org.apache.http.Consts;
    import org.apache.http.HttpEntity;
    import org.apache.http.NameValuePair;
    import org.apache.http.client.config.RequestConfig;
    import org.apache.http.client.entity.UrlEncodedFormEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.client.utils.URIBuilder;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.StringEntity;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    import org.apache.http.entity.mime.content.StringBody;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.message.BasicNameValuePair;
    import org.apache.http.util.EntityUtils;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Component;
    
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Map;
    
    /**
     * @Author lucky
     * @Date 2022/3/25 9:23
     */
    @Component
    public class HttpClientUtil {
        @Autowired
        private CloseableHttpClient httpClient;
    
        @Autowired
        private RequestConfig requestConfig;
    
        public Result doPost(String url) throws Exception{
            return this.doPost(url,null);
        }
    
        /**
         * 带参数的post方法
         * @param url
         * @param map
         */
        public Result doPost(String url, Map<String, Object> map) throws Exception{
            HttpPost httpPost=new HttpPost(url);
            httpPost.setConfig(requestConfig);
            if(map!=null){
                List<NameValuePair> list=new ArrayList<>();
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    list.add(new BasicNameValuePair(entry.getKey(),entry.getValue().toString() ));
                }
                //构造form表单对象
                UrlEncodedFormEntity urlEncodedFormEntity=new UrlEncodedFormEntity(list,"UTF-8");
                //把表单放到post里
                httpPost.setEntity(urlEncodedFormEntity);
            }
            //发起请求
            CloseableHttpResponse response = this.httpClient.execute(httpPost);
            return new Result(String.valueOf(response.getStatusLine().getStatusCode()),"",EntityUtils.toString(response.getEntity(),"UTF-8"));
        }
    
        public Result doPostJson(String url,String json) throws Exception{
            HttpPost httpPost=new HttpPost(url);
            httpPost.setConfig(requestConfig);
            StringEntity entity=new StringEntity(json);
            httpPost.setEntity(entity);
            httpPost.setHeader("Accept","application/json");
            httpPost.setHeader("Content-type","application/json");
            CloseableHttpResponse response=this.httpClient.execute(httpPost);
            return new Result(String.valueOf(response.getStatusLine().getStatusCode()),"",EntityUtils.toString(response.getEntity(),"UTF-8"));
        }
    
        public Result doPostFile(String url, String key,String params, InputStream fileInputStream) throws IOException {
            HttpPost httpPost=new HttpPost(url);
            httpPost.setConfig(requestConfig);
            MultipartEntityBuilder builder = MultipartEntityBuilder.create();
            builder.addBinaryBody("file",fileInputStream, ContentType.create("multipart/form-data"),"test" );
            StringBody body=new StringBody(params,ContentType.create("text/plain", Consts.UTF_8 ));
            builder.addPart(key,body);
            HttpEntity entity=builder.build();
            httpPost.setEntity(entity);
            //发起请求
            CloseableHttpResponse response = this.httpClient.execute(httpPost);
            return new Result(String.valueOf(response.getStatusLine().getStatusCode()),"",EntityUtils.toString(response.getEntity(),"UTF-8"));
        }
    
        /**
         * 不带参数的get请求
         * @param url
         */
        public Result doGet(String url) throws IOException {
            HttpGet httpGet=new HttpGet(url);
            //加载配置信息
            httpGet.setConfig(requestConfig);
            //发起请求
            CloseableHttpResponse response = this.httpClient.execute(httpGet);
            return new Result(String.valueOf(response.getStatusLine().getStatusCode()),"",EntityUtils.toString(response.getEntity(),"UTF-8"));
        }
    
        public Result doGet(String url,Map<String,Object> map) throws Exception{
            URIBuilder uriBuilder=new URIBuilder(url);
            if(map!=null){
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    uriBuilder.setParameter(entry.getKey(),entry.getValue().toString() );
                }
            }
            return this.doGet(uriBuilder.build().toString());
        }
    }

    1.4 使用测试案例

    package com.ttbank.flep.core.controller;
    
    import com.sun.media.jfxmedia.logging.Logger;
    import com.ttbank.flep.core.util.HttpClientUtil;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Author lucky
     * @Date 2022/3/25 11:41
     */
    @RestController
    @RequestMapping("/httpclient")
    @Slf4j
    public class HttpClientController {
        @Autowired
        HttpClientUtil httpClientUtil;
    
        @PostMapping("/sayHello")
        public void sayHello(){
            String url="http://127.0.0.1:7011/task/getAttr";
            Map<String,Object> paramMap=new HashMap<>();
            paramMap.put("name","lucky" );
            paramMap.put("address","tiantai" );
            try {
                httpClientUtil.doPost(url,paramMap);
                log.info("send OK");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        @GetMapping("/sayBye")
        public void sayBye(){
            String url="http://127.0.0.1:7011/task/getInfo";
            Map<String,Object> paramMap=new HashMap<>();
            paramMap.put("name","linda" );
            paramMap.put("address","hangzhou" );
            try {
                httpClientUtil.doGet(url,paramMap);
                log.info("send success");
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    1.5 postman调用

    http://127.0.0.1:7010/httpclient/sayBye

    2.服务B接收Http请求

    package com.ttbank.flep.task.controller;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.bind.annotation.*;
    
    /**
     * @Author lucky
     * @Date 2022/3/25 14:31
     */
    @RestController
    @RequestMapping("/task")
    @Slf4j
    public class TaskController {
        @PostMapping("/getAttr")
        public void getAttr(@RequestParam String name,@RequestParam String address){
            log.info(name+":"+address);
        }
    
        @GetMapping("/getInfo")
        public void getInfo(@RequestParam String name,@RequestParam String address){
            log.info(name+":"+address);
        }
    }

    此时,控制台输出日志:

    2022-03-25 17:25:04.985 | INFO  | http-nio-7011-exec-8 | com.ttbank.flep.task.controller.TaskController:19 | [] - lucky:tiantai
    2022-03-25 17:50:42.897 | INFO  | http-nio-7011-exec-5 | com.ttbank.flep.task.controller.TaskController:21 | [] - linda:hangzhou
  • 相关阅读:
    [POJ2752]Seek the Name, Seek the Fame
    [HDOJ1247]Hat’s Words
    [POJ2001]Shortest Prefixes
    不用代码,10分钟打造属于自己的第一款小程序
    不用代码,10分钟打造属于自己的第一款小程序
    不用代码,10分钟打造属于自己的第一款小程序
    移动端iPhone系列适配问题的一些坑
    移动端iPhone系列适配问题的一些坑
    【前端统计图】echarts多条折线图和横柱状图实现
    【前端统计图】echarts多条折线图和横柱状图实现
  • 原文地址:https://www.cnblogs.com/luckyplj/p/16055409.html
Copyright © 2020-2023  润新知