您的位置:首页 > 教程 > JAVA/JAVA编程 > Java服务调用RestTemplate与HttpClient的使用详解

Java服务调用RestTemplate与HttpClient的使用详解

2022-06-21 10:48:10 来源:易采站长站 作者:

Java服务调用RestTemplate与HttpClient的使用详解

目录
概述RestTemplate概述及依赖配置类使用GET请求POST请求上传文件HttpClient概述使用

rnz站长之家-易采站长站-Easck.Com

概述

常见的远程调用方式有以下2种:rnz站长之家-易采站长站-Easck.Com

    RPC:>Http: http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。 现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。

    如果项目全部采用 Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。rnz站长之家-易采站长站-Easck.Com

    如果项目的技术栈多样化,主要采用了Spring和SpringBoot框架,那么SpringCloud搭建微服务是不二之选,使用Http方式来实现服务间调用。rnz站长之家-易采站长站-Easck.Com

    java开发中,使用http连接,访问第三方网络接口,通常使用的连接工具为RestTemplate、HttpClient和OKHttp。rnz站长之家-易采站长站-Easck.Com

    rnz站长之家-易采站长站-Easck.Com

    RestTemplate

    rnz站长之家-易采站长站-Easck.Com

    概述及依赖

    HttpClient和OKHttp两种连接工具,使用起来比较复杂,如果使用spring框架,可以使用restTemplate来进行http连接请求。rnz站长之家-易采站长站-Easck.Com

    restTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。rnz站长之家-易采站长站-Easck.Com

    依赖rnz站长之家-易采站长站-Easck.Com

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>5.2.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.apache.httpcomponents</groupId>
        <artifactId>httpclient</artifactId>
        <version>4.5.7</version>
    </dependency>
    

    rnz站长之家-易采站长站-Easck.Com

    配置类

    基础配置rnz站长之家-易采站长站-Easck.Com

    @Configuration
    public class RestTemplateConfig {
       @Bean
       public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
           return new RestTemplate(factory);
       }
       @Bean
       public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
           SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
           factory.setReadTimeout(150 * 1000); // ms
           factory.setConnectTimeout(150 * 1000); // ms
           return factory;
       }
    }
    

    进阶配置rnz站长之家-易采站长站-Easck.Com

    import org.apache.http.client.HttpClient;
    import org.apache.http.conn.HttpClientConnectionManager;
    import org.apache.http.impl.client.HttpClientBuilder;
    import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
    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;
    @Configuration
    public class RestTemplateConfig {
        /**
         * http连接管理器
         */
        @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
         */
        @Bean
        public HttpClient httpClient(HttpClientConnectionManager poolingHttpClientConnectionManager) {
            HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
            // 设置http连接管理器
            httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager);
            /*// 设置重试次数,默认是3次,没有开启
            httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(3, true));*/
            // 设置默认请求头
            /*List<Header> headers = new ArrayList<>();
            headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"));
            headers.add(new BasicHeader("Accept-Encoding", "gzip,deflate"));
            headers.add(new BasicHeader("Accept-Language", "zh-CN"));
            headers.add(new BasicHeader("Connection", "Keep-Alive"));
            headers.add(new BasicHeader("Content-type", "application/json;charset=UTF-8"));
            httpClientBuilder.setDefaultHeaders(headers);*/
            return httpClientBuilder.build();
        }
        /**
         * 请求连接池配置
         * @param httpClient
         */
        @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模板
         */
        @Bean
        public RestTemplate restTemplate(ClientHttpRequestFactory clientHttpRequestFactory) {
            // 配置请求工厂
            return new RestTemplate(clientHttpRequestFactory);
        }
    }

    rnz站长之家-易采站长站-Easck.Com

    rnz站长之家-易采站长站-Easck.Com

    使用

    实体类rnz站长之家-易采站长站-Easck.Com

    @Data
    @Builder
    @NoArgsConstrutor
    @AllArgsConstrutor
    public class BaseResponse<TempUser> implements Serializable {
        private static final long serialVersionUID  = 1L;
        private String responseCode;
        private String responseMessage;
        private List<TempUser> responseData;
    }
    @Data
    @Builder
    @NoArgsConstrutor
    @AllArgsConstrutor
    public class TempUser implements Serializable {
        private static final long serialVersionUID  = 1L;
        private String userName;   
        private Integer age;
    }
    

    rnz站长之家-易采站长站-Easck.Com

    GET请求

    普通访问rnz站长之家-易采站长站-Easck.Com

    BaseResponse result = restTemplate.getForObject(
        "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", BaseResponse.class);
    

    返回HTTP状态rnz站长之家-易采站长站-Easck.Com

    ResponseEntity<BaseResponse> responseEntity = restTemplate.getForEntity(
        "http://localhost:8080/cs-admin/rest/getUser?userName=张三&age=18", TempUser.class);
    // 获取状态对象
    HttpStatus httpStatus = responseEntity.getStatusCode();
    // 获取状态码
    int statusCodeValue = responseEntity.getStatusCodeValue();
    // 获取headers
    HttpHeaders httpHeaders = responseEntity.getHeaders();
    // 获取body
    BaseResponse result = responseEntity.getBody();
    

    映射请求参数rnz站长之家-易采站长站-Easck.Com

    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("userName", "张三");
    paramMap.put("age", 18);
    BaseResponse result = restTemplate.getForObject(
        "http://localhost:8080/cs-admin/rest/getUser?userName={userName}&age={age}", 
        BaseResponse.class, paramMap);
    

    rnz站长之家-易采站长站-Easck.Com

    POST请求

    普通访问接口rnz站长之家-易采站长站-Easck.Com

    TempUser param = new TempUser();
    param.setUserName("张三");
    param.setAge(18);
    BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", 
                                                 param, BaseResponse.class);
    

    带HEAD访问接口rnz站长之家-易采站长站-Easck.Com

    // 请求头信息
    HttpHeaders headers = new HttpHeaders();
    //headers.setContentType(MediaType.valueOf("application/json;charset=UTF-8"));
    headers.setContentType(MediaType.APPLICATION_JSON_UTF8);
    //headers.add("headParam1", "headParamValue");
    // 请求体内容
    TempUser param = new TempUser();
    param.setUserName("张三");
    param.setAge(18);
    // 组装请求信息
    HttpEntity<TempUser> httpEntity=new HttpEntity<>(param, headers);
    BaseResponse result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", 
                                                 httpEntity, BaseResponse.class);

    无请求体的访问:仅method为post,传参方式仍然为get的param方式rnz站长之家-易采站长站-Easck.Com

    Map<String, Object> paramMap = new HashMap<>();
    paramMap.put("userName", "张三");
    paramMap.put("age", 18);
    BaseResponse result = restTemplate.postForObject(
        "http://localhost:8080/cs-admin/rest/getPostUserNoBody?userName={userName}&age={age}", 
        null, BaseResponse.class, paramMap);
    System.out.println(result);
    

    rnz站长之家-易采站长站-Easck.Com

    上传文件

    后台接口代码:rnz站长之家-易采站长站-Easck.Com

    @RequestMapping("uploadFile")
    public TempUser uploadFile(HttpServletRequest request, TempUser form) {
        MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request;
        //获取文件信息
        MultipartFile multipartFile = multipartHttpServletRequest.getFile("file");
        TempUser tempUser = new TempUser();
        if (multipartFile != null) {
            tempUser.setUserName(form.getUserName() + " " + multipartFile.getOriginalFilename());
        }
        if(form!=null){
            tempUser.setAge(form.getAge());
        }
        return tempUser;
    }
    

    访问方式:rnz站长之家-易采站长站-Easck.Com

    // 文件
    FileSystemResource file=new FileSystemResource("D:\\Elasticsearch权威指南(中文版).pdf");
    // 设置请求内容
    MultiValueMap<String, Object> param=new LinkedMultiValueMap<>();
    param.add("file", file);
    // 其他参数
    param.add("userName", "张三");
    param.add("age", 18);
    // 组装请求信息
    HttpEntity<MultiValueMap<String, Object>> httpEntity=new HttpEntity<>(param);
    // 发送请求
    TempUser result = restTemplate.postForObject("http://localhost:8080/cs-admin/rest/uploadFile", 
                                                 httpEntity, TempUser.class);
    

    rnz站长之家-易采站长站-Easck.Com

    HttpClient

    rnz站长之家-易采站长站-Easck.Com

    概述

    HttpClient>

      管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接每次调用后必须执行 releaseConnection路由可以理解为客户端机器到目标机器的一条线路如果不给 httpclient配置指定的连接管理器,httpclient会自动使用PoolingHttpClientConnectionManager作为连接管理器。PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。

      连接池:rnz站长之家-易采站长站-Easck.Com

        连接池技术作为创建和管理连接的缓冲池技术。连接池管理的对象是长连接有长连接的优势

        **长连接:**是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,rnz站长之家-易采站长站-Easck.Com

        优势:rnz站长之家-易采站长站-Easck.Com

          省去了每次数据传输连接建立的时间开销资源的访问控制

          **短连接:**每次数据传输都需要客户端和服务器端建立一次连接rnz站长之家-易采站长站-Easck.Com

          使用

          使用HttpClient发送请求、接收响应很简单,一般需要如下几步即可:rnz站长之家-易采站长站-Easck.Com

            创建HttpClient对象创建请求方法的实例,并指定请求URL。如果需要发送GET请求,创建HttpGet对象;如果需要发送POST请求,创建HttpPost对象。如果需要发送请求参数,可调用HttpGet、HttpPost共同的setParams(HetpParams>方法来添加请求参数;对于HttpPost对象而言,也可调用setEntity(HttpEntity entity)方法来设置请求参数,参数则必须用NameValuePair[]数组存储调用HttpClient对象的execute(HttpUriRequest request)发送请求,该方法返回一个HttpResponse调用HttpResponse的getAllHeaders()getHeaders(String name)等方法可获取服务器的响应头;调用HttpResponsegetEntity()方法可获取HttpEntity对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容释放连接。无论执行方法是否成功,都必须释放连接

            依赖:rnz站长之家-易采站长站-Easck.Com

            <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient</artifactId>
                <version>4.5.2</version>
            </dependency>
                <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpclient-cache</artifactId>
                <version>4.5.2</version>
            </dependency>
                <dependency>
                <groupId>org.apache.httpcomponents</groupId>
                <artifactId>httpmime</artifactId>
                <version>4.5.2</version>
            </dependency>
            

            java工具类rnz站长之家-易采站长站-Easck.Com

            import com.alibaba.fastjson.JSON;
            import lombok.extern.slf4j.Slf4j;
            import org.apache.commons.lang3.StringUtils;
            import org.apache.http.Consts;
            import org.apache.http.HttpResponse;
            import org.apache.http.NameValuePair;
            import org.apache.http.client.HttpClient;
            import org.apache.http.client.config.RequestConfig;
            import org.apache.http.client.entity.UrlEncodedFormEntity;
            import org.apache.http.client.methods.HttpGet;
            import org.apache.http.client.methods.HttpPost;
            import org.apache.http.entity.StringEntity;
            import org.apache.http.impl.client.HttpClients;
            import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
            import org.apache.http.message.BasicNameValuePair;
            import org.apache.http.util.EntityUtils;
            import org.slf4j.Logger;
            import java.net.URI;
            import java.nio.charset.StandardCharsets;
            import java.util.ArrayList;
            import java.util.List;
            import java.util.Map;
            /**
             * HttpClient 工具类
             */
            @Slf4j
            public class HttpClientUtil {
                public static final String APPLICATION_JSON_VALUE = "application/json";
                private static final Logger logger = log;
                private static final Integer CONN_TIME_OUT = 3000;// 超时时间豪秒
                private static final Integer SOCKET_TIME_OUT = 10000;
                /** 每个路由的最大请求数,默认2 */
                private static final Integer DEFAULT_MAX_PER_ROUTE = 40;
                /** 最大连接数,默认20 */
                private static final Integer MAX_TOTAL = 400;
                private static HttpClient httpClient;
                static {
                    // 请求配置
                    RequestConfig requestConfig = RequestConfig.custom()
                            .setConnectTimeout(CONN_TIME_OUT)
                            .setConnectionRequestTimeout(CONN_TIME_OUT)
                            .setSocketTimeout(SOCKET_TIME_OUT)
                            .build();
                    // 管理 http连接池
                    PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
                    cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE);
                    cm.setMaxTotal(MAX_TOTAL);
                    httpClient = HttpClients.custom()
                        .setConnectionManager(cm)
                        .setDefaultRequestConfig(requestConfig)
                        .build();
                }
                /**
                 * Get请求
                 */
                public static String requestGet(String url, Map<String, String> paramsMap) throws Exception {
                    logger.info("GET request  url:{} params:{}", url, paramsMap);
                    Long start = System.currentTimeMillis();
                    List<NameValuePair> params = initParams(paramsMap);
                    // Get请求
                    HttpGet httpGet = new HttpGet(url);
                    try {
                        // 设置参数
                        String str = EntityUtils.toString(new UrlEncodedFormEntity(params, StandardCharsets.UTF_8));
                        String uriStr = StringUtils.isEmpty(str) ? 
                            httpGet.getURI().toString() : httpGet.getURI().toString() + "?" + str;
                        httpGet.setURI(new URI(uriStr));
                        // 发送请求
                        HttpResponse response = httpClient.execute(httpGet);
                        logger.info("GET request  url:{} response:{} time:{}",
                                url, response, System.currentTimeMillis() - start);
                        // 获取返回数据
                        return getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
                    } finally {
                        // 必须释放连接,不然连接用完后会阻塞
                        httpGet.releaseConnection();
                    }
                }
                /**
                 * Post请求,Map格式数据
                 */
                public static String requestPost(String url, Map<String, String> paramsMap) throws Exception {
                    logger.info("POST request  url:{} params:{}", url, paramsMap);
                    Long start = System.currentTimeMillis();
                    List<NameValuePair> params = initParams(paramsMap);
                    HttpPost httpPost = new HttpPost(url);
                    try {
                        httpPost.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
                        HttpResponse response = httpClient.execute(httpPost);
                        logger.info("POST request  url:{} response:{}  time:{}",
                                url, response, System.currentTimeMillis() - start);
                        String retStr = getSuccessRetFromResp(response, url, JSON.toJSONString(paramsMap));
                        return retStr;
                    } finally {
                        httpPost.releaseConnection();
                    }
                }
                /**
                 * Post请求,json格式数据
                 *
                 */
                public static String requestPostJsonStr(String url, String json) throws Exception {
                    logger.info("POST request  url:{} params:{}", url, json);
                    long start = System.currentTimeMillis();
                    HttpPost httpPost = new HttpPost(url);
                    try {
                        StringEntity entity = new StringEntity(json, Consts.UTF_8);
                        entity.setContentType(APPLICATION_JSON_VALUE);
                        httpPost.setEntity(entity);
                        HttpResponse response = httpClient.execute(httpPost);
                        logger.info("POST request  url:{} response:{}  time:{}", 
                                    url, response, System.currentTimeMillis() - start);
                        return getSuccessRetFromResp(response, url, json);
                    } finally {
                        // 资源释放
                        httpPost.releaseConnection();
                    }
                }
                /**
                 * post Object格式数据
                 */
                public static String requestPostJson(String url, Object obj) throws Exception {
                    String params = JSON.toJSONString(obj);
                    return requestPostJsonStr(url, params);
                }
                private static String getSuccessRetFromResp(HttpResponse response, String url, String params) throws Exception {
                    String retStr = "";
                    // 检验状态码,如果成功接收数据
                    int code = response.getStatusLine().getStatusCode();
                    if (code == 200) {
                        retStr = EntityUtils.toString(response.getEntity(), Consts.UTF_8);
                    } else {
                        throw new RuntimeException(String.format("Http request error:%s, url:%s, params:%s", response, url, params));
                    }
                    logger.info("Http request retStr:{}. url:{}", retStr, url);
                    return retStr;
                }
                private static List<NameValuePair> initParams(Map<String, String> paramsMap) {
                    List<NameValuePair> params = new ArrayList<NameValuePair>();
                    if (paramsMap == null)
                        return params;
                    for (Map.Entry<String, String> entry : paramsMap.entrySet()) {
                        params.add(new BasicNameValuePair(entry.getKey(), entry.getValue()));
                    }
                    return params;
                }
            }

            到此这篇关于Java服务调用RestTemplate与HttpClient的使用详解的文章就介绍到这了,更多相关Java RestTemplate与HttpClient内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!rnz站长之家-易采站长站-Easck.Com

            如有侵权,请联系QQ:279390809 电话:15144810328

