详解如何使用Jersey客户端请求Spring Boot(RESTFul)服务
本文介绍了使用jersey客户端请求spring boot(restful)服务,分享给大家,具体如下:
jersey客户端获取client对象实例封装:
@service("jerseypoolingclient") public class jerseypoolingclientfactorybean implements factorybean<client>, initializingbean, disposablebean{ /** * client接口是rest客户端的基本接口,用于和rest服务器通信。client被定义为一个重量级的对象,其内部管理着 * 客户端通信底层的各种对象,比如连接器,解析器等。因此,不推荐在应用中产生大量的的client实例,这一点在开发中 * 需要特别小心,另外该接口要求其实例要有关闭连接的保障,否则会造成内存泄露 */ private client client; /** * 一个client最大的连接数,默认为2000 */ private int maxtotal = 2000; /** * 每路由的默认最大连接数 */ private int defaultmaxperroute = 1000; private clientconfig clientconfig; public jerseypoolingclientfactorybean() { } /** * 带配置的构造函数 * @param clientconfig */ public jerseypoolingclientfactorybean(clientconfig clientconfig) { this.clientconfig = clientconfig; } public jerseypoolingclientfactorybean(int maxtotal, int defaultmaxperroute) { this.maxtotal = maxtotal; this.defaultmaxperroute = defaultmaxperroute; } /** * attention: * details:容器销毁时,释放client资源 * @author chhliu */ @override public void destroy() throws exception { this.client.close(); } /** * * attention: * details:以连接池的形式,来初始化client对象 * @author chhliu */ @override public void afterpropertiesset() throws exception { // 如果没有使用带clientconfig的构造函数,则该类的实例为null,则使用默认的配置初始化 if(this.clientconfig == null){ final clientconfig clientconfig = new clientconfig(); // 连接池管理实例,该类是线程安全的,支持多并发操作 poolinghttpclientconnectionmanager pcm = new poolinghttpclientconnectionmanager(); pcm.setmaxtotal(this.maxtotal); pcm.setdefaultmaxperroute(this.defaultmaxperroute); clientconfig.property(apacheclientproperties.connection_manager, pcm); /* * 在使用jersey来请求spring boot服务时,spring boot默认使用jackson来解析json * 而jersey默认使用moxy解析json,当jersey client想spring boot服务请求资源时, * 这个差异会导致服务端和客户端对pojo的转换不同,造成反序列化的错误 * 因此,此处需要在client的config实例中注册jackson特性 */ clientconfig.register(jacksonfeature.class); // 使用配置apache连接器,默认连接器为httpurlconnector clientconfig.connectorprovider(new apacheconnectorprovider()); client = clientbuilder.newclient(clientconfig); }else{ // 使用构造函数中的clientconfig来初始化client对象 client = clientbuilder.newclient(this.clientconfig); } } /** * attention: * details:返回client对象,如果该对象为null,则创建一个默认的client * @author chhliu */ @override public client getobject() throws exception { if(null == this.client){ return clientbuilder.newclient(); } return this.client; } /** * attention: * details:获取client对象的类型 * @author chhliu */ @override public class<?> getobjecttype() { return (this.client == null ? client.class : this.client.getclass()); } /** * attention: * details:client对象是否为单例,默认为单例 * @author chhliu */ @override public boolean issingleton() { return true; } }
请求spring boot服务的封装:
@component("jerseyclient") public class jerseyclient { @resource(name="jerseypoolingclient") private client client; /** * attention: * details:通过id来查询对象 * @author chhliu */ public resultmsg<githubentity> getresponsebyid(final string id) throws jsonprocessingexception, ioexception{ webtarget webtarget = client.target("http://localhost:8080").path("/github/get/user/"+id); invocation.builder invocationbuilder = webtarget.request(mediatype.application_json); generictype<resultmsg<githubentity>> generictype = new generictype<resultmsg<githubentity>>(){}; response response = invocationbuilder.get(); if(response.getstatus() == 200){ /* * 当调用readentity方法时,程序会自动的释放连接 * 即使没有调用readentity方法,直接返回泛型类型的对象,底层仍然会释放连接 */ return response.readentity(generictype); }else{ resultmsg<githubentity> res = new resultmsg<githubentity>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } /** * attention: * details:分页查询 * @author chhliu */ public resultmsg<pager<githubentity>> getgithubwithpager(final integer pageoffset, final integer pagesize, final string ordercolumn){ webtarget webtarget = client.target("http://localhost:8080").path("/github/get/users/page") .queryparam("pageoffset", pageoffset) .queryparam("pagesize", pagesize) .queryparam("ordercolumn", ordercolumn); // 注意,如果此处的媒体类型为mediatype.application_json,那么对应的服务中的参数前需加上@requestbody invocation.builder invocationbuilder = webtarget.request(mediatype.application_json); generictype<resultmsg<pager<githubentity>>> generictype = new generictype<resultmsg<pager<githubentity>>>(){}; response response = invocationbuilder.get(); if(response.getstatus() == 200){ return response.readentity(generictype); }else{ resultmsg<pager<githubentity>> res = new resultmsg<pager<githubentity>>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } /** * attention: * details:根据用户名来查询 * @author chhliu */ public resultmsg<list<githubentity>> getresponsebyusername(final string username) throws jsonprocessingexception, ioexception{ webtarget webtarget = client.target("http://localhost:8080").path("/github/get/users/"+username); invocation.builder invocationbuilder = webtarget.request(mediatype.application_json); generictype<resultmsg<list<githubentity>>> generictype = new generictype<resultmsg<list<githubentity>>>(){}; response response = invocationbuilder.get(); if(response.getstatus() == 200){ return response.readentity(generictype); }else{ resultmsg<list<githubentity>> res = new resultmsg<list<githubentity>>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } /** * attention: * details:根据id来删除一个记录 * @author chhliu */ public resultmsg<githubentity> deletebyid(final string id) throws jsonprocessingexception, ioexception{ webtarget target = client.target("http://localhost:8080").path("/github/delete/"+id); generictype<resultmsg<githubentity>> generictype = new generictype<resultmsg<githubentity>>(){}; response response = target.request().delete(); if(response.getstatus() == 200){ return response.readentity(generictype); }else{ resultmsg<githubentity> res = new resultmsg<githubentity>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } /** * attention: * details:更新一条记录 * @author chhliu */ public resultmsg<githubentity> update(final githubentity entity) throws jsonprocessingexception, ioexception{ webtarget target = client.target("http://localhost:8080").path("/github/put"); generictype<resultmsg<githubentity>> generictype = new generictype<resultmsg<githubentity>>(){}; response response = target.request().buildput(entity.entity(entity, mediatype.application_json)).invoke(); if(response.getstatus() == 200){ return response.readentity(generictype); }else{ resultmsg<githubentity> res = new resultmsg<githubentity>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } /** * attention: * details:插入一条记录 * @author chhliu */ public resultmsg<githubentity> save(final githubentity entity) throws jsonprocessingexception, ioexception{ webtarget target = client.target("http://localhost:8080").path("/github/post"); generictype<resultmsg<githubentity>> generictype = new generictype<resultmsg<githubentity>>(){}; response response = target.request().buildpost(entity.entity(entity, mediatype.application_json)).invoke(); if(response.getstatus() == 200){ return response.readentity(generictype); }else{ resultmsg<githubentity> res = new resultmsg<githubentity>(); res.seterrorcode(string.valueof(response.getstatus())); res.seterrormsg(response.getstatusinfo().tostring()); res.setok(false); return res; } } }
jersey客户端接口详解
1 client接口
创建一个client实例是通过clientbuilder构造的,通常使用一个clientconfig实例作为参数,如果我们使用client client = clientbuilder.newclient()的方式来创建client实例的时候,每次都会创建一个client实例,但该实例是一个重量级的对象,所以,建议使用http连接池的方式来管理连接,而不是每次请求都去创建一个client对象,具体的连接池管理方式见上面的代码示例。
2 webtarget接口
webtarget接口是为rest客户端实现资源定位的接口,通过webtarget接口,我们可以定义请求资源的具体地址,查询参数和媒体类型信息等。我们可以通过方法链的方式完成对一个webtarget实例的配置,但是需要注意的是,虽然webtarget的使用方式和stringbuffer的方法链方式非常类似,但实质是不一样的,webtarget的方法链必须设置方法的返回值,作为后续流程的句柄,这个是什么意思了,看下面的几个示例:
示例1:stringbuffer的方法链示例
stringbuffer sb = new stringbuffer("lch"); sb.append("hello"); sb.append("world"); sb.append("hello").append("world"); // 这种方式和上面的两行代码实现的效果是一样的。
示例2:webtarget的方法链示例
// 使用一行代码的方法链来实例化webtarget webtarget webtarget = 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并没有起任何作用,毕竟每一行的实例都不一样,如果我们想要分多行实例化了,就必须为每个方法的返回提供一个句柄,方式如下: webtarget target = client.target("http://localhost:8080"); webtarget pathtarget = target.path("/github/get/users/page"); webtarget paramtarget = pathtarget.queryparam("pageoffset", pageoffset); // 最后使用的时候,用最后一个webtarget实例对象即可
3 invocation接口
invocation接口是在完成资源定位配置后,向rest服务端发起请求的接口,请求包括同步和异步两种方式,由invocation接口内部的builder接口定义,builder接口继承了同步接口syncinvoker,异步调用的使用示例如下:
future<resultmsg<list<githubentity>>> response = invocationbuilder.async().get(generictype); if(response.isdone()){ return response.get(); }
invocation.builder接口实例分别执行了get和post请求来提交查询和创建,默认情况下,http方法调用的返回类型是response类型,同时也支持泛型类型的返回值,在上面的示例中,我们使用了大量的泛型,这里就不做过多的解释了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。