Maven学习笔记-05-Jersey 与 Spring 的集成
最近对自己做过的项目进行一个梳理,其中主要用到了RESTful的Web服务框架 Jersey ,并与Spring进行了集成。在此对Jersey框架进行一个总结。
一 RESTful的web框架 Jersey
Jersey RESTful 框架是开源的RESTful框架, 实现了 JAX-RS 规范。它扩展了JAX-RS 参考实现, 提供了更多的特性和工具, 可以进一步地简化 RESTful service 和 client 开发。
REST 中最重要的概念是资源(resources),使用全球 ID(通常使用 URI)标识。客户端应用程序使用 HTTP 方法(GET/ POST/ PUT/ DELETE)操作资源或资源集。RESTful Web 服务是使用 HTTP 和 REST 原理实现的 Web 服务. 比如 RESTful Web 服务示例如下图所示:
二 Jersey与Spring进行集成
项目中使用到的技术和环境:
Jersey 1.8 Spring 3.0.5.RELEASE Maven 3 JDK 1.7 Eclipse 4.5.1
1. 项目依赖
在项目中 Jersey , Spring 的依赖文件放在了 Maven工程的 pom.xml文件
<dependencies> <!-- Jersey --> <dependency> <groupId>com.sun.jersey</groupId> <artifactId>jersey-server</artifactId> <version>1.8</version> </dependency> <!-- Spring 3 dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>3.0.5.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>3.0.5.RELEASE</version> </dependency> <!-- Jersey + Spring --> <dependency> <groupId>com.sun.jersey.contribs</groupId> <artifactId>jersey-spring</artifactId> <version>1.8</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> </exclusions> </dependency>
<!-- Json --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.1.23</version> </dependency> </dependencies> <repositories> <repository> <id>maven2-repository.java.net</id> <name>Java.net Repository for Maven</name> <url>http://download.java.net/maven/2/</url> </repository> <repository> <id>oschina Releases</id> <name>oschina Releases</name> <url>http://maven.oschina.net/content/groups/public</url> </repository> <repository> <id>nexus-osc</id> <name>Nexus osc</name> <url>http://maven.oschina.net/content/groups/public/</url> </repository> <repository> <id>nexus-osc-thirdparty</id> <name>thirdparty</name> <url>http://maven.oschina.net/content/repositories/thirdparty/</url> </repository> <!-- jesery插件仓库 --> <repository> <id>snapshot-repository.java.net</id> <name>Java.net Snapshot Repository for Maven</name> <url>https://maven.java.net/content/repositories/snapshots/</url> <layout>default</layout> </repository> </repositories>
2. Spring Bean
生成一个简单的 ”transactionBo“ Bean,然后把它注册于 Spring Container容器中。稍后把它注入到 Jersey 服务中。
TransactionBo.java
package com.xinping.transaction; import com.alibaba.fastjson.JSONObject; public interface TransactionBo { String save(); public JSONObject findInfo(); }
TransactionBoImpl.java
package com.xinping.transaction.impl; import com.alibaba.fastjson.JSONObject; import com.xinping.transaction.TransactionBo; public class TransactionBoImpl implements TransactionBo { public String save() { return "Jersey集成Spring 测试例子"; } public JSONObject findInfo(){ JSONObject json = new JSONObject(); json.put("name", "xinping"); json.put("age", "35"); return json; } }
在 src/main/resources下新建 applicationContext.xml 文件,负责注册bean 和启动组件自动扫描功能。
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <context:component-scan base-package="com.xinping.rest" /> <bean id="transactionBo" class="com.xinping.transaction.impl.TransactionBoImpl" /> </beans>
3. Jersey
在 RESTFUL方法中,可以使用Spring 框架的自动注入功能,把 transactionBo 注入到 Jersey 服务中。
package com.xinping.rest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.Response;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSONObject;
import com.xinping.transaction.TransactionBo; @Component @Path("/payment") public class PaymentService { @Autowired TransactionBo transactionBo;
@GET
@Path("/sayHello")
@Produces("application/json")
public Response sayHello(@DefaultValue("") @QueryParam("name") String name) {
JSONObject userObj = new JSONObject();
userObj.put("name", name);
userObj.put("age", new Integer(20));
userObj.put("time", new Date());
userObj.put("address", null);
System.out.println(userObj.toJSONString());
return Response.status(200).entity(userObj.toJSONString()).build();
}
@GET @Path("/save")
@Produces("application/json") public Response savePayment() { String result = transactionBo.save(); return Response.status(200).entity(result).build(); } @GET @Path("/findInfo") public Response findInfo() { JSONObject result = transactionBo.findInfo(); Map<String,String> map = new HashMap<String,String> (); map.put("name", "wangwu"); map.put("addresss", "beijing"); return Response.ok(result.toJSONString()).build(); } }
4. 集成 Jersey与 Spring
核心的注入代码在 web.xml中。
1. 注册Spring “ContextLoaderListener” 监听器。
2. 配置Jersey servlet 为 “com.sun.jersey.spi.spring.container.servlet.SpringServlet“。
web.xml
<web-app id="WebApp_ID" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Restful Web Application</display-name> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:applicationContext.xml</param-value> </context-param> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener> <servlet> <servlet-name>jersey-serlvet</servlet-name> <servlet-class> com.sun.jersey.spi.spring.container.servlet.SpringServlet </servlet-class> <init-param> <param-name> com.sun.jersey.config.property.packages </param-name> <param-value>com.xinping.rest</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jersey-serlvet</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> </web-app>
5. 测试访问
http://localhost:8080/oneWeb1/rest/payment/save
http://localhost:8080/oneWeb1/rest/payment/findInfo
http://localhost:8080/oneWeb1/rest/payment/sayHello?name=lisi
6 异步调用服务
http://docs.huihoo.com/jersey/2.13/async.html
TestCaseModel.java
package cn.com.ctsi.csdp.user.api.rest.biscuit; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.TimeUnit; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.container.AsyncResponse; import javax.ws.rs.container.Suspended; import javax.ws.rs.container.TimeoutHandler; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import javax.ws.rs.core.UriInfo; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import com.alibaba.fastjson.JSONObject; import com.wordnik.swagger.annotations.Api; import cn.com.ctsi.csdp.base.rest.WebService; import cn.com.ctsi.csdp.base.rest.result.ObjectRESTResult; @Path("/testcase") @Api(value = "/testcase", description = "rest api for api gateway",position=0) @Component("biscuitTestcase") public class TestCaseModel extends WebService { Logger logger = Logger.getLogger(TestCaseModel.class); public TestCaseModel(@Context UriInfo uriInfo, @Context HttpHeaders headers, @Context SecurityContext securityContext) { super(uriInfo, headers, securityContext); } public TestCaseModel() { } @Context private HttpServletRequest request; /** * 显示时间 * http://127.0.0.1:8083/auth/api/v2/testcase/showTime * */ @GET @Path("/showTime") @Produces(MediaType.APPLICATION_JSON) public Response showTime() { logger.info("********* TestCaseModel showTime **************"); Map<String, Object> result = new HashMap<String, Object>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); result.put("time", dateFormat.format(new Date())); result.put("desc", "resource showTime"); return Response.ok(result).build(); } /** * 显示时间 * http://127.0.0.1:8083/auth/api/v2/testcase/sayHello?name=wangwu&age=20 * */ @GET @Path("/sayHello") @Produces(MediaType.APPLICATION_JSON) public Response sayHello(@QueryParam("name") String name,@QueryParam("age") String age) { logger.info("********* TestCaseModel sayHello **************"); logger.info("name=" + name); logger.info("age=" + age); Map<String, Object> result = new HashMap<String, Object>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); result.put("time", dateFormat.format(new Date())); result.put("name", name); result.put("age", age); return Response.ok(result).build(); } /** * http://127.0.0.1:8083/auth/api/v2/testcase/findProjectsById/1112222 * */ @GET @Path("/findProjectsById/{project_id}") @Produces(MediaType.APPLICATION_JSON) public Response findProjectsById(@PathParam("project_id") String projectId,@QueryParam("name") String name ) throws Exception{ logger.info("********* TestCaseModel findProjectsById **************"); logger.info("projectId" + projectId); logger.info("name" + name); Map<String, Object> result = new HashMap<String, Object>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); result.put("time", dateFormat.format(new Date())); result.put("projectId", projectId); result.put("name", name); return Response.ok(result).build(); } /** * http://127.0.0.1:8083/auth/api/v2/testcase/v2.0/createV2Project { "name": "wangwu", "age": 23 } * */ @POST @Path("/v2.0/createV2Project") @Produces(MediaType.APPLICATION_JSON) public Response createV2Project(String json) throws Exception{ logger.info("********* TestCaseModel createV2Project **************"); logger.info("json" + json); Map<String, Object> result = new HashMap<String, Object>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); result.put("time", dateFormat.format(new Date())); JSONObject body = JSONObject.parseObject(json); String name = (String) body.get("name"); Integer age = (Integer) body.get("age"); result.put("name", name); result.put("age", age); return Response.ok(result).build(); } /** * http://127.0.0.1:8083/auth/api/v2/testcase/showDatas * */ @GET @Path("/showDatas") @Produces(MediaType.APPLICATION_JSON) public Response showDatas( ) throws Exception{ logger.info("********* TestCaseModel showDatas **************"); Map<String, Object> result = new HashMap<String, Object>(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); result.put("time", dateFormat.format(new Date())); List list = new ArrayList(); Map record1 = new HashMap(); record1.put("uuid", "8f6cae8a24ab4d0887dd5907430075e7"); record1.put("created", "1496800026000"); record1.put("username", "test03-SD"); record1.put("contractNumber", "131"); Map record2 = new HashMap(); record2.put("name", "8bbf9fded675472aa852cf1940bc8234"); record2.put("created", "1489479452000"); record2.put("username", "test02"); record2.put("contractNumber", "132"); Map record3 = new HashMap(); record3.put("name", "156b396f9b354467b5d1d1a1014b2d10"); record3.put("created", "1487576620000"); record3.put("username", "test01"); record2.put("contractNumber", "133"); list.add(record1); list.add(record2); list.add(record3); result.put("resources", list); result.put("total", 3); result.put("pageNum", 1); return Response.ok(result).build(); } /** http://127.0.0.1:8083/auth/api/v2/testcase/asyncGetWithTimeout * */ @GET @Path("/asyncGetWithTimeout") @Produces(MediaType.APPLICATION_JSON) public void asyncGetWithTimeout(@Suspended final AsyncResponse asyncResponse) { logger.info("******** asyncGetWithTimeout **********"); asyncResponse.setTimeoutHandler(new TimeoutHandler() { @Override public void handleTimeout(AsyncResponse asyncResponse) { /* asyncResponse.resume(Response.status(Response.Status.SERVICE_UNAVAILABLE) .entity("Operation time out.").build());*/ Response response = Response.status(Response.Status.SERVICE_UNAVAILABLE.getStatusCode()).entity(new ObjectRESTResult(Response.Status.SERVICE_UNAVAILABLE.getStatusCode(),"Your Operation time out,please check it。",null)).build(); asyncResponse.resume(response); } }); asyncResponse.setTimeout(10, TimeUnit.SECONDS); new Thread(new Runnable() { @Override public void run() { Map msg = new HashMap(); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒"); msg.put("begintime", dateFormat.format(new Date())); String result = veryExpensiveOperation(); msg.put("msg",result); msg.put("endtime", dateFormat.format(new Date())); msg.put("statusCode",200); asyncResponse.resume(msg); } private String veryExpensiveOperation() { logger.info("* begin veryExpensiveOperation "); try { Thread.sleep( 3 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } logger.info("* end veryExpensiveOperation "); return "hello csdp, bbb"; } }).start(); } }
二 生产环境中的restful
添加资源请求
修改资源请求
删除资源请求
查看资源请求
参考资料:
http://www.lifeba.org/arch/restlet_develop_jax-rs_service_1.html
如果您觉的本篇文章有用,可以赞助作者一些小额的比特币,用来买咖啡,谢谢。 收款地址:3NTPbsJKRKhe1RE1g2rZdr2dFTDgkBUgUa
注:转载需注明出处及作者名,严禁恶意转载,尊重原作者的劳动成果。