Jersey是JAX-RS(JSR311)开源参考实现,用于构建RESTful Web service。它包含三个部分:
核心服务器(Core Server) 通过提供JSR 311中标准化的注释和API标准化,可以用直观的方式开发RESTful Web服务。
核心客户端(Core Client) Jersey客户端API能够帮助开发者与RESTful服务轻松通信;
集成(Integration) Jersey还提供可以轻松继承Spring、Guice、Apache Abdera的库。
本节使用Jersey集成Spring搭建。
[b]1.spring web基础环境[/b]
eclipse的Maven Web工程,工程名为testRest。集成spring并创建简单的Teacher模块,包含POJO、SERVICE、DAO层简单代码,使用spring注解注入bean。
见[url=http://sb33060418.iteye.com/blog/2372646]spring mvc系列[/url],第六篇使用springmvc实现了REST。
后续各框架陆续并入该工程。
[b]2.REST地址[/b]
设计jersey模块rest接口地址:
/jersey/teachers GET 获取所有资源
/jersey/teachers POST 创建新资源,content中包含资源内容
/jersey/teacher/{id} GET 获取编号为id的资源
/jersey/teacher/{id} PUT 更新编号为id的资源,content中包含资源内容
/jersey/teacher/{id} DELETE 删除编号为id的资源
[b]3.jersey库[/b]
在项目pom.xml中加入Jersey依赖:
使用Jersey老版本2.25.1,与spring4集成也可使用jersey-spring3包。不使用jersey-client调用api可不载入该依赖。
[b]4.Servlet[/b]
配置Jersey访问入口。
Jersey Servlet将拦截/jersey/*下的所有访问。
因为Jersey服务必须通过容器来访问,实践过程中发现直接在web.xml中配置:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.sunbin.test.jersey</param-value>
</init-param>
不生效,还是需要实现Application来设置扫描的包路径。
新增JerseyConfig类:
Jersey将com.sunbin.test.jersey包下的类中的注解,转换为REST服务。
[b]5.实现api[/b]
在com.sunbin.test.jersey新增TeachersResource类,以实现/teachers路径的接口:
用到了以下JAX-RS注解:
@Path("teachers")绑定路径:/servlet路径/teachers。可在类和方法上加注解。
@Produces(MediaType.APPLICATION_JSON)支持返回类型:application/json。可支持多种类型,按请求header:AcceptType返回。
@GET:GET请求的响应方法。
@POST:POST请求的响应方法。
@FormParam("age") int age, @FormParam("name") String name:获取通过application/x-www-form-urlencoded方式提交的参数。
新增TeacherResource类,以实现/teacher/{id}路径的接口:
用到了以下JAX-RS注解:
@PathParam("id"):获取路径参数{id}
@PUT:PUT请求的响应方法。
@DELETE:DELETE请求的响应方法。
[b]6.js测试[/b]
Jersey不像springmvc一样,可以通过在POST form中增加_method=PUT/DELETE隐藏参数的方法来支持表单直接提交PUT/DELETE,所以要通过javascript或者程序来访问。
先使用jquery库来进行ajax访问测试。
在src\main\webapp\rest目录下新建index.jsp:
重新部署后,使用浏览器访问[url]http://localhost:8080/testRest/rest[/url],可以看到页面:
[img]http://dl2.iteye.com/upload/attachment/0125/0690/2365687a-5a8a-3076-bbfe-06491a04b43e.png[/img]
通过js访问REST api,就类似网站使用第三方登录(QQ、微博等)后访问用户头像昵称的过程,当然登录时一般使用OAUTH2.0 做认证方案。
[b]7.JerseyClient测试[/b]
Jersey提供Client库用于测试JAX-RS接口。Client不仅可用来测Jersey REST,也可以用来测试其他框架实现的接口和http服务。
新建TestJersey类,代码如下:
测试结果如下:
通过js访问REST api,类似于服务端、桌面应用、移动端APP使用第三方登录(QQ、微信等)后访问用户数据并保存的过程。
核心服务器(Core Server) 通过提供JSR 311中标准化的注释和API标准化,可以用直观的方式开发RESTful Web服务。
核心客户端(Core Client) Jersey客户端API能够帮助开发者与RESTful服务轻松通信;
集成(Integration) Jersey还提供可以轻松继承Spring、Guice、Apache Abdera的库。
本节使用Jersey集成Spring搭建。
[b]1.spring web基础环境[/b]
eclipse的Maven Web工程,工程名为testRest。集成spring并创建简单的Teacher模块,包含POJO、SERVICE、DAO层简单代码,使用spring注解注入bean。
见[url=http://sb33060418.iteye.com/blog/2372646]spring mvc系列[/url],第六篇使用springmvc实现了REST。
后续各框架陆续并入该工程。
[b]2.REST地址[/b]
设计jersey模块rest接口地址:
/jersey/teachers GET 获取所有资源
/jersey/teachers POST 创建新资源,content中包含资源内容
/jersey/teacher/{id} GET 获取编号为id的资源
/jersey/teacher/{id} PUT 更新编号为id的资源,content中包含资源内容
/jersey/teacher/{id} DELETE 删除编号为id的资源
[b]3.jersey库[/b]
在项目pom.xml中加入Jersey依赖:
<properties>
<jersey.version>2.25.1</jersey.version>
</properties>
<dependencies>
...
<!-- jersey begin -->
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<!-- if your container implements Servlet API older than 3.0, use "jersey-container-servlet-core" -->
<artifactId>jersey-container-servlet</artifactId>
<version>${jersey.version}</version>
</dependency>
<!-- Required only when you are using JAX-RS Client -->
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey.version}</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.ext</groupId>
<artifactId>jersey-spring3</artifactId>
<version>${jersey.version}</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>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-jaxrs</artifactId>
<version>1.8.11</version>
</dependency>
<!-- jersey end -->
...
使用Jersey老版本2.25.1,与spring4集成也可使用jersey-spring3包。不使用jersey-client调用api可不载入该依赖。
[b]4.Servlet[/b]
配置Jersey访问入口。
<!-- jersey -->
<servlet>
<servlet-name>Jersey REST Service</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.sunbin.test.jersey.JerseyConfig</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>Jersey REST Service</servlet-name>
<url-pattern>/jersey/*</url-pattern>
</servlet-mapping>
Jersey Servlet将拦截/jersey/*下的所有访问。
因为Jersey服务必须通过容器来访问,实践过程中发现直接在web.xml中配置:
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value>com.sunbin.test.jersey</param-value>
</init-param>
不生效,还是需要实现Application来设置扫描的包路径。
新增JerseyConfig类:
package com.sunbin.test.jersey;
import org.glassfish.jersey.server.ResourceConfig;
import org.codehaus.jackson.jaxrs.JacksonJsonProvider;
// TODO: Auto-generated Javadoc
/**
* The Class JerseyConfig.
*/
public class JerseyConfig extends ResourceConfig {
/**
* Instantiates a new jersey config.
*/
public JerseyConfig() {
// 配置扫描包
packages("com.sunbin.test.jersey");
// 配置json转换。配置后如果api定义返回类型为json、且pojo注解XmlRootElement,将自动转为json返回;否则需要自己转换
register(JacksonJsonProvider.class);
}
}
Jersey将com.sunbin.test.jersey包下的类中的注解,转换为REST服务。
[b]5.实现api[/b]
在com.sunbin.test.jersey新增TeachersResource类,以实现/teachers路径的接口:
package com.sunbin.test.jersey;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;
@Path("teachers")
@Produces(MediaType.APPLICATION_JSON)
public class TeachersResource {
@Autowired
private TeacherService teacherService;
@GET
public Map get() {
System.out.println("Jersey TeachersResource.get");
Map map = new HashMap();
map.put("teachers", teacherService.list());
return map;
}
@POST
public Map post(@FormParam("age") int age, @FormParam("name") String name) {
Map map = new HashMap();
try {
Teacher teacher = new Teacher();
teacher.setName(name);
teacher.setAge(age);
System.out.println("Jersey TeachersResource.post:" + teacher);
teacherService.save(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
}
用到了以下JAX-RS注解:
@Path("teachers")绑定路径:/servlet路径/teachers。可在类和方法上加注解。
@Produces(MediaType.APPLICATION_JSON)支持返回类型:application/json。可支持多种类型,按请求header:AcceptType返回。
@GET:GET请求的响应方法。
@POST:POST请求的响应方法。
@FormParam("age") int age, @FormParam("name") String name:获取通过application/x-www-form-urlencoded方式提交的参数。
新增TeacherResource类,以实现/teacher/{id}路径的接口:
package com.sunbin.test.jersey;
import java.util.HashMap;
import java.util.Map;
import javax.ws.rs.DELETE;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;
@Path("teacher/{id}")
@Produces(MediaType.APPLICATION_JSON)
public class TeacherResource {
@Autowired
private TeacherService teacherService;
@GET
public Map get(@PathParam("id") int id) {
System.out.println("Jersey TeacherResource.get:" + id);
Teacher teacher = new Teacher();
teacher.setId(id);
Map map = new HashMap();
map.put("teacher", teacherService.get(teacher));
return map;
}
@PUT
public Map put(@PathParam("id") int id, @FormParam("age") int age,
@FormParam("name") String name) {
Map map = new HashMap();
try {
Teacher teacher = new Teacher();
teacher.setId(id);
teacher.setName(name);
teacher.setAge(age);
System.out.println("Jersey TeacherResource.put:" + id + ":"
+ teacher);
teacherService.update(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
@DELETE
public Map delete(@PathParam("id") int id) {
Map map = new HashMap();
try {
System.out.println("Jersey TeacherResource.delete:" + id);
Teacher teacher = new Teacher();
teacher.setId(id);
teacherService.remove(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return map;
}
}
用到了以下JAX-RS注解:
@PathParam("id"):获取路径参数{id}
@PUT:PUT请求的响应方法。
@DELETE:DELETE请求的响应方法。
[b]6.js测试[/b]
Jersey不像springmvc一样,可以通过在POST form中增加_method=PUT/DELETE隐藏参数的方法来支持表单直接提交PUT/DELETE,所以要通过javascript或者程序来访问。
先使用jquery库来进行ajax访问测试。
在src\main\webapp\rest目录下新建index.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>teacher</title>
<script type="text/javascript" src="<%=path %>/resources/js/jquery-3.2.0.js"></script>
<script type="text/javascript">
// 测试框架
var restType = "jersey";
//var restType = "restlet";
//var restType = "resteasy";
//var restType = "restCxf";
//var restType = "restMvc";
// 初始化加载
$(document).ready(function(){
list();
var ajaxOption = null;
$("#saveButton").click(function(){
save();
});
});
// GET /teachers
function list(){
$.ajax({
url:"../"+ restType +"/teachers",
dataType:"json",
success:function(data){
$("#listBody").empty();
$.each(data.teachers, function(i, item){
var teacherTr = "<tr><form name='updateForm_"+item.id+"' action='teacher/update' method='POST'>"
+"<td><input type='hidden' name='id' id='id_"+item.id+"' value='"+item.id+"'/>"+item.id+"</td>"
+"<td><input type='text' name='name' id='name_"+item.id+"' value='"+item.name+"' /></td>"
+"<td><input type='text' name='age' id='age_"+item.id+"' value='"+item.age+"' /></td>"
+"<td><a href='javascript:void(0);' onclick='get("+item.id+");'>get</a> "
+"<a href='javascript:void(0);' onclick='remove("+item.id+");'>remove</a> "
+"<input type='submit' value='update' id='updateButton_"+item.id+"' onclick='update("+item.id+");' /></td></tr>";
$("#listBody").append(teacherTr);
});
}
});
}
// POST /teachers
function save(){
$("#saveButton").attr("disabled", true);
$.ajax({
url:"../"+ restType +"/teachers",
type:"POST",
data:"name="+$("#name").val()+"&"+"age="+$("#age").val(),
dataType:"json",
complete:function(){
$("#saveButton").attr("disabled", false);
},
success:function(data){
alert(data.status);
$("#name").val('');
$("#age").val('');
list();
}
});
}
// GET /teachers/{id}
function get(id){
$.ajax({
url:"../"+ restType +"/teacher/"+id,
dataType:"json",
success:function(data){
var teacherInfo = "id:"+data.teacher.id+"\nname:"+data.teacher.name+"\nage:"+data.teacher.age;
alert(teacherInfo);
}
});
}
// DELETE /teachers/{id}
function remove(id){
$.ajax({
url:"../"+ restType +"/teacher/"+id,
type:"DELETE",
dataType:"json",
success:function(data){
alert(data.status);
list();
}
});
}
// PUT /teachers/{id}
function update(id){
$("#updateButton_"+id).attr("disabled", true);
$.ajax({
url:"../"+ restType +"/teacher/"+id,
type:"PUT",
data:"&name="+$("#name_"+id).val()+"&"+"age="+$("#age_"+id).val(),
dataType:"json",
complete:function(data){
$("#updateButton_"+id).attr("disabled", false);
},
success:function(data){
alert(data.status);
list();
}
});
}
</script>
</head>
<body>
save
<form name="saveForm" action="teacher/save" method="POST">
name:<input type="text" name="name" id="name" />
age:<input type="text" name="age" id="age" />
<input type="button" value="save" id="saveButton" />
</form>
<br/>
list
<table border="1">
<thead>
<tr>
<td>id</td>
<td>name</td>
<td>age</td>
<td>操作</td>
</tr>
</thead>
<tbody id="listBody">
<!-- 无用,通过js增加行 -->
<c:forEach items="${list }" var="teacher">
<tr>
<form name="updateForm_${teacher.id}" action="teacher/update" method="POST">
<td><input type="hidden" name="id" id="id" value="${teacher.id}" />${teacher.id}</td>
<td><input type="text" name="name" id="name" value="${teacher.name}" /></td>
<td><input type="text" name="age" id="age" value="${teacher.age}" /></td>
<td>[url=javascript:void(0);]get[/url] [url=javascript:void(0);]remove[/url] <input type="submit" value="update" id="updateButton_${teacher.id}" /></td>
</form>
</tr>
</c:forEach>
</tbody>
</table>
</body>
</html>
重新部署后,使用浏览器访问[url]http://localhost:8080/testRest/rest[/url],可以看到页面:
[img]http://dl2.iteye.com/upload/attachment/0125/0690/2365687a-5a8a-3076-bbfe-06491a04b43e.png[/img]
通过js访问REST api,就类似网站使用第三方登录(QQ、微博等)后访问用户头像昵称的过程,当然登录时一般使用OAUTH2.0 做认证方案。
[b]7.JerseyClient测试[/b]
Jersey提供Client库用于测试JAX-RS接口。Client不仅可用来测Jersey REST,也可以用来测试其他框架实现的接口和http服务。
新建TestJersey类,代码如下:
package com.sunbin.test.jersey;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Form;
public class TestJersey {
public static final String URL_BASE = "http://localhost:8080/testRest/jersey/";
public static void main(String[] args) {
Client client = ClientBuilder.newClient();
String module = "teacher";
String url = "";
String result = "";
Entity<Form> entity = null;
Form form = null;
WebTarget baseTarget = client.target(URL_BASE);
WebTarget target = null;
url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);
url = URL_BASE + module + "s";
System.out.println("post\t " + url);
target = baseTarget.path(module + "s");
form = new Form().param("age", "1").param("name", "a");
entity = Entity.form(form);
result = target.request().post(entity, String.class);
System.out.println(result);
url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);
url = URL_BASE + module + "/1";
System.out.println("get\t " + url);
target = baseTarget.path(module + "/1");
result = target.request().get(String.class);
System.out.println(result);
url = URL_BASE + module + "/1";
System.out.println("put\t " + url);
target = baseTarget.path(module + "/1");
form = new Form().param("age", "11").param("name", "aa");
entity = Entity.form(form);
result = target.request().put(entity, String.class);
System.out.println(result);
url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);
url = URL_BASE + module + "/1";
System.out.println("delete\t " + url);
target = baseTarget.path(module + "/1");
result = target.request().delete(String.class);
System.out.println(result);
url = URL_BASE + module + "s";
System.out.println("get\t" + url);
target = baseTarget.path(module + "s");
result = target.request().get(String.class);
System.out.println(result);
}
}
测试结果如下:
get http://localhost:8080/testRest/jersey/teachers
{"teachers":[]}
post http://localhost:8080/testRest/jersey/teachers
{"status":"y"}
get http://localhost:8080/testRest/jersey/teachers
{"teachers":[{"id":1,"age":1,"name":"a"}]}
get http://localhost:8080/testRest/jersey/teacher/1
{"teacher":{"id":1,"age":1,"name":"a"}}
put http://localhost:8080/testRest/jersey/teacher/1
{"status":"y"}
get http://localhost:8080/testRest/jersey/teachers
{"teachers":[{"id":1,"age":11,"name":"aa"}]}
delete http://localhost:8080/testRest/jersey/teacher/1
{"status":"y"}
get http://localhost:8080/testRest/jersey/teachers
{"teachers":[]}
通过js访问REST api,类似于服务端、桌面应用、移动端APP使用第三方登录(QQ、微信等)后访问用户数据并保存的过程。