示例简介
记账簿示例应用程序中包含了 3 种资源:账目、用户以及账目种类,用户与账目、账目种类与账目之间都是一对多的关系。记账簿实现的主要功能包括:
1. 记录某用户在什么时间花费了多少金额在哪个种类上
2. 按照用户、账目种类、时间或者金额查询记录
3. 对用户以及账目种类的管理
Resource 类和 Resource 方法
Web 资源作为一个 Resource 类来实现,对资源的请求由 Resource 方法来处理。Resource 类或 Resource 方法被打上了 Path 标注,Path 标注的值是一个相对的 URI 路径,用于对资源进行定位,路径中可以包含任意的正则表达式以匹配资源。和大多数 JAX-RS 标注一样,Path 标注是可继承的,子类或实现类可以继承超类或接口中的 Path 标注。
Resource 类是 POJO,使用 JAX-RS 标注来实现相应的 Web 资源。Resource 类分为根 Resource 类和子 Resource 类,区别在于子 Resource 类没有打在类上的 Path 标注。Resource 类的实例方法打上了 Path 标注,则为 Resource 方法或子 Resource 定位器,区别在于子 Resource 定位器上没有任何 @GET、@POST、@PUT、@DELETE 或者自定义的 @HttpMethod。清单 1 展示了示例应用中使用的根 Resource 类及其 Resource 方法。
清单 1. 根 Resource 类
@Path("/")
public class BookkeepingService {
......
@Path("/person/")
@POST
@Consumes("application/json")
public Response createPerson(Person person) {
......
}
@Path("/person/")
@PUT
@Consumes("application/json")
public Response updatePerson(Person person) {
......
}
@Path("/person/{id:\\d+}/")
@DELETE
public Response deletePerson(@PathParam("id")
int id) {
......
}
@Path("/person/{id:\\d+}/")
@GET
@Produces("application/json")
public Person readPerson(@PathParam("id")
int id) {
......
}
@Path("/persons/")
@GET
@Produces("application/json")
public Person[] readAllPersons() {
......
}
@Path("/person/{name}/")
@GET
@Produces("application/json")
public Person readPersonByName(@PathParam("name")
String name) {
......
}
......
参数标注
JAX-RS 中涉及 Resource 方法参数的标注包括:@PathParam、@MatrixParam、@QueryParam、@FormParam、@HeaderParam、 @CookieParam、@DefaultValue 和 @Encoded。这其中最常用的是 @PathParam,它用于将 @Path 中的模板变量映射到方法参数,模板变量支持使用正则表达式,变量名与正则表达式之间用分号分隔。例如对 清单 1 中所示的 BookkeepingService 类,如果使用 Get 方法请求资源”/person/jeffyin”,则 readPersonByName 方法将被调用,方法参数 name 被赋值为”jeffyin”;而如果使用 Get 方法请求资源”/person/123”,则 readPerson 方法将被调用,方法参数 id 被赋值为 123。要了解如何使用其它的参数标注 , 请参考 JAX-RS API。
JAX-RS 规定 Resource 方法中只允许有一个参数没有打上任何的参数标注,该参数称为实体参数,用于映射请求体。例如 清单 1中所示的 BookkeepingService 类的 createPerson 方法和 updatePerson 方法的参数 person。
参数与返回值类型
Resource 方法合法的参数类型包括:
1. 原生类型
2. 构造函数接收单个字符串参数或者包含接收单个字符串参数的静态方法 valueOf 的任意类型
3. List<T>,Set<T>,SortedSet<T>(T 为以上的 2 种类型)
4. 用于映射请求体的实体参数
Resource 方法合法的返回值类型包括:
1. void:状态码 204 和空响应体
2. Response:Response 的 status 属性指定了状态码,entity 属性映射为响应体
3. GenericEntity:GenericEntity 的 entity 属性映射为响应体,entity 属性为空则状态码为 204,非空则状态码为 200
4. 其它类型:返回的对象实例映射为响应体,实例为空则状态码为 204,非空则状态码为 200
对于错误处理,Resource 方法可以抛出非受控异常 WebApplicationException 或者返回包含了适当的错误码集合的 Response 对象。
Context 标注
通过 Context 标注,根 Resource 类的实例字段可以被注入如下类型的上下文资源:
1. Request、UriInfo、HttpHeaders、Providers、SecurityContext
2. HttpServletRequest、HttpServletResponse、ServletContext、 ServletConfig
CRUD 操作
JAX-RS 定义了 @POST、@GET、@PUT 和 @DELETE,分别对应 4 种 HTTP 方法,用于对资源进行创建、检索、更新和删除的操作。
POST 标注
POST 标注用于在服务器上创建资源,如 清单 2 所示。
清单 2. POST 标注
@Path("/")
public class BookkeepingService {
......
@Path("/account/")
@POST
@Consumes("application/json")
public Response createAccount(Account account) {
......
}
......
如果使用 POST 方法请求资源”/account”,则 createAccount 方法将被调用,JSON 格式的请求体被自动映射为实体参数 account。
GET 标注
GET 标注用于在服务器上检索资源,如 清单 3 所示。
清单 3. GET 标注
@Path("/")
public class BookkeepingService {
......
@Path("/person/{id}/accounts/")
@GET
@Produces("application/json")
public Account[] readAccountsByPerson(@PathParam("id")
int id) {
......
}
......
@Path("/accounts/{beginDate:\\d{4}-\\d{2}-\\d{2}},{endDate:\\d{4}-\\d{2}-\\d{2}}/")
@GET
@Produces("application/json")
public Account[] readAccountsByDateBetween(@PathParam("beginDate")
String beginDate, @PathParam("endDate")
String endDate) throws ParseException {
......
}
......
如果使用 GET 方法请求资源”/person/123/accounts”,则 readAccountsByPerson 方法将被调用,方法参数 id 被赋值为 123,Account 数组类型的返回值被自动映射为 JSON 格式的响应体;而如果使用 GET 方法请求资源”/accounts/2008-01-01,2009-01-01”,则 readAccountsByDateBetween 方法将被调用,方法参数 beginDate 被赋值为”2008-01-01”,endDate 被赋值为”2009-01-01”,Account 数组类型的返回值被自动映射为 JSON 格式的响应体。
PUT 标注
PUT 标注用于更新服务器上的资源,如 清单 4 所示。
清单 4. PUT 标注
@Path("/")
public class BookkeepingService {
......
@Path("/account/")
@PUT
@Consumes("application/json")
public Response updateAccount(Account account) {
......
}
......
如果使用 PUT 方法请求资源”/account”,则 updateAccount 方法将被调用,JSON 格式的请求体被自动映射为实体参数 account。
DELETE 标注
DELETE 标注用于删除服务器上的资源,如 清单 5 所示。
清单 5. DELETE 标注
@Path("/")
public class BookkeepingService {
......
@Path("/account/{id:\\d+}/")
@DELETE
public Response deleteAccount(@PathParam("id")
int id) {
......
}
......
如果使用 DELETE 方法请求资源”/account/323”,则 deleteAccount 方法将被调用,方法参数 id 被赋值为 323。
内容协商与数据绑定
Web 资源可以有不同的表现形式,服务端与客户端之间需要一种称为内容协商(Content Negotiation)的机制:作为服务端,Resource 方法的 Produces 标注用于指定响应体的数据格式(MIME 类型),Consumes 标注用于指定请求体的数据格式;作为客户端,Accept 请求头用于选择响应体的数据格式,Content-Type 请求头用于标识请求体的数据格式。
JAX-RS 依赖于 MessageBodyReader 和 MessageBodyWriter 的实现来自动完成返回值到响应体的序列化以及请求体到实体参数的反序列化工作,其中,XML 格式的请求/响应数据与 Java 对象的自动绑定依赖于 JAXB 的实现。
用户可以使用 Provider 标注来注册使用自定义的 MessageBodyProvider,如 清单 6 所示,GsonProvider 类使用了 Google Gson 作为 JSON 格式的 MessageBodyProvider 的实现。
清单 6. GsonProvider
@Provider
@Produces("application/json")
@Consumes("application/json")
public class GsonProvider implements MessageBodyWriter<Object>,
MessageBodyReader<Object> {
private final Gson gson;
public GsonProvider() {
gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().setDateFormat(
"yyyy-MM-dd").create();
}
public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return true;
}
public Object readFrom(Class<Object> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
throws IOException, WebApplicationException {
return gson.fromJson(new InputStreamReader(entityStream, "UTF-8"), type);
}
public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations,
MediaType mediaType) {
return true;
}
public long getSize(Object obj, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
return -1;
}
public void writeTo(Object obj, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
throws IOException, WebApplicationException {
entityStream.write(gson.toJson(obj, type).getBytes("UTF-8"));
}
}
JAX-RS 与 JPA 的结合使用
由于 JAX-RS 和 JPA 同样都使用了基于 POJO 和标注的编程模型,因而很易于结合在一起使用。示例应用中的 Web 资源 ( 如账目 ) 同时也是持久化到数据库中的实体,同一个 POJO 类上既有 JAXB 的标注,也有 JPA 的标注 ( 或者还有 Gson 的标注 ) ,这使得应用中类的个数得以减少。如 清单 7 所示,Account 类可以在 JAX-RS 与 JPA 之间得到复用,它不但可以被 JAX-RS 绑定为请求体 / 响应体的 XML/JSON 数据,也可以被 JPA 持久化到关系型数据库中。
清单 7. Account
@Entity
@Table(name = "TABLE_ACCOUNT")
@XmlRootElement
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "COL_ID")
@Expose
private int id;
@ManyToOne
@JoinColumn(name = "COL_PERSON")
@Expose
private Person person;
@Column(name = "COL_AMOUNT")
@Expose
private BigDecimal amount;
@Column(name = "COL_DATE")
@Expose
private Date date;
@ManyToOne
@JoinColumn(name = "COL_CATEGORY")
@Expose
private Category category;
@Column(name = "COL_COMMENT")
@Expose
private String comment;
......
REST 作为一种轻量级的 Web 服务架构被越来越多的开发者所采用,JAX-RS 的发布则规范了 REST 应用开发的接口。本文首先阐述了 REST 架构的基本设计原则,然后通过一个示例应用展示了 JAX-RS 是如何通过各种标注来实现以上的设计原则的,最后还介绍了 JAX-RS 与 JPA、Gson 的结合使用。本文的示例应用使用了 Jersey 和 OpenJPA,部署在 Tomcat 容器上,替换成其它的实现只需要修改 web.xml 和 persistence.xml 配置文件。
实例下载链接:
http://www.ibm.com/developerworks/cn/java/j-lo-jaxrs/Bookkeeping.zip
分享到:
相关推荐
为了让读者对REST在WCF中的应用有一个大致的了解,我们先来进行一个简单的实例演示。[源代码从这里下载] 微软在WCF3.5中就通过提供基于WebHTTP的编程模式使我们很容易地创建基于REST的服务,WCF4.0中对此进行了较...
Bboss is a good elasticsearch Java rest client. It operates and accesses elasticsearch in a way similar to mybatis.BBoss Environmental requirementsJDK requirement: JDK 1.7+Elasticsearch version ...
REST演示:React前端 React中REST客户端UI的简单演示。 该存储库实现了REST客户端应用程序,用于管理简单的书签数据库。 每个书签都包含一个名称(链接文本)和应链接到的URL。 该存储库是我的REST API演示项目的...
ng-cordova-facebook-example, 离子框架ngCordova的Oauth实例 Facebook的离子框架示例这个例子将演示如何使用ngCordova来验证Facebook和检索与 Facebook REST API 一起使用的访问令牌。要求Apache Cordova 3.5 ...
节点休息演示这演示了如何使用Node.js实现REST服务。运行时依赖bcrypt-用于从密码创建加密的哈希并将密码与哈希进行比较body-parser-用于解析HTTP请求正文(例如,当Content-Type标头为application/json时,解析为...
Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式 //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener 在...
Filmster 是一个演示(示例)项目,它演示了延迟加载 ListView 中的 REST 处理 REST API 由使用演示数据的模拟服务器提供(在 imdb.com 上公开提供) 技术细节 电影通过具有特定响应侦听器的异步任务从 REST API ...
通过运行,服务器主要是用于插入和列出框架的REST api。 所有逻辑都在客户端中运行。 该逻辑通过spock测试在groovy中完成,并通过转换为javascript。 使用require.js加载所有JavaScript内容。 创建创意项目: ./...
用于演示的API端点的工作流程包括对用户进行身份验证,搜索和获取数据集,创建报告和多维数据集的新实例,显示来自那些多维数据集和报告的过滤/排序的数据。 使用的REST API POST /身份验证/登录 给定凭据和身份...
这个小示例演示了如何使用 REST API 和 Apache HTTP 客户端为 Camunda BPM 创建部署。 测试一下 如果它不是localhost调整src/main/java/org/camunda/bpm/RestDeployment.java localhost 。 然后运行: mvn compile...
应网友要求,重新整理原《eclipse + maven多模块项目框架 + jetty热部署的实例源码》,增加了各配置的详细注释。 并且基于Spring MVC提供了一个完整功能:实现了生成验证码图片,以及验证输入是否匹配的两个接口,...
该项目旨在通过可用于部署的REST服务使您尽快启动并运行。 它使用以下技术: Java Sprint Boot Gradle 它演示了以下内容: 服务,域对象和测试客户端的单独项目 端到端单元测试 使用Jetty代替Tomcat作为容器 端点...
Message-Driven Bean EJB实例源代码,演示一个接收购物订单的消息驱动Bean,处理这个订单同时通过e-mail的形式 //给客户发一个感谢消息,消息驱动Bean必须实现两个接口MessageDrivenBean和MessageListener 在...
JavaOne 2015演示文稿的示例项目-“其他会话”。 主要目标是详细说明云解决方案中基于REST的集成模式。 介绍 该项目代表简化云解决方案的仿真。 云架构面向基于JAX-RS的微服务。 想法是,每个微服务都作为新的JVM...
然而,出于演示目的,它们与服务代码一起放置在这里,而不是单元测试,这将能够以较小的努力(使用模拟)实现类似的结果。 用法 构建包并运行本地服务器 run.sh 将war包部署到Tomcat服务器(必须设置CATALINA_HOME...
本实例是一个基于bboss es spring boot starter的demo maven工程,可供spring boot项目集成bboss elasticsearch rest client参考 展示了通过spring boot管理单集群功能和管理多集群功能 单集群测试用例:...
春天云演示 建筑-购物车 模组 购物车通用 通用数据传输对象,已在其他项目中重复使用 购物车客户边缘 面向客户的边缘应用程序。 与其他两个微服务交互 促销服务(购物车促销)。 客户边缘使用客户端来使用此推荐服务...
演示脚本使用Metron REST API为用例的每个元素安装配置。 它们还会更新弹性模板,并在群集上标准ssh用户的路径下的相关路径中安装任何数据生成器(如果只使用ssh而没有用户,则会得到什么) 待办事项-每个文件夹...
“备用只读 HDFS NameNode,没有 RPC 服务器,通过 REST API 为客户端提供服务,利用 Java 8 Stream API,所有这些都是为了为最终用户对整个文件系统元数据执行大型复杂的扫描。” 立即在本地运行演示! 只需在工作...