JavaEE 7教程
RESTFul服务(2)
绑定Http方法
支持JAX-RS
HTTP 方法:
GET @GET
POST @POST
PUT @PUT
DELETE @DELETE
HEAD @HEAD
OPTIONS @OPTIONS
假设有一个html表单:
<form method="post" action="webresources/orders/create">
Order Number: <input type="text" name="id"/><br/>
Customer Name: <input type="text" name="name"/><br/>
<input type="submit" value="Create Order"/>
</form>
提交的http://localhost:8080/webresources/orders/create的资源类
@POST
@Path("create")
@Consumes("application/x-www-form-urlencoded")
public Order createOrder(@FormParam("id")int id,
@FormParam("name")String name) {
Order order = new Order();
order.setId(id);
order.setName(name);
return order;
}
下面是一个PUT标注:
@PUT
@Path("{id}")
@Consumes("*/xml")
public Order putXml(@PathParam("id")int id,
String content) {
Order order = findOrder(id);
// update order from "content"
. . .
return order;
}
@Consumes表示提交的内容体是xml。对应putXml的方法参数content。
curl -i -X PUT -d "New Order"
http://localhost:8080/store/webresources/orders/1
putXml的方法参数content将有一个值"New Order"
删除如下:
@DELETE
@Path("{id}")
public void putXml(@PathParam("id")int id) {
Order order = findOrder(id);
// delete order
}
curl -i -X DELETE http://localhost:8080/store/webresources/orders/1
多个资源表现Representations
一个RESTful 资源通过MIME类型表现来发布或消费。分别使用 @Consumes 和@Produces
@GET
@Path("{oid}")
@Produces({"application/xml", "application/json"})
public Order getOrder(@PathParam("oid")int id) { . . . }
这个将产生Order的XML or JSON输出。
@POST
@Path("{oid}")
@Consumes({"application/xml", "application/json"})
public Order getOrder(@PathParam("oid")int id) { . . . }
表示资源可以接受XML和Json输入。
绑定请求到资源
默认情况下,新的资源为每个请求访问创建一个资源。资源方法的参数,字段或bean的属性是由xxxParam注解的方式绑定,是在对象创建时添加
。除了@ PathParam和@ QueryParam,
下面说明可将请求的不同部分绑定到一个资源方法的参数,字段或bean的属性之中。
@CookieParam绑定 cookie值:
public Order getOrder(
@CookieParam("JSESSIONID")String sessionid) {
//. . .
}
@HeaderParam绑定 HTTP header值:
public Order getOrder(
@HeaderParam("Accept")String accept) {
//. . .
}
@FormParam绑定form表单参数。
@MatrixParam绑定URI中键值对。
public List<Order> getAll(
@MatrixParam("start")int from,
@MatrixParam("page")int page) {
//. . .
}
访问URI
http://localhost:8080/store/webresources/orders;
start=10;
page=20
您可以使用@ Context注解获取有关应用程序部署上下文和语境详情
@Path("orders")
publicclass OrderResource {
@Context Application app;
@Context UriInfo uri;
@Context HttpHeaders headers;
@Context Request request;
@Context SecurityContext security;
@Context Providers providers;
@GET
@Produces("application/xml")
public List<Order> getAll(@QueryParam("start")int from,@QueryParam("end")int to) {
//. . .(app.getClasses());
//. . .(uri.getPath());
//. . .(headers.getRequestHeader(HttpHeaders.ACCEPT));
//. . .(headers.getCookies());
//. . .(request.getMethod());
//. . .(security.isSecure());
//. . .
}
}
- UriInfo提供了访问应用程序和请求的URI信息。
- Application提供了访问应用程序的配置信息。
- HttpHeaders提供了访问HTTP头信息无论是作为一个Map或
方便的方法。注意,@ HeaderParam也可以用于绑定的HTTP
头一个资源方法的参数,字段或bean属性。
- Request提供了一个帮助实现请求处理,通常用于动态生成的响应。
- SecurityContext中提供了访问有关当前安全相关信息请求。
- Providers提供基于
一组搜索标准有关运行时提供者实例的查找信息。
Entity Providers实体提供者
JAX-RS定义了实体提供者提供了一种服务,用来映射表现与它们相关的Java类型。这个实体也被称为“消息有效载荷message payload” 或“ payload有效载荷”,代表一个HTTP消息的主体部分。这些被指定为资源的方法参数和方法的返回类型。
几个标准的Java类型 - 如String , byte [], javax.xml.bind.JAXBElement ,java.io.InputStream, java.io.File是预定义的类型,开发者可以自己定义类型,使用接口MessageBodyReader和MessageBodyWriter可以实现。
下面实现一个Order的阅读类型类:
@Provider
@Produces("application/json")
public class OrderReader implements MessageBodyReader<Order> {
//. . .
@Override
public void writeTo(Order o,
Class<?> type,
Type t,
Annotation[] as,
MediaType mt,
MultivaluedMap<String, Object> mm,
OutputStream out)
throws IOException, WebApplicationException {
JsonGeneratorFactory factory = Json.createGeneratorFactory();
JsonGenerator gen = factory.createGenerator(out);
gen.writeStartObject()
.write("id", o.getId())
.writeEnd();
}
}
这是一个将对象写到http响应。下面是从http响应读取到对象中:
@Provider
@Consumes("application/json")
public class OrderReader implements MessageBodyReader<Order> {
//. . .
@Override
public Order readFrom(Class<Order> type,Type t,Annotation[] as,MediaType mt,
MultivaluedMap<String, String> mm,
InputStream in)
throws IOException, WebApplicationException {
Order o = new Order();
JsonParser parser = Json.createParser(in);
while (parser.hasNext()) {
switch (parser.next()) {
case KEY_NAME:
String key = parser.getString();
parser.next();
switch (key) {
case "id":
o.setId(parser.getIntValue());
break;
default:
break;
}
break;
default:
break;
}
}
return o;
}
}
客户端API
JAX-RS2增加了一个新的客户端API可以用来访问网络资源,并提供 使用JAX-RS提供的整合。没有这个API,用户必须使用一个低级别的 Http网络连接来访问REST端点。
Client client = ClientBuilder.newClient();
Order order = client
.target("http://localhost:8080/store/webresources/orders")
.path("{oid}")
.resolveTemplate("oid", 1)
.request()
.get(Order.class);
post方法:
Order order =
client
.target(...)
.request()
.post(Entity.entity(new Order(1), "application/json"),Order.class);
删除:
client
.target("...")
.target("{oid}")
.resolveTemplate("oid", 1)
.request()
.delete();
可以通过异步获得:
Future<Order> f = client
.target("http://localhost:8080/store/webresources/orders")
.path("{oid}")
.resolveTemplate("oid", 1)
.request()
.async()
.get();
//. . .
Order o = f.get();
通过回调事件实现:
client
.target("http://localhost:8080/store/webresources/orders/{oid}")
.resolveTemplate("oid", 1)
.request()
.async()
.get(new InvocationCallback<Order>() {
@Override
public void completed(Order o) {
//. . .
}
@Override
public void failed(Throwable t) {
//. . .
}
});
映射Exception
订单抛出错误:
@Path("{id}")
public Order getOrder(@PathParam("id")int id) {
Order order = null;
if (order == null) {
throw new OrderNotFoundException(id);
}
//. . .
return order;
}
Exception映射器:
@Provider
public class OrderNotFoundExceptionMapper
implements ExceptionMapper<OrderNotFoundException> {
@Override
public Response toResponse(
OrderNotFoundException exception) {
return Response
.status(Response.Status.PRECONDITION_FAILED)
.entity("Response not found")
.build();
}
}
这可以确保客户端接收规范的格式化响应,而不是一个其他。
资源校验
如下面代码:
@Path("/names")
public class NameResource {
@NotNull
@Size(min=1)
@FormParam("firstName")
private String firstName;
@NotNull
@Size(min=1)
@FormParam("lastName")
private String lastName;
@FormParam("email")
public void setEmail(String email) {
this.email = email;
}
@Email
public String getEmail() {
return email;
}
firstName和lastName是通过注射初始化字段。这些字段不能为
空并且必须至少一个字符。
电子邮件是资源类属性,注解被指定在相应的getter方法。
过滤器和拦截器
JAX-RS2定义扩展可以在客户端和服务器端自定义请求/响应处理
。这些是用来为了延长已经
提供的功能寿命,例如日志记录,机密性和认证。两种
扩展是:过滤器和实体拦截器。 过滤器主要用于修改或处理传入和传出的请求或响应
头。实体拦截器主要关心HTTP消息体的marshaling 和 unmarshaling。