Java服务RestTemplate与HttpClient怎么使用
概述
常见的远程调用方式有以下2种:
RPC: Remote Produce Call远程过程调用,类似的还有RMI(remote method invoke)。自定义数据格式,基于原生TCP通信,速度快,效率高。早期的webservice,现在热门的dubbo,都是RPC的典型代表。
Http: http其实是一种网络传输协议,基于TCP,规定了数据传输的格式。 现在客户端浏览器与服务端通信基本都是采用Http协议,也可以用来进行远程服务调用。缺点是消息封装臃肿,优势是对服务的提供和调用方没有任何技术限定,自由灵活,更符合微服务理念。现在热门的Rest风格,就可以通过http协议来实现。
如果项目全部采用 Java技术栈,那么使用Dubbo作为微服务架构是一个不错的选择。
如果项目的技术栈多样化,主要采用了Spring和SpringBoot框架,那么SpringCloud搭建微服务是不二之选,使用Http方式来实现服务间调用。
java开发中,使用http连接,访问第三方网络接口,通常使用的连接工具为RestTemplate、HttpClient和OKHttp。
RestTemplate
概述及依赖
HttpClient和OKHttp两种连接工具,使用起来比较复杂,如果使用spring框架,可以使用restTemplate来进行http连接请求。
restTemplate默认的连接方式是java中的HttpConnection,可以使用ClientHttpRequestFactory指定不同的HTTP连接方式。
依赖
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>
配置类
基础配置
@Configuration publicclassRestTemplateConfig{ @Bean publicRestTemplaterestTemplate(ClientHttpRequestFactoryfactory){ returnnewRestTemplate(factory); } @Bean publicClientHttpRequestFactorysimpleClientHttpRequestFactory(){ SimpleClientHttpRequestFactoryfactory=newSimpleClientHttpRequestFactory(); factory.setReadTimeout(150*1000); //ms factory.setConnectTimeout(150*1000); //ms returnfactory; } }
进阶配置
importorg.apache.http.client.HttpClient; importorg.apache.http.conn.HttpClientConnectionManager; importorg.apache.http.impl.client.HttpClientBuilder; importorg.apache.http.impl.conn.PoolingHttpClientConnectionManager; importorg.springframework.context.annotation.Bean; importorg.springframework.context.annotation.Configuration; importorg.springframework.http.client.ClientHttpRequestFactory; importorg.springframework.http.client.HttpComponentsClientHttpRequestFactory; importorg.springframework.web.client.RestTemplate; @Configuration publicclassRestTemplateConfig{ /** *http连接管理器 */ @Bean publicHttpClientConnectionManagerpoolingHttpClientConnectionManager(){ /*//注册http和https请求 RegistryConnectionSocketFactory> registry=RegistryBuilder.ConnectionSocketFactory> create() .register("http",PlainConnectionSocketFactory.getSocketFactory()) .register("https",SSLConnectionSocketFactory.getSocketFactory()) .build(); PoolingHttpClientConnectionManagerpoolingHttpClientConnectionManager=newPoolingHttpClientConnectionManager(registry); */ PoolingHttpClientConnectionManagerpoolingHttpClientConnectionManager=newPoolingHttpClientConnectionManager(); //最大连接数 poolingHttpClientConnectionManager.setMaxTotal(500); //同路由并发数(每个主机的并发) poolingHttpClientConnectionManager.setDefaultMaxPerRoute(100); returnpoolingHttpClientConnectionManager; } /** *HttpClient *@parampoolingHttpClientConnectionManager */ @Bean publicHttpClienthttpClient(HttpClientConnectionManagerpoolingHttpClientConnectionManager){ HttpClientBuilderhttpClientBuilder=HttpClientBuilder.create(); //设置http连接管理器 httpClientBuilder.setConnectionManager(poolingHttpClientConnectionManager); /*//设置重试次数,默认是3次,没有开启 httpClientBuilder.setRetryHandler(newDefaultHttpRequestRetryHandler(3,true)); */ //设置默认请求头 /*ListHeader> headers=newArrayList> (); headers.add(newBasicHeader("User-Agent","Mozilla/5.0(WindowsNT6.1)AppleWebKit/537.36(KHTML,likeGecko)Chrome/31.0.1650.16Safari/537.36")); headers.add(newBasicHeader("Accept-Encoding","gzip,deflate")); headers.add(newBasicHeader("Accept-Language","zh-CN")); headers.add(newBasicHeader("Connection","Keep-Alive")); headers.add(newBasicHeader("Content-type","application/json; charset=UTF-8")); httpClientBuilder.setDefaultHeaders(headers); */ returnhttpClientBuilder.build(); } /** *请求连接池配置 *@paramhttpClient */ @Bean publicClientHttpRequestFactoryclientHttpRequestFactory(HttpClienthttpClient){ HttpComponentsClientHttpRequestFactoryclientHttpRequestFactory=newHttpComponentsClientHttpRequestFactory(); //httpClient创建器 clientHttpRequestFactory.setHttpClient(httpClient); //连接超时时间/毫秒(连接上服务器(握手成功)的时间,超出抛出connecttimeout) clientHttpRequestFactory.setConnectTimeout(5*1000); //数据读取超时时间(socketTimeout)/毫秒(服务器返回数据(response)的时间,超过抛出readtimeout) clientHttpRequestFactory.setReadTimeout(10*1000); //从连接池获取请求连接的超时时间,不宜过长,必须设置/毫秒(超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException:Timeoutwaitingforconnectionfrompool) clientHttpRequestFactory.setConnectionRequestTimeout(10*1000); returnclientHttpRequestFactory; } /** *rest模板 */ @Bean publicRestTemplaterestTemplate(ClientHttpRequestFactoryclientHttpRequestFactory){ //配置请求工厂 returnnewRestTemplate(clientHttpRequestFactory); } }
使用
实体类
@Data @Builder @NoArgsConstrutor @AllArgsConstrutor publicclassBaseResponseTempUser> implementsSerializable{ privatestaticfinallongserialVersionUID=1L; privateStringresponseCode; privateStringresponseMessage; privateListTempUser> responseData; }
@Data @Builder @NoArgsConstrutor @AllArgsConstrutor publicclassTempUserimplementsSerializable{ privatestaticfinallongserialVersionUID=1L; privateStringuserName; privateIntegerage; }
GET请求
普通访问
BaseResponseresult=restTemplate.getForObject( "http://localhost:8080/cs-admin/rest/getUser?userName=张三& age=18",BaseResponse.class);
返回HTTP状态
ResponseEntityBaseResponse> responseEntity=restTemplate.getForEntity( "http://localhost:8080/cs-admin/rest/getUser?userName=张三& age=18",TempUser.class); //获取状态对象 HttpStatushttpStatus=responseEntity.getStatusCode(); //获取状态码 intstatusCodeValue=responseEntity.getStatusCodeValue(); //获取headers HttpHeadershttpHeaders=responseEntity.getHeaders(); //获取body BaseResponseresult=responseEntity.getBody();
映射请求参数
MapString,Object> paramMap=newHashMap> (); paramMap.put("userName","张三"); paramMap.put("age",18); BaseResponseresult=restTemplate.getForObject( "http://localhost:8080/cs-admin/rest/getUser?userName={ userName} & age={ age} ", BaseResponse.class,paramMap);
POST请求
普通访问接口
TempUserparam=newTempUser(); param.setUserName("张三"); param.setAge(18); BaseResponseresult=restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", param,BaseResponse.class);
带HEAD访问接口
//请求头信息 HttpHeadersheaders=newHttpHeaders(); //headers.setContentType(MediaType.valueOf("application/json; charset=UTF-8")); headers.setContentType(MediaType.APPLICATION_JSON_UTF8); //headers.add("headParam1","headParamValue"); //请求体内容 TempUserparam=newTempUser(); param.setUserName("张三"); param.setAge(18); //组装请求信息 HttpEntityTempUser> httpEntity=newHttpEntity> (param,headers); BaseResponseresult=restTemplate.postForObject("http://localhost:8080/cs-admin/rest/getPostUser", httpEntity,BaseResponse.class);
无请求体的访问:仅method为post,传参方式仍然为get的param方式
MapString,Object> paramMap=newHashMap> (); paramMap.put("userName","张三"); paramMap.put("age",18); BaseResponseresult=restTemplate.postForObject( "http://localhost:8080/cs-admin/rest/getPostUserNoBody?userName={ userName} & age={ age} ", null,BaseResponse.class,paramMap); System.out.println(result);
上传文件
后台接口代码:
@RequestMapping("uploadFile") publicTempUseruploadFile(HttpServletRequestrequest,TempUserform){ MultipartHttpServletRequestmultipartHttpServletRequest=(MultipartHttpServletRequest)request; //获取文件信息 MultipartFilemultipartFile=multipartHttpServletRequest.getFile("file"); TempUsertempUser=newTempUser(); if(multipartFile!=null){ tempUser.setUserName(form.getUserName()+""+multipartFile.getOriginalFilename()); } if(form!=null){ tempUser.setAge(form.getAge()); } returntempUser; }
访问方式:
//文件 FileSystemResourcefile=newFileSystemResource("D:\\Elasticsearch权威指南(中文版).pdf"); //设置请求内容 MultiValueMapString,Object> param=newLinkedMultiValueMap> (); param.add("file",file); //其他参数 param.add("userName","张三"); param.add("age",18); //组装请求信息 HttpEntityMultiValueMapString,Object> > httpEntity=newHttpEntity> (param); //发送请求 TempUserresult=restTemplate.postForObject("http://localhost:8080/cs-admin/rest/uploadFile", httpEntity,TempUser.class);
HttpClient
概述
HttpClient 通过连接池创建连接:
管理连接的基本单位是Route(路由),每个路由上都会维护一定数量的HTTP连接
每次调用后必须执行 releaseConnection
路由可以理解为客户端机器到目标机器的一条线路
如果不给 httpclient配置指定的连接管理器,httpclient会自动使用PoolingHttpClientConnectionManager作为连接管理器。
PoolingHttpClientConnectionManager默认的maxConnPerRoute和maxConnTotal分别是是2和20。也就是对于每个服务器最多只会维护2个连接,看起来有点少。所以,在日常使用时我们尽量使用自己配置的连接管理器比较好。
连接池:
连接池技术作为创建和管理连接的缓冲池技术。
连接池管理的对象是长连接
有长连接的优势
**长连接:**是指客户端与服务器端一旦建立连接以后,可以进行多次数据传输而不需重新建立连接,
优势:
省去了每次数据传输连接建立的时间开销
资源的访问控制
**短连接:**每次数据传输都需要客户端和服务器端建立一次连接
使用
使用HttpClient
发送请求、接收响应很简单,一般需要如下几步即可:
创建
HttpClient
对象创建请求方法的实例,并指定请求
URL
。如果需要发送GET
请求,创建HttpGet
对象;如果需要发送POST
请求,创建HttpPost
对象。如果需要发送请求参数,可调用
HttpGet、HttpPost
共同的setParams(HetpParams params)
方法来添加请求参数;对于HttpPost
对象而言,也可调用setEntity(HttpEntity entity)
方法来设置请求参数,参数则必须用NameValuePair[]
数组存储调用
HttpClient
对象的execute(HttpUriRequest request)
发送请求,该方法返回一个HttpResponse
调用
HttpResponse的getAllHeaders()
、getHeaders(String name)
等方法可获取服务器的响应头;调用HttpResponse
的getEntity()
方法可获取HttpEntity
对象,该对象包装了服务器的响应内容。程序可通过该对象获取服务器的响应内容释放连接。无论执行方法是否成功,都必须释放连接
依赖:
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工具类
importcom.alibaba.fastjson.JSON; importlombok.extern.slf4j.Slf4j; importorg.apache.commons.lang3.StringUtils; importorg.apache.http.Consts; importorg.apache.http.HttpResponse; importorg.apache.http.NameValuePair; importorg.apache.http.client.HttpClient; importorg.apache.http.client.config.RequestConfig; importorg.apache.http.client.entity.UrlEncodedFormEntity; importorg.apache.http.client.methods.HttpGet; importorg.apache.http.client.methods.HttpPost; importorg.apache.http.entity.StringEntity; importorg.apache.http.impl.client.HttpClients; importorg.apache.http.impl.conn.PoolingHttpClientConnectionManager; importorg.apache.http.message.BasicNameValuePair; importorg.apache.http.util.EntityUtils; importorg.slf4j.Logger; importjava.net.URI; importjava.nio.charset.StandardCharsets; importjava.util.ArrayList; importjava.util.List; importjava.util.Map; /** *HttpClient工具类 */ @Slf4j publicclassHttpClientUtil{ publicstaticfinalStringAPPLICATION_JSON_VALUE="application/json"; privatestaticfinalLoggerlogger=log; privatestaticfinalIntegerCONN_TIME_OUT=3000; //超时时间豪秒 privatestaticfinalIntegerSOCKET_TIME_OUT=10000; /**每个路由的最大请求数,默认2*/ privatestaticfinalIntegerDEFAULT_MAX_PER_ROUTE=40; /**最大连接数,默认20*/ privatestaticfinalIntegerMAX_TOTAL=400; privatestaticHttpClienthttpClient; static{ //请求配置 RequestConfigrequestConfig=RequestConfig.custom() .setConnectTimeout(CONN_TIME_OUT) .setConnectionRequestTimeout(CONN_TIME_OUT) .setSocketTimeout(SOCKET_TIME_OUT) .build(); //管理http连接池 PoolingHttpClientConnectionManagercm=newPoolingHttpClientConnectionManager(); cm.setDefaultMaxPerRoute(DEFAULT_MAX_PER_ROUTE); cm.setMaxTotal(MAX_TOTAL); httpClient=HttpClients.custom() .setConnectionManager(cm) .setDefaultRequestConfig(requestConfig) .build(); } /** *Get请求 */ publicstaticStringrequestGet(Stringurl,MapString,String> paramsMap)throwsException{ logger.info("GETrequesturl:{ } params:{ } ",url,paramsMap); Longstart=System.currentTimeMillis(); ListNameValuePair> params=initParams(paramsMap); //Get请求 HttpGethttpGet=newHttpGet(url); try{ //设置参数 Stringstr=EntityUtils.toString(newUrlEncodedFormEntity(params,StandardCharsets.UTF_8)); StringuriStr=StringUtils.isEmpty(str)? httpGet.getURI().toString():httpGet.getURI().toString()+"?"+str; httpGet.setURI(newURI(uriStr)); //发送请求 HttpResponseresponse=httpClient.execute(httpGet); logger.info("GETrequesturl:{ } response:{ } time:{ } ", url,response,System.currentTimeMillis()-start); //获取返回数据 returngetSuccessRetFromResp(response,url,JSON.toJSONString(paramsMap)); } finally{ //必须释放连接,不然连接用完后会阻塞 httpGet.releaseConnection(); } } /** *Post请求,Map格式数据 */ publicstaticStringrequestPost(Stringurl,MapString,String> paramsMap)throwsException{ logger.info("POSTrequesturl:{ } params:{ } ",url,paramsMap); Longstart=System.currentTimeMillis(); ListNameValuePair> params=initParams(paramsMap); HttpPosthttpPost=newHttpPost(url); try{ httpPost.setEntity(newUrlEncodedFormEntity(params,Consts.UTF_8)); HttpResponseresponse=httpClient.execute(httpPost); logger.info("POSTrequesturl:{ } response:{ } time:{ } ", url,response,System.currentTimeMillis()-start); StringretStr=getSuccessRetFromResp(response,url,JSON.toJSONString(paramsMap)); returnretStr; } finally{ httpPost.releaseConnection(); } } /** *Post请求,json格式数据 * */ publicstaticStringrequestPostJsonStr(Stringurl,Stringjson)throwsException{ logger.info("POSTrequesturl:{ } params:{ } ",url,json); longstart=System.currentTimeMillis(); HttpPosthttpPost=newHttpPost(url); try{ StringEntityentity=newStringEntity(json,Consts.UTF_8); entity.setContentType(APPLICATION_JSON_VALUE); httpPost.setEntity(entity); HttpResponseresponse=httpClient.execute(httpPost); logger.info("POSTrequesturl:{ } response:{ } time:{ } ", url,response,System.currentTimeMillis()-start); returngetSuccessRetFromResp(response,url,json); } finally{ //资源释放 httpPost.releaseConnection(); } } /** *postObject格式数据 */ publicstaticStringrequestPostJson(Stringurl,Objectobj)throwsException{ Stringparams=JSON.toJSONString(obj); returnrequestPostJsonStr(url,params); } privatestaticStringgetSuccessRetFromResp(HttpResponseresponse,Stringurl,Stringparams)throwsException{ StringretStr=""; //检验状态码,如果成功接收数据 intcode=response.getStatusLine().getStatusCode(); if(code==200){ retStr=EntityUtils.toString(response.getEntity(),Consts.UTF_8); } else{ thrownewRuntimeException(String.format("Httprequesterror:%s,url:%s,params:%s",response,url,params)); } logger.info("HttprequestretStr:{ } .url:{ } ",retStr,url); returnretStr; } privatestaticListNameValuePair> initParams(MapString,String> paramsMap){ ListNameValuePair> params=newArrayListNameValuePair> (); if(paramsMap==null) returnparams; for(Map.EntryString,String> entry:paramsMap.entrySet()){ params.add(newBasicNameValuePair(entry.getKey(),entry.getValue())); } returnparams; } }
到此,相信大家对“Java服务RestTemplate与HttpClient怎么使用”有了更深的了解,不妨来实际操作一番吧!这里是网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!
声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!
若转载请注明出处: Java服务RestTemplate与HttpClient怎么使用
本文地址: https://pptw.com/jishu/301628.html