一:简介
因为项目需要,最近研究了下restful风格的编程方式,这里也Jersey为例。Jersey是一个restful框架,其提供了面向切面的Providers功能,一般情况下我们可以手动注册到Application中,但是它支持更加灵活的方式,这就是jersey提供的绑定机制。
二:客户端封装
Jersey Client的每次创建连接都必须耗资源,我们可以用连接池模式进行封装。
package com.jersey.client; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import org.apache.http.impl.conn.PoolingClientConnectionManager; import org.glassfish.jersey.apache.connector.ApacheClientProperties; import org.glassfish.jersey.apache.connector.ApacheConnectorProvider; import org.glassfish.jersey.client.ClientConfig; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.stereotype.Service; /** * 对Jersey客户端得封装 1、使用spring提供的几个bean实现 InitializingBean , * FactoryBean 工厂bean,其返回的对象不是指定类的一个实例,其返回的是该FactoryBean的getObject方法所返回的对象 * DisposableBean * bean的销毁 * * @author tanjie * */ @SuppressWarnings("deprecation") @Service("jerseyClient") public final class JerseyClient implements FactoryBean<Client>, InitializingBean, DisposableBean { /** * 返回Client实例 */ private Client client; private ClientConfig clientConfig; /** * httpclient连接的最大连接数 */ private int maxTotal = 1000; /** * httpclient每个主机地址的并发数 */ private int defaultMaxPerRoute = 100; /** * 无参构造函数,spring管理的对象必须提供一个 */ public JerseyClient(){ } public JerseyClient(int maxTotal, int defaultMaxPerRoute) { this.maxTotal = maxTotal; this.defaultMaxPerRoute = defaultMaxPerRoute; } /** * spring会在初始化bean之后执行该方法,优先于init-method执行,但是init-method不依赖spring,只是其采用 * 反射实现,效率上没有实现InitalizingBean高 */ @Override public void afterPropertiesSet() throws Exception { if (null == clientConfig) { clientConfig = new ClientConfig(); final PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager(); connectionManager.setMaxTotal(maxTotal); connectionManager.setDefaultMaxPerRoute(defaultMaxPerRoute); clientConfig.property(ApacheClientProperties.CONNECTION_MANAGER, connectionManager); clientConfig.connectorProvider(new ApacheConnectorProvider()); client = ClientBuilder.newClient(clientConfig); }else{ // 默认创建一个 client = ClientBuilder.newClient(); } } /** * 实例销毁 */ @Override public void destroy() throws Exception { if (null != client) { client.close(); } } @Override public Client getObject() throws Exception { return this.client; } @Override public Class<?> getObjectType() { return this.client.getClass(); } @Override public boolean isSingleton() { return true; } }
2.1 按名称绑定
使用@NameBinding
package com.tanjie.jersey.绑定机制; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.ws.rs.NameBinding; /** * 通过名称绑定 */ @NameBinding @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(value=RetentionPolicy.RUNTIME) public @interface Banding { }
绑定@Provider
package com.jersey.绑定机制; import java.io.IOException; import javax.annotation.Priority; import javax.ws.rs.Priorities; import javax.ws.rs.container.ContainerRequestContext; import javax.ws.rs.container.ContainerRequestFilter; import javax.ws.rs.container.ContainerResponseContext; import javax.ws.rs.container.ContainerResponseFilter; import javax.ws.rs.ext.Provider; @Banding @Priority(Priorities.USER) @Provider public class NameBindingFilter implements ContainerRequestFilter, ContainerResponseFilter { /** * @param requestContext服务器请求过滤器 * 可以分为预处理:即当服务器接收到请求后先执行处理 * 后处理:当服务器接收到请求并处理后在进行处理(默认情况系) * 二者可同时执行 */ @Override public void filter(ContainerRequestContext requestContext) throws IOException { System.out.println("AirNameBindingFilter请求前" + requestContext.getMethod()); } /** * 服务器响应请求后的过滤器 * @param requestContext 容器请求上下文 * @param responseContext 容器响应上下文 */ @Override public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException { System.out.println("AirNameBindingFilter请求后" + requestContext.getMethod() + ",url:" + responseContext.getStatus()); } }
提供rest接口
package com.jersey.resources; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import com.jersey.vo.User; import com.jersey.绑定机制.Banding; @Banding @Path("/helloword") public class RestfulHello { /** * @GET 方法是幂等的,因为读取同一个资源,总是得到相同的数据,GET方法也是线程安全的 * 因为读取资源不会对其状态做改到 * 1、在接口中定义了资源请求的类型后,在实现类上不用再定义 * @return */ @GET @Produces(MediaType.TEXT_PLAIN) public String sayHello() { return "restful hello word"; } @GET @Path("/{param}") @Produces("text/plain;charset=UTF-8") public String sayHello2UserByText(@PathParam("param") String username) { return "Hello " + username; } @GET @Path("/get") @Produces(MediaType.APPLICATION_JSON) public User HH(@QueryParam("username") String username) { User user = new User(); user.setId(1); user.setName(username); return user; } }
单元测试:
package com.jersey_restful; import javax.annotation.Resource; import javax.ws.rs.client.Client; import javax.ws.rs.client.Invocation.Builder; import javax.ws.rs.client.WebTarget; import javax.ws.rs.core.GenericType; import javax.ws.rs.core.Response; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:applicationContext.xml" }) public class NameBindTest{ @Resource(name = "jerseyClient") private transient Client jerseyClient; @Test public void test() { WebTarget target = jerseyClient.target( "http://localhost:8080/jersey_restful/restful/helloword") Builder builder = target.request(); Response response = builder.get(); GenericType<String> genericType = new GenericType<String>(String.class); if (200 == response.getStatus()) { System.out.println("请求OK"); System.out.println("返回值:" + response.readEntity(genericType)); } } }
运行效果:
AirNameBindingFilter请求前GET 请求OK 返回值:restful hello world AirNameBindingFilter请求后GET,url:200
2.2 动态绑定
Jersey支持动态绑定,可以更个性化的加载,在运行期只要匹配的动态绑定扩展的方法,面向切面的Provider就会被加载
定义动态绑定:
package com.tanjie.jersey.绑定机制; import javax.ws.rs.GET; import javax.ws.rs.container.DynamicFeature; import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.FeatureContext; import javax.ws.rs.ext.Provider; import com.tanjie.jersey.resources.RestfulHello; @Provider public final class 动态绑定 implements DynamicFeature{ @Override public void configure(ResourceInfo resourceInfo, FeatureContext context) { boolean 是否是这个类 = RestfulHello.class.isAssignableFrom(resourceInfo.getResourceClass()); boolean 是否是这个方法名 = resourceInfo.getResourceMethod().getName().contains("sayHello"); boolean 是否是这个请求类型 = resourceInfo.getResourceMethod().isAnnotationPresent(GET.class); if (是否是这个类 && 是否是这个方法名 && 是否是这个请求类型) { context.register(AirDynamicBindingFilter.class); } } }
切面
public class AirDynamicBindingFilter implements ContainerRequestFilter { @Override public void filter(final ContainerRequestContext requestContext) throws IOException { System.out.println("动态绑定业务处理"); } }
浏览器执行:
http://localhost:8080/jersey_restful/restful/helloword
运行效果:
动态绑定业务处理
如果继续执行:
http://localhost:8080/jersey_restful/restful/helloword/get?username=zs
则不会有满足切面条件。
相关推荐
Official Jersey 2.25.1 User Guide. This is user guide for Jersey 2.25.1. We are trying to keep it up to date as we add new features. When reading the user guide, please consult also our Jersey API ...
Jersey所需Jar包。jersey-client、jersey-core、jersey-grizzly2、jersey-server
如果flink提交jar到yarn上运行报如下错误:java.lang.NoClassDefFoundError: com/sun/jersey/core/util/FeaturesAndProperties,在flink的lib包里面添加这两个jar包
jersey
Jersey官网下载jar,导入功能即可使用,Jersey官网下载jar,导入功能即可使用
jersey-1.19JAR包全 Jersey所需要的所有的Jar包,包括对Jason的支持等等,总够有26个
下载后里面的target目录下有war包,可以直接放在tomcat下运行。 项目使用Intellij Idea 14 创建。 http://localhost:8080/rest/helloWorld/a 单独的jersey...http://localhost:8080/rest/demo/hello 集成spring的jersey
Jersey+Spring:解决Jersey单实例问题
赠送jar包:jersey-container-servlet-core-2.22.2.jar; 赠送原API文档:jersey-container-servlet-core-2.22.2-javadoc.jar; 赠送源代码:jersey-container-servlet-core-2.22.2-sources.jar; 赠送Maven依赖信息...
赠送jar包:jersey-media-jaxb-2.22.2.jar; 赠送原API文档:jersey-media-jaxb-2.22.2-javadoc.jar; 赠送源代码:jersey-media-jaxb-2.22.2-sources.jar; 赠送Maven依赖信息文件:jersey-media-jaxb-2.22.2.pom;...
jersey1.18相关的几乎所有jar包,还有部分官方文档
jersey RESTful service 源代码 jersey RESTful service 源代码
org.glassfish.jersey.media:jersey-media-multipart:2.24.1 Jersey 上传文件以及下载文件所需的依赖库,maven下载比较慢,我手动下载下来了。放到你的libs目录
jersey最新jar包
Jersey 2.7的官方英文文档 CHM格式
jersey框架简单叙述以及 Jersey对HTTPS的支持, Jersey对Json的支持
赠送jar包:jersey-client-1.19.jar; 赠送原API文档:jersey-client-1.19-javadoc.jar; 赠送源代码:jersey-client-1.19-sources.jar; 赠送Maven依赖信息文件:jersey-client-1.19.pom; 包含翻译后的API文档:...
赠送jar包:jersey-core-1.19.jar; 赠送原API文档:jersey-core-1.19-javadoc.jar; 赠送源代码:jersey-core-1.19-sources.jar; 赠送Maven依赖信息文件:jersey-core-1.19.pom; 包含翻译后的API文档:jersey-...
赠送jar包:jersey-common-2.22.2.jar; 赠送原API文档:jersey-common-2.22.2-javadoc.jar; 赠送源代码:jersey-common-2.22.2-sources.jar; 赠送Maven依赖信息文件:jersey-common-2.22.2.pom; 包含翻译后的API...
Jersey所需要的所有的Jar包,包括对Jason的支持等等,总够有26个。