详解如何使用Jersey客户端请求Spring Boot(RESTFul)服务
本文介绍了使用Jersey客户端请求SpringBoot(RESTFul)服务,分享给大家,具体如下:
Jersey客户端获取Client对象实例封装:
@Service("jerseyPoolingClient")
publicclassJerseyPoolingClientFactoryBeanimplementsFactoryBean,InitializingBean,DisposableBean{
/**
*Client接口是REST客户端的基本接口,用于和REST服务器通信。Client被定义为一个重量级的对象,其内部管理着
*客户端通信底层的各种对象,比如连接器,解析器等。因此,不推荐在应用中产生大量的的Client实例,这一点在开发中
*需要特别小心,另外该接口要求其实例要有关闭连接的保障,否则会造成内存泄露
*/
privateClientclient;
/**
*一个Client最大的连接数,默认为2000
*/
privateintmaxTotal=2000;
/**
*每路由的默认最大连接数
*/
privateintdefaultMaxPerRoute=1000;
privateClientConfigclientConfig;
publicJerseyPoolingClientFactoryBean(){
}
/**
*带配置的构造函数
*@paramclientConfig
*/
publicJerseyPoolingClientFactoryBean(ClientConfigclientConfig){
this.clientConfig=clientConfig;
}
publicJerseyPoolingClientFactoryBean(intmaxTotal,intdefaultMaxPerRoute){
this.maxTotal=maxTotal;
this.defaultMaxPerRoute=defaultMaxPerRoute;
}
/**
*attention:
*Details:容器销毁时,释放Client资源
*@authorchhliu
*/
@Override
publicvoiddestroy()throwsException{
this.client.close();
}
/**
*
*attention:
*Details:以连接池的形式,来初始化Client对象
*@authorchhliu
*/
@Override
publicvoidafterPropertiesSet()throwsException{
//如果没有使用带ClientConfig的构造函数,则该类的实例为null,则使用默认的配置初始化
if(this.clientConfig==null){
finalClientConfigclientConfig=newClientConfig();
//连接池管理实例,该类是线程安全的,支持多并发操作
PoolingHttpClientConnectionManagerpcm=newPoolingHttpClientConnectionManager();
pcm.setMaxTotal(this.maxTotal);
pcm.setDefaultMaxPerRoute(this.defaultMaxPerRoute);
clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER,pcm);
/*
*在使用Jersey来请求SpringBoot服务时,SpringBoot默认使用Jackson来解析JSON
*而Jersey默认使用MOXy解析JSON,当JerseyClient想SpringBoot服务请求资源时,
*这个差异会导致服务端和客户端对POJO的转换不同,造成反序列化的错误
*因此,此处需要在Client的Config实例中注册Jackson特性
*/
clientConfig.register(JacksonFeature.class);
//使用配置Apache连接器,默认连接器为HttpUrlConnector
clientConfig.connectorProvider(newApacheConnectorProvider());
client=ClientBuilder.newClient(clientConfig);
}else{
//使用构造函数中的ClientConfig来初始化Client对象
client=ClientBuilder.newClient(this.clientConfig);
}
}
/**
*attention:
*Details:返回Client对象,如果该对象为null,则创建一个默认的Client
*@authorchhliu
*/
@Override
publicClientgetObject()throwsException{
if(null==this.client){
returnClientBuilder.newClient();
}
returnthis.client;
}
/**
*attention:
*Details:获取Client对象的类型
*@authorchhliu
*/
@Override
publicClass>getObjectType(){
return(this.client==null?Client.class:this.client.getClass());
}
/**
*attention:
*Details:Client对象是否为单例,默认为单例
*@authorchhliu
*/
@Override
publicbooleanisSingleton(){
returntrue;
}
}
请求SpringBoot服务的封装:
@Component("jerseyClient")
publicclassJerseyClient{
@Resource(name="jerseyPoolingClient")
privateClientclient;
/**
*attention:
*Details:通过id来查询对象
*@authorchhliu
*/
publicResultMsggetResponseById(finalStringid)throwsJsonProcessingException,IOException{
WebTargetwebTarget=client.target("http://localhost:8080").path("/github/get/user/"+id);
Invocation.BuilderinvocationBuilder=webTarget.request(MediaType.APPLICATION_JSON);
GenericType>genericType=newGenericType>(){};
Responseresponse=invocationBuilder.get();
if(response.getStatus()==200){
/*
*当调用readEntity方法时,程序会自动的释放连接
*即使没有调用readEntity方法,直接返回泛型类型的对象,底层仍然会释放连接
*/
returnresponse.readEntity(genericType);
}else{
ResultMsgres=newResultMsg();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
/**
*attention:
*Details:分页查询
*@authorchhliu
*/
publicResultMsg>getGithubWithPager(finalIntegerpageOffset,finalIntegerpageSize,finalStringorderColumn){
WebTargetwebTarget=client.target("http://localhost:8080").path("/github/get/users/page")
.queryParam("pageOffset",pageOffset)
.queryParam("pageSize",pageSize)
.queryParam("orderColumn",orderColumn);
//注意,如果此处的媒体类型为MediaType.APPLICATION_JSON,那么对应的服务中的参数前需加上@RequestBody
Invocation.BuilderinvocationBuilder=webTarget.request(MediaType.APPLICATION_JSON);
GenericType>>genericType=newGenericType>>(){};
Responseresponse=invocationBuilder.get();
if(response.getStatus()==200){
returnresponse.readEntity(genericType);
}else{
ResultMsg>res=newResultMsg>();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
/**
*attention:
*Details:根据用户名来查询
*@authorchhliu
*/
publicResultMsg>getResponseByUsername(finalStringusername)throwsJsonProcessingException,IOException{
WebTargetwebTarget=client.target("http://localhost:8080").path("/github/get/users/"+username);
Invocation.BuilderinvocationBuilder=webTarget.request(MediaType.APPLICATION_JSON);
GenericType>>genericType=newGenericType>>(){};
Responseresponse=invocationBuilder.get();
if(response.getStatus()==200){
returnresponse.readEntity(genericType);
}else{
ResultMsg>res=newResultMsg>();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
/**
*attention:
*Details:根据id来删除一个记录
*@authorchhliu
*/
publicResultMsgdeleteById(finalStringid)throwsJsonProcessingException,IOException{
WebTargettarget=client.target("http://localhost:8080").path("/github/delete/"+id);
GenericType>genericType=newGenericType>(){};
Responseresponse=target.request().delete();
if(response.getStatus()==200){
returnresponse.readEntity(genericType);
}else{
ResultMsgres=newResultMsg();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
/**
*attention:
*Details:更新一条记录
*@authorchhliu
*/
publicResultMsgupdate(finalGitHubEntityentity)throwsJsonProcessingException,IOException{
WebTargettarget=client.target("http://localhost:8080").path("/github/put");
GenericType>genericType=newGenericType>(){};
Responseresponse=target.request().buildPut(Entity.entity(entity,MediaType.APPLICATION_JSON)).invoke();
if(response.getStatus()==200){
returnresponse.readEntity(genericType);
}else{
ResultMsgres=newResultMsg();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
/**
*attention:
*Details:插入一条记录
*@authorchhliu
*/
publicResultMsgsave(finalGitHubEntityentity)throwsJsonProcessingException,IOException{
WebTargettarget=client.target("http://localhost:8080").path("/github/post");
GenericType>genericType=newGenericType>(){};
Responseresponse=target.request().buildPost(Entity.entity(entity,MediaType.APPLICATION_JSON)).invoke();
if(response.getStatus()==200){
returnresponse.readEntity(genericType);
}else{
ResultMsgres=newResultMsg();
res.setErrorCode(String.valueOf(response.getStatus()));
res.setErrorMsg(response.getStatusInfo().toString());
res.setOK(false);
returnres;
}
}
}
Jersey客户端接口详解
1Client接口
创建一个Client实例是通过ClientBuilder构造的,通常使用一个ClientConfig实例作为参数,如果我们使用Clientclient=ClientBuilder.newClient()的方式来创建Client实例的时候,每次都会创建一个Client实例,但该实例是一个重量级的对象,所以,建议使用HTTP连接池的方式来管理连接,而不是每次请求都去创建一个Client对象,具体的连接池管理方式见上面的代码示例。
2WebTarget接口
WebTarget接口是为REST客户端实现资源定位的接口,通过WebTarget接口,我们可以定义请求资源的具体地址,查询参数和媒体类型信息等。我们可以通过方法链的方式完成对一个WebTarget实例的配置,但是需要注意的是,虽然WebTarget的使用方式和StringBuffer的方法链方式非常类似,但实质是不一样的,WebTarget的方法链必须设置方法的返回值,作为后续流程的句柄,这个是什么意思了,看下面的几个示例:
示例1:StringBuffer的方法链示例
StringBuffersb=newStringBuffer("lch");
sb.append("hello");
sb.append("world");
sb.append("hello").append("world");//这种方式和上面的两行代码实现的效果是一样的。
示例2:WebTarget的方法链示例
//使用一行代码的方法链来实例化WebTarget
WebTargetwebTarget=client.target("http://localhost:8080");
webTarget.path("/github/get/users/page")
.queryParam("pageOffset",pageOffset)
.queryParam("pageSize",pageSize)
.queryParam("orderColumn",orderColumn);
//下面是分开使用方法链来实例化WebTarget
webTarget.path("/github/get/users/page");
webTarget.queryParam("pageOffset",pageOffset);
webTarget.queryParam("pageSize",pageSize);
//上面两种实例化的方式最后产生的结果大相径庭,上面的实例化方式是OK的,没有问题,下面的实例化方式却有问题,下面的实例化方式中,每一行都会生成一个
//新的WebTarget对象,原来的WebTarget并没有起任何作用,毕竟每一行的实例都不一样,如果我们想要分多行实例化了,就必须为每个方法的返回提供一个句柄,方式如下:
WebTargettarget=client.target("http://localhost:8080");
WebTargetpathTarget=target.path("/github/get/users/page");
WebTargetparamTarget=pathTarget.queryParam("pageOffset",pageOffset);
//最后使用的时候,用最后一个WebTarget实例对象即可
3Invocation接口
Invocation接口是在完成资源定位配置后,向REST服务端发起请求的接口,请求包括同步和异步两种方式,由Invocation接口内部的Builder接口定义,Builder接口继承了同步接口SyncInvoker,异步调用的使用示例如下:
Future>>response=invocationBuilder.async().get(genericType); if(response.isDone()){ returnresponse.get(); }
Invocation.Builder接口实例分别执行了GET和POST请求来提交查询和创建,默认情况下,HTTP方法调用的返回类型是Response类型,同时也支持泛型类型的返回值,在上面的示例中,我们使用了大量的泛型,这里就不做过多的解释了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。