一:简介
因为项目需要,最近研究了下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
则不会有满足切面条件。
相关推荐
5. 数据绑定:Jersey支持多种数据绑定机制,如JAXB、Gson、Jackson等,将Java对象序列化为JSON或XML。 6. 过滤器和拦截器:可以通过实现ContainerRequestFilter和ContainerResponseFilter接口,对请求和响应进行...
13. **扩展性**:Jersey允许通过SPI(Service Provider Interface)机制添加自定义功能,如提供新的消息处理器或资源解析器。 14. **测试**:Jersey提供测试框架,使得开发者可以轻松地编写单元测试和集成测试,...
5. **扩展性**:通过 SPI(Service Provider Interface)机制,可以扩展 Jersey 的功能。 总结 Jersey 作为 JAX-RS 的实现,为开发者提供了一个强大且灵活的工具,用于构建 RESTful Web 服务。通过深入理解其核心...
- **请求参数处理**:通过`@QueryParam`和`@PathParam`等注解来绑定URL中的查询参数或路径参数到方法参数上。 - **实体处理**:支持多种数据格式(如JSON、XML等),可通过`@Consumes`和`@Produces`注解指定请求和...
4. 参数注解,如@*Param,它们用于方法参数的绑定。 5. 子资源的处理,如何创建和使用子资源。 6. 根资源类的生命周期以及依赖注入规则。 7. @Context注解的使用方法。 8. 程序化资源模型的创建。 在应用程序部署和...
2. **功能特性**:Jersey提供了丰富的功能,包括但不限于HTTP方法支持(GET、POST、PUT、DELETE等)、URI模板、请求和响应过滤器、实体提供者和消费者、安全性和认证机制、支持多种数据格式(XML、JSON等)。...
在JAX-RS中,提供了NameBinding机制,简单理解NameBinding,就是把指定过滤器/拦截器通过自定义的名称注解绑定在某些匹配的资源方法上。Jersey, RESTeasy等框架都有相应的实现。 该代码利用Springboot模拟实现了...
4. **jaxb-impl-2.2.3-1.jar**:Java Architecture for XML Binding (JAXB) 是一个用于XML到Java对象绑定的标准,使得XML数据可以直接转换为Java对象,反之亦然。在Jersey中,JAXB用于序列化和反序列化JSON或XML响应...
Jersey提供了一组工具来简化RESTful服务的创建,包括处理HTTP请求、数据绑定、依赖注入、拦截器、过滤器以及异步支持等。 ### Maven原型创建项目 在Jersey 2.x版本中,可以使用Maven原型来快速生成一个新的RESTful...
1. **路由管理**:Jersey 提供了注解机制,如 `@Path`,可以将特定的 HTTP 路径映射到 Java 类或方法上,方便地定义资源路径。 2. **HTTP 方法处理**:通过 `@GET`, `@POST`, `@PUT`, `@DELETE` 等注解,可以直接在...
3. **过滤器与拦截器**:Jersey2 提供了过滤器(Filter)和拦截器(Interceptor)机制,允许在请求处理之前或之后执行自定义逻辑,如认证、日志记录等。 4. **客户端API**:除了服务器端功能,Jersey2 还提供了...
- **安全与认证**:结合 OAuth2、JWT 或其他机制实现身份验证和授权。 - **服务版本控制**:通过 URL 或请求头实现服务的版本管理。 - **性能优化**:利用缓存、异步处理、分页等技术提升服务性能。 - **集成其他...
7. **模块化和扩展性**:Jersey可以通过插件机制添加额外的功能,如支持OAuth、CORS、JWT等。 通过深入学习和实践jersey-samples-1.4中的示例,开发者可以更好地掌握RESTful Web服务开发,并在实际项目中灵活运用...
2. **丰富的功能集**:提供了广泛的API集合,用于处理HTTP请求、响应以及数据绑定。 3. **社区支持**:拥有活跃的开发者社区,可以提供技术支持和解决方案。 4. **易于集成**:能够轻松地与其他Java框架集成,如...
Java Architecture for XML Binding (JAXB) 是一个Java标准,它提供了在Java对象和XML文档之间进行绑定的能力。这意味着你可以将Java对象转换为XML格式的数据,反之亦然。JAXB允许开发者在不直接处理XML语法的情况下...
1. **Jersey MVC框架的源代码**:包括了路由、控制器、模型绑定、视图渲染等关键组件,这些可以帮助你理解Jersey MVC是如何将请求映射到处理函数,并如何生成响应的。 2. **Jasper引擎的源代码**:展示了JSP编译和...
2. **自动绑定**:Jersey 可以自动将请求参数绑定到资源方法的参数,包括路径参数、查询参数、头参数和请求体。 3. **内容协商**:Jersey 提供了内容协商机制,可以根据客户端的 Accept 头部自动选择合适的响应格式...
2. **Jersey**:Jersey是JAX-RS规范的开源实现,它提供了一整套工具和服务,包括资源类的自动扫描、依赖注入、异常处理、数据绑定等,使得开发者可以更专注于业务逻辑。 3. **过滤器(Filter)**:在JAX-RS中,过滤...
Jersey还支持多种数据绑定机制,如JSON、XML,以及客户端API,方便服务调用。 结合Jetty和Jersey,我们可以实现动态发布REST接口。首先,需要在项目中引入Jetty和Jersey的相关依赖。接着,创建一个Jetty服务器实例...
- `jersey-apache-client`:为Apache HttpClient提供了绑定,允许你利用HttpClient的特性与RESTful服务交互。 - `jersey-guice`:整合了Google Guice依赖注入框架,使得配置和管理Jersey组件更加容易。 综合这些...