相关文章

  • Spring Cloud 整合Apache-SkyWalking实现链路跟踪的方法

    Spring Cloud 整合Apache-SkyWalking实现链路跟踪的方法

    什么是SkyWalking 查看官网https://skywalking.apache.org/ 分布式系统的应用程序性能监视工具,专为微服务、云原生架构和基于容器(Docker、K8s、Mesos)架构而设计。 安装 进入下载页面https://
    2020-06-18
  • 成功解决IDEA2020 Plugins 连不上、打不开的方法

    成功解决IDEA2020 Plugins 连不上、打不开的方法

    IntelliJ IDEA 2020.1 插件中心一直打不开,鉴于有部分同学反馈设置http proxy不能解决,所以可按以下顺序检查 一、设置 http proxy—勾上Auto-detect proxy setting,参照下图,加上地址 http://127.0.0
    2020-06-25
  • Java后台实现微信支付和微信退款

    Java后台实现微信支付和微信退款

    微信支付流程 都是我自己工作中开发的,亲测可用,不喜勿喷。 controller中我是这么写的,你们需要根据自己的业务需求改动。ResponseBean是我自己封装的,你们可以改成你们想要的形式
    2020-03-27
  • IDEA2020 1.1中Plugins加载不出来的问题及解决方法

    IDEA2020 1.1中Plugins加载不出来的问题及解决方法

    进入File-Setting 如图,取消勾选,点击确认后重启,点击了以后等一会就可以正常显示 ps:下面看下解决IDEA 2020.1.1 找不到程序包和符号 问题描述 IDEA 2020.1.1 maven项目build的时候报错,找
    2020-06-28
  • Intellij idea热部署插件JRebel的使用

    Intellij idea热部署插件JRebel的使用

    项目需求,一直用eclipse的我,也要改用IDEA了,一开始,很不习惯。经过几天的慢慢摸索和习惯之后,发现IDEA确实很好用。dark的界面是我喜欢的,智能的提示也让写代码不再枯燥。 遗
    2020-06-25
  • 详解基于IDEA2020.1的JAVA代码提示插件开发例子

    详解基于IDEA2020.1的JAVA代码提示插件开发例子

    之前因为项目组有自己的代码规范,为了约束平时的开发规范,于是基于2019.1.3版本开发了一个代码提示的插件。但是在把IDEA切换到2020.1版本的时候,却发现疯狂报错,但是网上关于
    2020-06-25
  • springboot + rabbitmq 如何实现消息确认机制(踩坑经验)

    springboot + rabbitmq 如何实现消息确认机制(踩坑经验)

    本文收录在个人博客:www.chengxy-nds.top,技术资源共享,一起进步 最近部门号召大伙多组织一些技术分享会,说是要活跃公司的技术氛围,但早就看穿一切的我知道,这 T M 就是为了刷
    2020-07-01
  • JetBrains IntelliJ IDEA 2020安装与使用教程详解

    JetBrains IntelliJ IDEA 2020安装与使用教程详解

    对于JetBrains IntelliJ IDEA 2020的认识 IntelliJ IDEA 2020是一款JAVA编程软件,捷克IntelliJ公司研发推出。该软件提供了一个非常强大的JAVA集成开发环境,不仅添加了对Records的完整代码洞察支持,
    2020-06-28