REST和JAX-RS相关知识介绍
REST
REpresentational State Transfer;代表性状态传输、具象状态传输
REST定义了应该如何正确地使用Web标准,例如HTTP和URI。REST并非标准,而是一种开发 Web 应用的架构风格,可以将其理解为一种设计模式。
REST关键原则
1、为所有“事物”定义ID
含义:
在Web中,代表ID的统一概念是:URI。URI构成了一个全局命名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。
使用URI标识所有值得标识的事物,特别是应用中提供的所有“高级”资源,无论这些资源代表单一数据项、数据项集合、虚拟亦或实际的对象还是计算结果等。
好处:
使用唯一、全局统一的命名规则的好处,既适用于浏览器中的Web应用,也适用于机对机(machine-to-machine,m2m)通信。
2、将所有事物链接在一起
含义:
任何可能的情况下,使用链接指引可以被标识的事物(资源)。
正式描述:“超媒体被当作应用状态引擎(Hypermedia as the engine of application state)”,有时简写为HATEOAS。这个描述的核心是超媒体概念,换句话说:是链接的思想
好处:
超媒体原则还有一个更重要的方面——应用“状态”。简而言之,实际上服务器端为客户端提供一组链接,使客户端能通过链接将应用从一个状态改变为另一个状态。目前,只需要记住:链接是构成动态应用的非常有效的方式.
<order self="http://example.com/customers/1234">
<amount>23</amount>
<product ref="http://example.com/products/4554">
<customer ref="http://example.com/customers/1234">
</customer>
</product>
</order>
3、使用标准方法
含义:
浏览器知道如何去处理URI的原因在于所有的资源都支持同样的接口,一套同样的方法集合。标准方法集合包含GET、POST\PUT、DELETE、HEAD和OPTIONS
为使客户端程序能与你的资源相互协作,资源应该正确地实现默认的应用协议(HTTP),也就是使用标准的GET、PUT、POST和DELETE方法。
好处:
它使你的应用成为Web的一部分——应用程序为Web变成Internet上最成功的应用所做的贡献,与它添加到Web中的资源数量成比例。采用RESTful方式,一个应用可能会向Web中添加数以百万计的客户URI
统一接口也使得所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序(generic client)就是从中受益的组件的例子,例如curl、wget、代理、缓存、HTTP服务器、网关还有Google、Yahoo!、MSN等等。
4、资源多重表述?
含义:
客户程序如何知道该怎样处理检索到的数据,比如作为GET或者POST请求的结果?原因是,HTTP采取的方式是允许数据处理和操作调用之间关系分离的。
针对不同的需求提供资源多重表述
好处:
如果你为你的资源提供HTML和XML两种表述方式,那这些资源不仅可以被你的应用所用,还可以被任意标准Web浏览器所用
5、无状态通信
含义:
REST要求状态要么被放入资源状态中,要么保存在客户端上。或者换句话说,服务器端不能保持除了单次请求之外的,任何与其通信的客户端的通信状态。
这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间
好处:
无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。
JAX-RS
Java API forRESTful WebServices旨在定义一个统一的规范,使得 Java 程序员可以使用一套固定的接口来开发 REST 应用,避免了依赖于第三方框架。是一个Java编程语言的应用程序接口,支持按照表象化状态转变 (REST)架构风格创建Web服务Web服务。
与传统的 servlet 模型相比,JAX-RS 提供了一种可行的、更为简便、移植性更好的方式来在 Java 内实现 RESTful 服务。使用注释让您能够轻松提供 Java 资源的路径位置并将 Java 方法绑定到 HTTP 请求方法。一种可移植的数据绑定架构提供了一些本机的 Java 类型支持并允许进行序列化/反序列化处理的完全定制。javax.ws.rs.core.Application 子类的扩展以及 web.xml 内的相应清单表明了用最少的部署描述符配置就能进行轻松部署。
JAX-RS 的具体实现由第三方提供,例如 Sun 的参考实现 Jersey、Apache 的 CXF 以及 JBoss 的 RESTEasy。
JAX-RS标注
JAX-RS提供了一些标注将一个资源类,一个POJO类,封装为Web资源。标注包括:
@Path,标注资源类或方法的相对路径
@GET,@PUT,@POST,@DELETE,标注方法是用的HTTP请求的类型,分别对应 4 种 HTTP 方法,用于对资源进行创建、检索、更新和删除的操作。
- 若要创建资源,应该使用 POST 方法;
- 若要检索某个资源,应该使用 GET 方法;
- 若要更改资源状态或对其进行更新,应该使用 PUT 方法;
- 若要删除某个资源,应该使用 DELETE 方法。
@Produces,标注返回的MIME媒体类型
@Consumes,标注可接受请求的MIME媒体类型
@PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam,分别标注方法的参数来自于HTTP请求的不同位置,
- @PathParam来自于URL的路径,
- @QueryParam来自于URL的查询参数,
- @HeaderParam来自于HTTP请求的头信息,
- @CookieParam来自于HTTP请求的Cookie。
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
@Path("/")
public class BookkeepingService {
......
@Path("/person/") //资源方法;若无@POST,则为子资源定位器
@POST
@Consumes("application/json")
public Response createPerson(Person person) { //JSON 格式的请求体被自动映射为实体参数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() { //数组类型的返回值被自动映射为 JSON 格式的响应体——?
......
} @Path("/person/{name}/")
@GET
@Produces("application/json")
public Person readPersonByName(@PathParam("name")
String name) {
......
}
注意:
- Subresources Locators是指一个指定了@Path annotation,但未指定HttpMethod的annotation
- 最好是在一个interface中定义这个标注,然后实现这个interface
Resource方法参数类型、返回类型
Resource 方法合法的
参数类型包括:
- 原生类型 ——在客户端如何发送原生类型?可否发送JSON类?
- 构造函数接收单个字符串参数,或者包含拥有一个static的valueOf(String)方法
- List<T>,Set<T>,SortedSet<T>(T 为以上的 2 种类型)
- 用于映射请求体的实体参数
Resource 方法合法的返回值类型包括:
- void:状态码 204 和空响应体
- Response:Response 的 status 属性指定了状态码,entity 属性映射为响应体
return Response.status(Status.OK).entity(JsonUtils.toString(result)).build();
- GenericEntity:GenericEntity 的 entity 属性映射为响应体,entity 属性为空则状态码为 204,非空则状态码为 200
- 其它类型:返回的对象实例映射为响应体,实例为空则状态码为 204,非空则状态码为 200
对于错误处理,Resource 方法可以抛出非受控异常 WebApplicationException 或者返回包含了适当的错误码集合的 Response 对象。
内容协商与数据绑定
Web 资源可以有不同的表现形式,服务端与客户端之间需要一种称为内容协商(Content Negotiation)的机制:
作为服务端,Resource 方法的@Produces 标注用于指定响应体的数据格式(MIME 类型),@Consumes 标注用于指定请求体的数据格式;
作为客户端,Accept 请求头用于选择响应体的数据格式,Content-Type 请求头用于标识请求体的数据格式。
——Produces=Accept?Consumes=Content-Type?
服务端:@Produces,@Consumes
@GET
@Path(value="/{emailAddress:.+@.+\\.[a-z]+}")
@Produces(value={"text/xml", "application/json"})
public ContactInfo getByEmailAddress(@PathParam(value="emailAddress")
String emailAddress) {
...
} @POST
@Consumes(value={"text/xml", "application/json"})
public void addContactInfo(ContactInfo contactInfo) {
...
}
客户端AngularJS:Accept,Content-Type
例如AngularJS发送请求:
$http({method: 'GET', url: '/someUrl'}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
AngularJS Setting HTTP Headers
默认的HTTP头:
The $http service will automatically add certain HTTP headers to all requests. These defaultscan be fully configured by accessing the$httpProvider.defaults.headers
configurationobject, which currently contains this default configuration:
$httpProvider.defaults.headers.common
(headers that are common for all requests):Accept: application/json, text/plain, * / *
X-Requested-With: XMLHttpRequest
$httpProvider.defaults.headers.post
: (header defaults for POST requests)Content-Type: application/json
$httpProvider.defaults.headers.put
(header defaults for PUT requests)Content-Type: application/json
如何修改HTTP头:
To add or overwrite these defaults, simply add or remove a property from these configuration objects. To add headers for an HTTP method other than POST or PUT, simply add a new objectwith the lowercased HTTP method name as the key, e.g.$httpProvider.defaults.headers.get['My-Header']='value'
.
Additionally, the defaults can be set at runtime via the $http.defaults
object in the same fashion.
e.g. 修改$httpProvider.defaults.headers
(prevent angular.js $http object from sending X-Requested-With header)
angular.module('myModule', [])
.config(['$httpProvider', function($httpProvider) {
delete $httpProvider.defaults.headers.common["X-Requested-With"]
}])
e.g. 使用$http.defaults
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'}, //headers参数可以设置Accept、Content-Type
}).success(function () {});
Requests与Responses的序列化和反序列化
服务端:实现MessageBodyWriter、MessageBodyReader
JAX-RS 依赖于 MessageBodyReader 和 MessageBodyWriter 的实现来自动完成返回值到响应体的序列化以及请求体到实体参数的反序列化工作,其中,XML 格式的请求/响应数据与 Java 对象的自动绑定依赖于 JAXB 的实现。
用户可以使用 Provider 标注来注册使用自定义的 MessageBodyProvider,如 清单 6 所示,GsonProvider 类使用了 Google Gson 作为 JSON 格式的 MessageBodyProvider 的实现。
@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;
} //MessageBodyReader.readFrom()
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;
} //MessageBodyWriter.writeTo()
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"));
} }
配置完成后,如何让它生效呢?——可以通过扩展 javax.ws.rs.core.Application 类实现
public class ContactInfoApplicaiton extends Application {
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSetSet<Class<?>>();
classes.add(ContactsResource.class);
classes.add(ContactInfoWriter.class);
classes.add(ContactInfoReader.class);
} public SetSet<Object<?>> getSingletons() {
// nothing to do, no singletons
}
}
然后配置web.xml
<web-app id="WebApp_ID" version="2.5">
<servlet>
<servlet-name>ContactInfoServlet</servlet-name>
<servlet-class>com.sample.RESTSystemServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>
com.ibm.jaxrs.sample.organization.ContactInfoApplication
</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ContactInfoServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
客户端:$httpProvider.defaults.transformRequest
/Response
AngularJS Transforming Requests and Responses
Both requests and responses can be transformed using transform functions. By default, Angularapplies these transformations:
Request transformations:
- If the
data
property of the request configuration object contains an object,serialize it intoJSON format.
Response transformations:
- If XSRF prefix is detected, strip it (see Security Considerations section below).
- If JSON response is detected, deserialize it using a JSON parser.
To globally augment or override the default transforms, modify the $httpProvider.defaults.transformRequest
and$httpProvider.defaults.transformResponse
properties. These properties are by default an array of transform functions, which allows you topush
or unshift
a new transformation function into the transformation chain. You can also decide to completely override any default transformations by assigning yourtransformation functions to these properties directly without the array wrapper.
Similarly, to locally override the request/response transforms, augment thetransformRequest
and/or transformResponse
properties of the configuration object passed into$http
.
e.g.
local配置:在发送请求时设置transformRequest:
$http({
method: 'POST',
url: url,
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
transformRequest: function(obj) {
var str = [];
for(var p in obj)
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
return str.join("&");
},
data: xsrf
}).success(function () {});
e.g. Global配置:$httpProvider.defaults.transformRequest
var module = angular.module('myApp'); module.config(function ($httpProvider) {
$httpProvider.defaults.transformRequest = function(data){
if (data === undefined) {
return data;
}
return $.param(data);
}
});
RESTEasy
RESTEasy是JBoss提供的JAX-RS 的具体实现。、
web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" >
<context-param>
<param-name>resteasy.providers</param-name>
<param-value>
org.jboss.resteasy.plugins.providers.DefaultTextPlain,
org.jboss.resteasy.plugins.providers.ByteArrayProvider,
org.jboss.resteasy.plugins.providers.InputStreamProvider,
org.jboss.resteasy.plugins.providers.ByteArrayProvider,
org.jboss.resteasy.plugins.providers.StringTextStar,
org.jboss.resteasy.plugins.providers.FormUrlEncodedProvider
</param-value>
</context-param>
<context-param>
<param-name>resteasy.scan</param-name>
<param-value>true</param-value>
</context-param>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/web</param-value>
</context-param> <listener>
<listener-class>org.jboss.resteasy.plugins.server.servlet.ResteasyBootstrap</listener-class>
</listener>
<servlet>
<servlet-name>Resteasy</servlet-name>
<servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Resteasy</servlet-name>
<url-pattern>/web/*</url-pattern>
</servlet-mapping> </web-app>
参考资料
http://liugang594.iteye.com/category/218423
http://www.infoq.com/cn/articles/rest-introduction
http://www.ibm.com/developerworks/cn/web/wa-jaxrs/ 用 Java 技术创建 RESTful Web 服务
http://www.ibm.com/developerworks/cn/java/j-lo-jaxrs/ 使用 JAX-RS 简化 REST 应用开发
http://www.ibm.com/developerworks/cn/webservices/ws-restful/ 基于 REST 的 Web 服务:基础
REST和JAX-RS相关知识介绍的更多相关文章
- PySpark SQL 相关知识介绍
title: PySpark SQL 相关知识介绍 summary: 关键词:大数据 Hadoop Hive Pig Kafka Spark PySpark SQL 集群管理器 PostgreSQL ...
- MTD NANDFLASH驱动相关知识介绍
转:http://blog.csdn.net/zhouzhuan2008/article/details/11053877 目录 MTD总概述 MTD数据结构 MTD相关层实现 MTD,Memory ...
- 流媒体相关知识介绍 及其 RTP 应用
一.流媒体简介 随着Internet的日益普及,在网络上传输的数据已经不再局限于文字和图形,而是逐渐向声音和视频等多媒体格式过渡.目前在网络上传输音频/视频(Audio/Video,简称A/V)等多媒 ...
- Web客户端语言HTML、XHTML和XML相关知识介绍
HTML简介 HTML(Hyper Text Mark-up Language)即超文本标记语言或超文本链接标示语言,是目前网络上应用最为广泛的语言,也是构成网页文档的主要语言.HTML文本是由HTM ...
- 大数据及hadoop相关知识介绍
一.大数据的基本概念 1.1什么是大数据 互联网企业是最早收集大数据的行业,最典型的代表就是Google和百度,这两个公司是做搜索引擎的,数量都非常庞大,每天都要去把互联网上的各种各样的网页信息抓取下 ...
- DBA入门相关知识介绍
DBA(database administrator):数据库管理员 DBMS(database management system):数据库管理系 ...
- jsp、Servlet相关知识介绍(转)
1.servlet生命周期 所谓生命周期,指的是servlet容器如何创建servlet实例.分配其资源.调用其方法.并销毁其实例的整个过程. 阶段一: 实例化(就是创建servlet对象,调用构造器 ...
- LEB128相关知识
LEB128相关知识 介绍 LEB128(little endian base 128)是一种变长的整数压缩编码形式,它是出自于DWARF debug file format.在Android的Dal ...
- 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸
类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...
随机推荐
- 忽然有一种感觉:云存储必须从系统级定制,所以必须对Linux相当熟悉。Windows下开发软件的模式已经过时了
看了诸多招聘帖子以后的感觉- 工作内容: .存储相关产品的设计.开发和维护. .Linux系统应用程序研发. .主流Linux内核文件系统研发. .自动化测试框架和工具的研发. 职位要求: .计算机相 ...
- SQL表名,应该用复数还是单数
用单数形式更佳,理由如下: 1.概念直观. 你有一个袋子,里面有好多个苹果,你会说这是个苹果袋.但无论里面有0,1,百万个苹果,它依然是个袋子.表也是如此,表明需要描述清楚,表里面包含的对象,而非有多 ...
- FPGA的SPI从机模块实现
一. SPI总线协议 SPI(Serial Peripheral Interface)接口,中文为串行外设接口.它只需要3根线或4根线即可完成通信工作(这里讨论4根线的情况). ...
- diff函数(matlab)
diff函数式用于求导数和差分的.无论是求导数还是差分,其原理是一样的. 这里简单介绍下其用法: 前后相邻元素之差 上下相邻行之差. 与diff(A,1,1)类似. 第三个参数为2时,则变为列差分运算 ...
- js LocalStorage
此对象主要有两个方法:保存数据:localStorage.setItem(Key, value);读取数据:localStorage.getItem(Key);Key:表示你要存入的键名称,此名称可以 ...
- .NET委托:一个关于C#的睡前故事 【转】
紧耦合 从前,在南方一块奇异的土地上,有个工人名叫彼得,他非常勤奋,对他的老板总是百依百顺.但是他的老板是个吝啬的人,从不信任别人,坚决要求随时知道彼得的工作进度,以防止他偷懒.但是彼得又不想让老板呆 ...
- Hibernate征途(二)之基础与核心
根据我司优良传统,必然要由上向下.逐级深入,所以在钻到Hibernate细节之前,先从宏观上行欣赏一下Hibernate.为什么说是欣赏?大家可以自行查阅一下Hibernate知识外的信息,创始人和H ...
- Django学习笔记(三)—— 型号 model
疯狂暑期学习 Django学习笔记(三)-- 型号 model 參考:<The Django Book> 第5章 1.setting.py 配置 DATABASES = { 'defaul ...
- Java中 map.values转换为list或者string[]
@Test public void testMap2List() throws Exception{ Map<String, String> map = new HashMap<St ...
- form表单中经常用到的禁用获取值问题
<input name="country" id="country" size=12 value="disabled提交时得不到该值 " ...