最近对自己做过的项目进行一个梳理,其中主要用到了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/savehttp://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
一个知识点,你自己看懂了,那是一个层次;你会用,是另外一个层次;你写出来,你写出来让别人懂,那又是更高的一个层次;你用最通俗的言语,把知识点讲出来,让别人一下子明白,又是更高的一个层次。
如果您觉的本篇文章有用,
注:转载需注明出处及作者名,严禁恶意转载,尊重原作者的劳动成果。