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
