笔记:Jersey REST API 设计
- REST 统一接口
REST 使用 HTTP 协议的通用方法作为统一接口的标准词汇,REST 服务所提供的方法信息都在 HTTP 方法里,每一种HTTP请求方法都可以从安全性和幂等性两方面考虑,这对正确理解HTTP请求方法和设计统一接口具有决定性的意义,安全性是指系统对接口的访问,不会使服务器端资源的状态发生改变;幂等性是指系统对同一REST接口的多次访问,得到的资源状态是相同的,以下是各个方法的安全性和幂等性要求:
|
方法名称 |
安全性 |
幂等性 |
说明 |
|
GET |
Y |
Y |
GET 方法是只读的 |
|
PUT |
N |
Y |
PUT 方法是一种写操作的HTTP请求,PUT方法是幂等性的,即多次插入或者更新同一份数据,如果每次提交到服务器端,都会为数据添加一个新的主键值,那么就不是幂等性的,因此需要使用POST 方法 |
|
DELETE |
N |
Y |
DELETE 方法是幂等的,即多次删除同一份数据,在服务器端的改变相同,执行删除的方法其返回值可以定义为 void,无返回值的方法,返回的响应实体为空,HTTP状态码为204 |
|
POST |
N |
N |
POST 方法是写操作的HTTP请求,RPC 的所有写操作均使用 POST 方法,REST 只使用 HTTP 的POST 方法增加资源 |
- 资源地址设计
资源地址的设计对整个REST式的Web服务至关重要,涉及系统的可用性、可维护性和可扩展性等诸多方面的表现,资源地址的路径变量是用来表达逻辑上的层次结构的,资源和子资源的形式是自左至右、斜杠分割的名词,一个典型的URI包括协议名称、主机名称、服务端口、资源地址和查询字符串等组成,URI 组成如下:
http://localhost:8080/rest-demo/webapi/demos/demo?id=1
其中 rest-demo 表示 ContextPath(上下文路径)通常和部署服务器的配置或者REST服务的web.xml配置有关;webapi 表示 ServletPath 是 Servlet 名称,与 REST 服务中定义的 @ApplicationPath 注解或者web.xml 的配置有关;demos/demo 为资源地址,与资源类、子类以及类中的方法定义的@Path注解有关。需要注意的是,资源地址并不能唯一定位一个资源,只有资源地址和HTTP方法才能唯一定位资源。
在路径变量里可以使用标点符合以辅助增强逻辑清晰性,作为资源地址的查询变量,用来表达算法的输入,实现对方法的作用域的约束,标点符号说明如下:
- 问号(?)是用来分割资源地址和查询字符串的,与符号(&)是用来分割查询条件的参数, 示例代码如下:
GET /demos?start=0&size=10
- 逗号(,)是用来分割有次序的作用域信息,这种顺序可以是约定俗成的,比如先经度后纬度等,示例代码如下:
GET /demos/01,2002-12,2014
这段代码表示查询2002年1月到2014年12月的数据,这个例子中还是用了连字符(-)
- 分号(;)是用来分割无序的作用域信息,通常这些信息是逻辑上并列存在的,示例代码如下:
GET /demos/name;program=java;type=web
- 路径变量注解
- @QueryParam 注解
查询条件决定了方法的作用域,查询参数组成了查询条件,使用@QueryParam注解来定义查询参数,使用示例如下:
|
接口描述 |
资源地址 |
|
分页查询列表数据 |
/demos?start=10&size=100 |
|
查询单项数据 |
/demos/demo?id=12 |
分页查询注解示例:
Public DemoList getBypaging(@QueryParam("start") final int start,@DefaultValue("100") @QueryParam("size") final int size){
// 查询代码
}
查询单项数据注解示例:
Public Demo getEntity(@QueryParam("id") final int id){
// 查询代码
}
注解@QueryParam 可以和注解@DefaultValue 一起使用,注解 @DefaultValue 的作用是预置一个默认值,当请求不包含参数时,使用该默认值
- @PathParam参数
用来定义路径参数,每个参数对应一个子资源,使用示例如下:
|
接口描述 |
资源地址 |
|
基本路径参数 |
/demos/eric |
|
带标点符号的资源路径 |
/demos/01,2012-12,2014 |
|
子资源变长的资源路径 |
/demos/d/e/m/o /demos/q2/restful;program=java;type=web |
@Path 注解来定义资源路径,需要一个value参数来解析资源路径,该参数除了使用静态定义的方式外,也可以使用动态变量的方式,其格式为:{参数名称:正则表达式}。
基本路径参数注解示例:
@GET
@Path("eric")
Public string get(){
// 查询代码
}
带标点符号的资源路径注解示例:
@GET
@Path("{from:[0-9]{2},[0-9]{4}}-{to:[0-9]{2},[0-9]{4}}")
Public string getByCondition(@PathParam("from") string fromString,@PathParam("to") string toString){
// 查询代码
}
路径区间(PathSegment)是对资源地址更灵活的支持,使资源类的一个方法可以支持更广泛的资源地址请求,例如,固定子资源和动态子资源两个部分,对于动态匹配变长的子资源地址,PathSegment 类型的参数结合正则表达式很容易处理,示例如下:
@GET
@Path("{p:.+}/m/{n:[a-zA-Z]+}")
Public string getByAddress(@PathParam("p") final List<PathSegment> p,@PathParam("n") final string n){
Final StringBuilder result = new StringBuilder();
for(final PathSegment path : p){
result.append(path.getPath()).append("-");
}
return result.toString();
}
对于查询参数动态给定的场景,可以定义PathSegment作为参数类型,通过 getMatrixParameters方法获取 MultivaluedMap 类型的查询参数信息,示例代码如下:
@Path("q2/{condition}")
@GET
public String get(@PathParam("condition") final PathSegment condition) {
StringBuilder stringBuilder = new StringBuilder();
final MultivaluedMap<String, String> map = condition.getMatrixParameters();
final Iterator<Map.Entry<String, List<String>>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
Map.Entry<String, List<String>> entry = iterator.next();
stringBuilder.append(entry.getKey()).append("=");
stringBuilder.append(entry.getValue()).append(" ");
}
return stringBuilder.toString();
}
上例是通过编程的方式调用PathSegment类的getMatrixParameters()方法来查询获取参数信息,还可以通过@MatrixParam注解来逐一定义参数,示例代码如下:
@Path("q3/{condition}")
@GET
public String get(@MatrixParam("program") String program, @MatrixParam("type") String type) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("program="+program).append("&type=").append(type);
return stringBuilder.toString();
}
- @FormParam 注解
该注解用于定义表单参数,相应的REST方法用以处理请求实体媒体类型为 Content-Type:application/x-www-form-urlencoded的请求,示例代码如下:
@Path("create")
@POST
@Produces(MediaType.APPLICATION_JSON)
public DemoResult create(@FormParam("name") String name, @FormParam("sex") String sex) {
DemoResult result = new DemoResult();
result.setHasError(false);
result.setMessage("创建 name=" + name + "\tsex=" + sex);
return result;
}
默认情况下,会对表单参数进行自动解码,也可以使用@Encoded注解来禁用自动解码
- @BeanParam 注解
该注解用于自定义参数组合,使REST方法可以使用简洁的参数形式完成复杂的接口设计,示例代码如下:
- 自定义参数类:
public class CreateParam {
@FormParam("name")
private String name;
@FormParam("sex")
private String sex;
// getter 和 setter 方法
}
- REST服务方法:
@Path("createparam")
@POST
public DemoResult createByBeanPraam(@BeanParam CreateParam createParam) {
DemoResult result = new DemoResult();
result.setHasError(false);
result.setMessage("创建 name=" + name + "\tsex=" + sex);
return result;
}
- @CookieParam 注解
该注解用以匹配Cookie中的键值对Cookie中的键值对信息,示例代码如下:
@Path("createbycookie")
@POST
public DemoResult createByCookie(@FormParam("name") String name, @FormParam("sex") String sex,
@CookieParam("dir") String bir) {
DemoResult result = new DemoResult();
result.setHasError(false);
result.setMessage("创建 name=" + name + "\tsex=" + sex + "\tcookie=" + bir);
return result;
}
- @Context 注解
该注解来解析上下文参数,REST服务中,有多种元素可以通过@Context注解作为上下文参数使用,示例代码如下:
@Path("context")
@GET
public String get(@Context Application application, @Context Request request,
@Context Providers provider, @Context UriInfo uriInfo,
@Context HttpHeaders httpHeaders) {
}
笔记:Jersey REST API 设计的更多相关文章
- 第3章 接口与API设计 52条笔记
第3章 接口与API设计 52条笔记 第15条: 用前缀避免命名空间冲突 Objective-C 没有其他语言那种内置的命名空间机制 .鉴于此,我们在起名时要设法避免潜在的命名冲突,否则很容易就重名了 ...
- effective OC2.0 52阅读笔记(三 接口与API设计)
第三章:接口与API设计 15 用前缀避免命名空间冲突 总结:避免重名符号错误的唯一办法是变相实现命名空间.为所有符号都加上命名前缀.类和分类都应加三字前缀.注意类实现文件中的纯C函数及全局变量,是算 ...
- HTML5项目笔记4:使用Audio API设计绚丽的HTML5音乐播放器
HTML5 有两个很炫的元素,就是Audio和 Video,可以用他们在页面上创建音频播放器和视频播放器,制作一些效果很不错的应用. 无论是视屏还是音频,都是一个容器文件,包含了一些音频轨道,视频轨道 ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- javascript的api设计原则
前言 本篇博文来自一次公司内部的前端分享,从多个方面讨论了在设计接口时遵循的原则,总共包含了七个大块.系卤煮自己总结的一些经验和教训.本篇博文同时也参考了其他一些文章,相关地址会在后面贴出来.很难做到 ...
- (转载) RESTful API 设计指南
作者: 阮一峰 日期: 2014年5月22日 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......). 因此,必须有一种统一的机制 ...
- RESTful API 设计指南
转自:http://www.ruanyifeng.com/blog/2014/05/restful_api.html 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机. ...
- GOTO Berlin: Web API设计原则
在邮件列表和讨论区中有很多与REST和Web API相关的讨论,下面仅是我个人对这些问题的一些见解,并没有绝对的真理,InnoQ的首席顾问Oliver Wolf在GOTO Berlin大会上开始自己的 ...
- RESTful API 设计最佳实践
背景 目前互联网上充斥着大量的关于RESTful API(为了方便,以后API和RESTful API 一个意思)如何设计的文章,然而却没有一个"万能"的设计标准:如何鉴权?API ...
随机推荐
- Hadoop1.x原理
将这种单机的工作进行分拆,变成协同工作的集群,这就是分布式计算框架设计.使得计算机硬件类似于应用程序中资源池的资源,使用者无需关心资源的分配情况,从而最大化了硬件资源的使用价值.分布式计算也是如此,具 ...
- 【java学习笔记】序列化、反序列化
序列化 是将对象的完整信息保存起来的过程(持久化). 序列化流:ObjectOutputStream 反序列化 是将对象进行还原的过程(反持久化). 反序列化流:Ob ...
- R语言︱贝叶斯网络语言实现及与朴素贝叶斯区别(笔记)
每每以为攀得众山小,可.每每又切实来到起点,大牛们,缓缓脚步来俺笔记葩分享一下吧,please~ --------------------------- 一.贝叶斯网络与朴素贝叶斯的区别 朴素贝叶斯的 ...
- JAVA代码发送邮件示例和解释(二)
之前有使用过一次在程序中发邮件的功能,也写了一篇相关的笔记,当时使用的是163邮箱,经过测试多个163账号都是可行的.但是最近把账号换成中国移动@chinamobilesz.com这种结尾的时候,却一 ...
- dojo拼接成CSV格式字符串
var student = "学号,姓名,年龄\n"; for(var i = 0;i<resp.items.length;i++) { student += resp.it ...
- jQuery提示parsererror错误解决办法
jquery来处理ajax,用到了json.但是很诧异,jquery的ajax回调时一直调用了error函数(一直提示parsererror异常),success函数一次没执行过 $.ajax({ t ...
- vector 遍历
vector向量容器,是数组的一个泛化推广.实现了类似于数据结构中顺序表的操作. vector容器是一个模板类,可以存放任何类型的对象(但必须是同一类对象).vector对象可以在运行时高效地添加元素 ...
- MiniGUI + Hi3531 笔记 .
一.移动光驱安装Ubuntu 10.04 1. 重启系统按住Delete进入BIOS界面! 2. 退出/高级模式 --> 启动 --> 启动设备选择. 移动光驱正常被识别后这里应该 ...
- (二十四)mongodb中group的问题二
今天的工作还是继续昨天没有完成的,由于对mongodb数据库的不熟悉,导致昨天的思路上也出了一点问题,我需要查询出同一个ruleID中不同的processingID的条数,然后根据条数来排列先后顺序, ...
- windows驱动程序wdf--KMDF大致框架
继WDM后微软出了WDF,封装了WDM中的一些基本代码逻辑.本人菜鸟,也不知道本质上有何区别,只觉得是多了Wdf开头的函数,基本的编程框架上有点出入. KMDF是WDF的内核级部分,为了理清KMDF的 ...