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。


JavaEE教程

Java学习心得