本文介绍了使用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类型,同时也支持泛型类型的返回值,在上面的示例中,我们使用了大量的泛型,这里就不做过多的解释了。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持小牛知识库。
我是web服务编程新手,我想使用netbeans 6在Grizzly服务器上使用Jersey创建一个restful web服务,然后创建一个客户端javascript,以便通过浏览器使用该web服务。因此,我开始了解更多关于restful web服务的知识,并在网上阅读了大量指南,然后通过阅读jersey用户指南http://jersey . Java . net/nonav/documentat
我试图用Java编写一个客户机来从RESTful web服务中获取数据。我已经看了几个教程和视频,但有一些我不明白。让我从这个开始。我能够使用PEST编写一个clientin PHP来获得成功的响应。这是一个如何发出请求的示例: 我发现有些事情很尴尬,我不太熟悉RESTful客户。出于某种原因,该站点使用POST请求而不是GET请求。凭据作为表单数据和任何查询参数在主体中传递。我查看的教程不是这样
问题内容: 这是RESTful调用的格式: 这是我的代码: 但它返回错误 我想我没有正确添加标题。 有人可以帮我解决吗?请给我建议,如何根据要求添加标题。 谢谢 问题答案: 我认为您正在寻找header(name,value)方法。看到 注意,尽管它返回一个Builder,所以您需要将输出保存在webResource var中。
问题内容: 我有一个node.js Connect服务器,用于检查请求的Cookie。为了在节点中测试它,我需要一种写客户端请求并将cookie附加到它的方法。我知道HTTP请求对此具有’cookie’标头,但是我不确定如何设置和发送它- 我还需要在同一请求中发送POST数据,因此我目前正在使用danwrong的restler模块,但似乎没有让我添加该标头。 关于如何使用硬编码的cookie和PO
在我的代码中,我试图反复构建一个客户端,并向远程endpoint发送一个输入流: 输入流包含消息的xml正文。我注意到在第一次迭代中。。。请求成功第二次迭代响应为400错误请求。。。第三个400错误请求。。。。等等。。。 如果我将输入流更改为字符串...获取真实的xml并用PUT方法发送它。 有什么区别?为什么它可以处理字符串而不能处理输入流?(似乎inputstream在第一次迭代后会发生变化)
客户端的HTTP/HTTPS请求。 进程:主进程 ClientRequest是由EventEmitter来实现Writable Stream new ClientRequest(options) 作用:发起新的HTTP/HTTPS请求 options(Object | String) - options是String时即请求URL。 options 是Object时则按以下属性请求: meth