前言
关于RESTful API的概念网上已经说过很多,可以用很多语言与框架实现,其规范也十分详尽。我这篇入门教程尽量用自己的理解去总结RESTful API的一些要点,并以JaveEE规范的JAX-RS框架为例,以实战的形式去讲述怎么搭建一套RESTful API,并在实践过程中体现RESTful API的设计规范。
什么是RESTful API
- 服务器端提供给开发者的一套接口,开发者通过调用这些接口,访问服务器的资源。这些资源通常是数据库的表抽象出来的对象,程序员通过获取这些对象,把对这些对象的增删改查映射到数据库,从而实现自己前后端的其他业务逻辑。目前移动端很多都是使用RESTful API来访问后台,受移动端影响,浏览器端也越来越多地使用这种规范。
- 本质就是http协议。RESTful API的所有操作无非是CRUD,全部映射成http的POST,GET,PUT,PATCH,DELETE等方法,操作RESTful API实际上就是操作http报文,其只是在http协议外面再封装一层。因此操作十分简洁,直观,代码优雅。
- 用URI定位所有资源。服务器端把所有供开发者访问的资源都以特定的URI表示。URI与http方法(上述的POST,GET等)组合,便可以实现对所有资源的所有操作。以微博和评论为例,假如新浪微博开放了所有微博和评论允许开发者访问。那么所有微博的URI可能是:
api/weibo
id为30691的微博URI可能是:api/weibo/30691
id为30691的微博所有评论的URI可能是:api/weibo/30691/comment
id为30691的微博对应的评论id为2589的评论的URI可能是:api/weibo/30691/comment/2589
出于面向对象的思想,一般每个资源都对应一个对象,应该用名词表示,且倾向于单数。资源之间的依赖关系可以参照上述的weibo与comment。由于评论必定对应于某一条微博,所以可以用类似weibo/30691/comment的形式表示这种依赖。
显而易见,这种目录式的URI定位十分直观,简单。
搭建基本JAX-RS环境
JAX-RS是JaveEE框架里专门用来实现RESTful API的技术。搭建十分简单,且大都用注解注入的形式实现,使代码结构十分清晰,代码量很少。除了依赖的包以及一些xml配置文件以外,代码里只需要自己继承实现javax.ws.rs.core.Application类便可以完成最基本的配置。依赖的包和xml配置可自行上网搜索,不是我这篇教程的重点,这里将主要介绍代码里如何实现RESTful API
Application类
必须创建一个类继承Application类。JAX-RS里我们用到的组件主要有两类,分别是Resource和Provider。Resource就是上述的URI对应的可供用户访问的资源。Provider是运行时自行调用的一些类,起到配置作用,这在下一讲再详细介绍。这两类组件都必须在Application类的实现类的Set
|
|
HelloWorldResource就是Resource组件的其中一个类,如果RESTful API需要访问这个资源类,则需要用上述的语法实现注册,是不是很简单。
ResourceConfig类
ResourceConfig是JAX-RS里提供的一个Application的实现类,通过继承这个类并且在其派生类的构造方法里对组件进行注册,可以简化注册的过程。除了对需要使用的Resource和Provider组件进行register以外,还可以通过提供要注册组件所在的包,而自动将包内所有这两类组件注册。以下是示例:
|
|
ApplicationPath注解
可以为Application的实现类添加@javax.ws.rs.ApplicationPath注解,那么所有RESTful API的URI资源都将包含该注解提供的名字作为前缀。以下是示例:
在这里注册的所有资源,其URI定位都必然是/api/…
Resource组件
搭建了基本的JAX-RS环境,便可以进行真正的业务逻辑的实现了。所谓的业务逻辑,无非对特定URI资源的增删改查操作。这些都是在Resource组件方法里通过特定的注解实现操作和资源的匹配的。所有在类名上面添加了@path注解的,都被认为是Resource组件。这些类方法上添加的@path注解,将与类的@path注解提供的名字以及ApplicationPath注解提供的名字组合在一起,作为其URI。
以下是Resource组件类示例:
以下是某资源方法示例:
先忽略掉无关的代码,只看@GET和@Path标注。@GET很容易猜到是用http的GET方法。@Path便是该资源的URI的一部分。如果findUnSolved方法是类MessageFacadeREST里的方法,且MessageFacadeREST在ApplicationConfig类里注册,那么findUnSolved方法便可以通过/api/message/danger-unsolved这个URI访问。如果加上@GET方法,那么就是对/api/message/danger-unsolved这个资源用http的GET方法访问,实际上便是调用对应的findUnSolved方法。
HTTP方法
RESTful API里涉及的HTTP方法一般是GET,POST,PUT,PATCH,DELETE。这些HTTP方法都是用注解形式添加在相应的Resource组件类的方法上。
- GET方法:用于对资源的读取,一般返回单个对象或者对象列表。
- POST方法:用于创建新对象,需要在客户端传送一个完整对象给服务器,然后将整个对象写入数据库。一般需返回创建好的对象。
- PUT方法:用于创建或替换已有对象,需要在客户端传送一个完整对象给服务器,如果数据库没有对应数据,则插入新数据;如果已有旧记录,则用新对象更新。一般需返回创建或更新的对象。
- PATCH方法:用于修改某已有对象的部分属性。如果确保对象记录已经在服务器存在,且只需要修改很少的属性,那么推荐用PATCH方法去代替PUT方法。PATCH方法不需要传送整个对象,只需要传送对象id以及需要修改的属性即可。一般需返回更新的对象。
- DELETE方法:删除相应对象记录。无返回。
有一些HTTP proxy只支持GET和POST方法,而不支持其他方法。这种情况在规范里一般在http header里加入X-HTTP-Method-Override的key,里面保存真正的http方法,例如”PUT”或”PATCH”,而请求一律通过POST方法发送到服务器端。具体的代码实现将会在下一讲介绍。
数据传输及序列化与反序列化
在RESTful API操作的是对象,传出与接收一般是实体的POJO对象。而对象如果传出,需要先进行序列化,以xml或json的形式传送。对象如果接收,则要进行反序列化,把json或xml的数据转换成实体的POJO对象。序列化或进行反序列化的数据类型一般用@Produces和@Consumes注解来实现。下面给出一个例子:
|
|
方法block是通过http的PUT方法访问的,需要传入一个MessageDTO对象,并返回一个MessageDTO对象。@Produces定义了返回对象将序列化成为json格式;@Cosumes定义了接收的对象是json格式的,将对其进行反序列化。JAX-RS里本身没有实现对特定对象自动进行序列化与反序列化。一般需实现MessageBodyWriter或MessageBodyReader这两个类,在这两个类里自行进行序列化与反序列化的处理。这两个类都属于Provider,将在下一讲介绍。但实际上,如果只是简单的进行json或xml的转换是非常简单的,并不需要另外实现Provider,只有对具体的格式有要求或者需要进行更多的配置才有必要实现。一般如果进行xml转换,只需要修改@Produces和@Consumes为对应格式,并且在需要进行序列化与反序列化的POJO类上加上@XmlRootElement注解,便可实现。这种做法实际上是JAX-RS后台调用JAXB实现,@XmlRootElement是JAXB注解,而JAXB是专门用于进行xml和JAVA对象转换的技术。如果需要用json格式,同样可以通过JAXB的@XmlRootElement注解实现,只需把@Provider或@Consumes修改为application/json即可。实际上如果你是用glassfish 4以上作为application server container的,如果以json格式进行传输不需要任何其他Provider或@XmlRootElement,只需要修改@Provider或@Consumes即可。因为glassfish 4已经配置了MOXy作为Default JSON-Binding Provider。MOXy是json的一个框架,它可以在Application里自动注册,不需要显示地手动注册资源。
目前,RESTful API规范建议一律采用json作为数据传输的格式,而不要使用xml。
总结
这篇教程主要针对JAX-RS的Resource组件的基础知识,介绍了RESTful API的概念,以及HTTP方法,URI资源定位和数据传输格式这三个最核心的内容,并涉及了一些RESTful API的设计规范。更多的设计规范以及关于Provider的知识,将再后面一一介绍。