如何配置JAX-RS 2实现(RESTEasy 3)以将应用程序的状态发送到客户端?
在JSF中,我可以使用STATE_SAVING_METHOD
参数。
是否有使用JAX-RS的标准方法?
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
只是举例说明我的问题,我想配置JAX-RS提供程序将cart
变量状态返回给客户端,这样我就不会将数据保留在内存中或持久化会话状态。
@Path("/cart")
public class ShoppingCart {
// List of products presented to the user
private List<Product> availableProducts;
// Products selected by the user
private List<Product> cart;
@GET
public List<Product> addProduct() {
return availableProducts;
}
@POST
public void addProduct(Product product) {
cart.add(product);
}
}
我想添加一些支持管理应用程序状态的引用。我同意在理论上,所有服务都应该是无状态的,但实际上我发现,如果可以维护状态,特别是出于安全和生产力的原因,许多情况会更有意义。
模式似乎通常通过超链接完成,内容经过适当加密以保证数据和完整性。我现在正在研究支持这些场景的JAX-RS工具。
来自 RESTful Web服务手册的How to Manage Application State:
由于HTTP是无状态协议,因此每个请求都独立于任何请求 先前的请求。但是,交互式应用通常需要 客户遵循特定顺序的一系列步骤。这个 强制服务器临时存储每个客户端的当前位置 协议之外的那些序列。诀窍是管理国家 这样你就可以在网络之间取得平衡 性能和可扩展性。
通过超链接进行有状态的互动:每次与a的互动 资源是无国籍的;也就是说,请求消息是自包含的。 有状态的交互基于显式状态的概念 传递。存在几种交换状态的技术,例如URI 重写,cookie和隐藏的表单字段。国家可以嵌入 响应消息以指向交互的有效未来状态。 请参阅使用实体提供程序映射HTTP响应和请求实体 有关更多信息,请参阅JAX-RS概述文档中的实体和“构建URI” 信息。
答案 0 :(得分:3)
虽然lefloh提供了非常清晰的answer,但我想添加一些有助于您了解REST架构的详细信息。
REST 代表重新表示 S tate T 转移。此体系结构协议无关,但经常通过HTTP协议实现。
REST架构风格在Roy Thomas Fielding博士论文的chapter 5中定义。并且在这种架构风格中添加了以下约束:
通过应用上面定义的约束,可以引入某些架构属性,例如可见性,可移植性,可靠性,可伸缩性和网络效率。
在REST应用程序中,从客户端到服务器的每个请求都必须包含服务器要理解的所有必要信息。有了它,您不依赖于服务器上存储的任何会话上下文,也不会破坏stateless constraint:
[...]通信本质上必须是无状态的[...],这样每个从客户端到服务器的请求必须包含理解请求所需的所有信息,并且不能利用任何存储的上下文。服务器。因此,会话状态完全保留在客户端上。 [...]
例如,在访问需要身份验证的受保护资源时,每个请求都必须包含要经过适当身份验证/授权的所有必需数据。这意味着将对每个请求执行身份验证。
使用JAX-RS创建REST应用程序时,您有资源类,即使用JAX-RS注释实现相应Web资源的Java类。
资源类是至少有一个使用@Path
或请求方法指示符(@DELETE
,@GET
,@HEAD
,@OPTIONS
注释的方法的POJO, @POST
,@PUT
,使用@HttpMethod
创建的自定义注释。
根据JAX-RS specification,资源类遵循明确定义的生命周期:
3.1.1生命周期与环境
默认情况下为每个对该资源的请求创建一个新的资源类实例。首先调用构造函数,然后注入任何请求的依赖项,然后调用适当的方法,最后使对象可用于垃圾收集。 [...]
在JAX-RS中,没有这样的javax.faces.STATE_SAVING_METHOD
或类似的。没有国家。没有会话。
您的资源类可以遵循lefloh的answer中建议的伪代码。不要忘记,您始终可以在资源类中执行注入:
@Path("/cart")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
@Produces({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public class ShoppingCart {
@Inject
private ShoppingCartService service;
@GET
public Response getProducts() {
...
}
@POST
public Response addProduct(Product product) {
...
}
}
REST的一个非常重要的方面是超链接,URI,用于客户端可用于将Web服务转换为新应用程序状态的表示形式。这被称为超媒体作为应用程序状态的引擎,经常被视为 HATEOAS 。
JAX-RS 2.0引入了Link
类,它用作RFC 5988中定义的Web链接的表示。 JAX-RS Link
类添加了API支持,以便在HTTP消息中提供其他元数据。
可以将Link
序列化为HTTP响应作为额外的HTTP标头(可能提供了多个Link
标头,因此可以在单个消息中提供多个链接)。这样的HTTP标头可能如下所示:
Link: <http://example.com/api/books/1/chapter/2>; rel="prev"; title="previous chapter"
使用JAX-RS API生成Link
可以完成如下:
Response response = Response.ok()
.link("http://example.com/api/books/1/chapter/2", "prev")
.build();
Link
的实例也可以通过调用Link
API上的一个工厂方法直接创建,该方法返回Link.Builder
,可用于配置和生成新链接:< / p>
URI uri = URI.create("http://example.com/api/books/1/chapter/2");
Link link = Link.fromUri(uri).rel("prev").title("previous chapter").build();
Response response = Response.ok().link(link).build();
Link
也可以添加到您的响应实体模型中:
public class Book {
private String title;
private Link link;
// Default constructor, getters and setters ommited
}
例如,当序列化为JSON时,您将拥有类似的内容:
{
"title" : "The Lord of the Rings",
"link" : {
"rel" : "self",
"uri" : "http://example.com/api/books/1",
"title": "self"
}
}
答案 1 :(得分:2)
由于您通常在RESTful应用程序中避免使用服务器端状态,因此您无法将状态发送到客户端。你没有。通常,您通过URI标识资源并从例如数据库中获取它们。
在伪代码中,您可以这样实现:
@Path("{customerId}/cart")
public class ShoppingCart {
@GET
public List<Product> getProducts(@PathParam("customerId") long customerId) {
// check if the caller has access-rights
// fetch all products for given customerID from a database,
// and return it to the client
}
@POST
public Response addProduct(@PathParam("customerId") long customerId, Product product) {
// check if the caller has access-rights,
// save the product in the database
// and return a 201 maybe with the product as entity
}
}