注解
描述
@Path
@Path注解的值是一个相对的URI路径,这个路径指定了该Java类的位置,例如/helloworld。在这个URI中可以包含变量,例如可以获取用户的姓名然后作为参数传入URI中:/helloworld/{username}。
@GET
@GET注解是请求方法指示符,这个指示符注解的Java方法会处理HTTPGET请求。资源的行为由资源回应的HTTP方法决定。@POST
@POST注解是请求方法指示符,这个指示符注解的Java方法会处理HTTPPOST请求。资源的行为由资源回应的HTTP方法决定。@PUT
@PUT注解是请求方法指示符,这个指示符注解的Java方法会处理HTTPPUT请求。资源的行为由资源回应的HTTP方法决定。@DELETE
@DELETE注解是请求方法指示符,这个指示符注解的Java方法会处理HTTPDELETE请求。资源的行为由资源回应的HTTP方法决定。@HEAD
@HEAD注解是请求方法指示符,这个指示符注解的Java方法会处理HTTPHEAD请求。资源的行为由资源回应的HTTP方法决定。@PathParam
@PathParam注解是可以抽取并用在资源类中的一类参数。URIpath参数是从请求的URI中抽取的,而且参数的名称和@Path注解中定义的变量名对应。@QueryParam
@QueryParam注解是可以抽取并在资源类中使用的一类参数。Query参数是从请求URI的查询参数中抽取的。@Consumes
@Consumes注解是用来指定资源能够接受的客户发送的MIME媒体类型。@Produces
@Produces注解用来指定资源能够生成并发送给客户端的MIME媒体类型,例如“text/plain”.@Provider
@Provider注解用在任何对JAX-RS运行时(如MessageBodyReader和MessageBodyWriter)有意义的事物上。对HTTP请求,MessageBodyReader用来将HTTP请求实体段映射为方法参数。在响应的时候,返回的值使用MessageBodyWriter来映射成HTTP响应实体段。如果应用程序需要提供其他的元数据,如HTTP头或不同的状态代码,方法可以返回一个打包了实体的Response,该Response可以使用Response.ResponseBuilder创建。 JAX-RS应用程序概况 下面的代码例子是一个非常简单的根资源类,使用了JAX-RS注解: package com.sun.jersey.samples.helloworld.resources; import javax.ws.rs.GET; import javax.ws.rs.Produces; import javax.ws.rs.Path; // The Java class will be hosted at the URI path "/helloworld" @Path("/helloworld") public class HelloWorldResource { // The Java method will process HTTP GET requests @GET // The Java method will produce content identified by the MIME Media // type "text/plain" @Produces("text/plain") public String getClichedMessage() { // Return some cliched textual content return "Hello World"; } } 复制代码 随后的几节中我们会详细描述这个例子中使用的注解。 @Path注解的值是一个相对的URI路径。在上面的例子中,这个Java类会放在/helloworld这个路径下。上面的例子中使用的是静态的URI路径,是最简单的例子。在URI中,我们可以包含变量,对于这样的包含变量的URI我们称为URI路径模板。 @GET注解是一个请求方法指示符。在上面的例子中,被注解的Java方法会处理HTTP GET请求。 @Produces注解用来指定资源能够生产和发送回客户端的MIME媒体类型。在上面的例子中,Java方法会生成MIME媒体类型“text/plain”。 @Consumes注解用来指定资源能够消费的客户端发送的MIME媒体类型。我们可以将上面的例子中的代码修改为 @POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message } 复制代码 @Path注解和URI路径模板 @Path注解指定了URI资源会响应的路径模板,是指定在资源的类级别或方法级别上。@Path注解的值是一个相对URI路径模板,这个路径是相对于资源发布的服务器的基础URI路径、应用程序的上下文根路径和JAX-RS运行时响应的URL。URI路径模板是包含变量的URI。这些变量在运行时会被取代,这样资源就能够根据被取代的URI来响应请求。变量是用花括号{}表示的,例如下面的例子 @Path annotation: @Path("/users/{username}") 复制代码 在这个例子中,用户会被提示输入自己的名字,然后一个被配置来响应这个URI路径模板的JAX-RS web service会响应该请求。例如,如果用户输入的名字是Galileo,这个web service会响应下面的URL http://example.com/users/Galileo. 要获取用户的名字,可以在请求方法的参数中使用@PathParam注解,如下面的代码所示: @Path("/users/{username}") public class UserResource { @GET @Produces("text/xml") public String getUser(@PathParam("username") String userName) { ... } } 复制代码 缺省的,URI变量必须符合正则表达式“[^/]+?”。开发人员也可以通过在变量名称后指定不同的正则表达式来指定客户化的变量模式。例如,如果用户名字必须是由大写或小写字母组成,可以在变量的定义中指定: @Path("users/{username: [a-zA-Z][a-zA-Z_0-9]}") 复制代码 在这个例子中,username这个变量只能匹配由大写或小写字母开头,后跟0个或多个字母、数字和下划线的用户名。如果用户名不匹配这个模板,那么一个404(Not Found)响应会被发送给客户端。 @Path的值并不要求必须以/开始。无论是否以/开头或者开头是否有空格,JAX-RS运行时会一样的解析。 一个URI路径模板可以包含一个或多个变量名,每个变量名都以前花括号{开始,以后花括号}结束。在上面的例子中,变量名是username。在运行时,被配置为响应上面的URI路径模板的资源会处理URI数据,将URI中对应{username}的部分作为username的变量数据。 例如,如果你想要发布一个资源来响应URI路径模板 http://example.com/myContextRoot/resources/ {name1}/{name2}/,你需要将应用程序发布在一个Java EE服务器上,该服务器要响应对URI http://example.com/myContextRoot 的请求,并使用如下的@Path注解来修饰你的资源: @Path annotation: @Path("/{name1}/{name2}/") public class SomeResource { ... } 复制代码 在这个例子中,在web.xml文件中指定的JAX-RS辅助servlet的URLpattern是: <servlet-mapping> <servlet-name>My JAX-RS Resource</servlet-name> <url-pattern>/resources/*</url-pattern> </servlet-mapping> 复制代码 在URI路径模板中,一个变量名可以被使用多次。 如果变量的值中的字符和URI的保留字符冲突,那么该冲突的字符应该使用百分号编码代替。例如,变量值中的空格应该是一 代替。 下表中列出了一些URI路径模板的例子以及这些URI中的变量被替换后的结果,例子中使用保额变量名和值如下: name1: james name2: gatz name3: location: Main Street question: why 注意:names的值是空字符串“”。URI路径模板
替换后的URI
http://example.com/{name1}/{name2}/ http://example.com/james/gatz/http://example.com/{question}/{question}/{question}/
http://example.com/why/why/why/
http://example.com/maps/{location}
http://example.com/maps/Main Street
http://example.com/{name3}/home/ http://example.com//home 对HTTP资源的响应 资源的行为是由资源响应的HTTP方法(GET,POST,PUT,DELETE)来决定的。 请求方法指示符注解 请求方法指示符注解是由JAX-RS定义的运行时注解,对应同名的HTTP方法。在一个资源类文件中,HTTP方法通过使用请求方法指示符注解映射到Java编程语言的方法。一个资源的行为是由其要响应的HTTP方法决定的。JAX-RS为普通的HTTP方法定义了@GET,@POST,@PUT,@DELETE和@HEAD注解。开发人员也肯创建自己的客户化的请求方法指示符。创建客户化的请求方法指示符不在本教程的范围内。 下面的例子是从storage service例子程序中抽取的,显示了怎样使用PUT方法来创建或更新storage容器: @PUT public Response putContainer() { System.out.println("PUT CONTAINER " + container); URI uri = uriInfo.getAbsolutePath(); Container c = new Container(container, uri.toString()); Response r; if (!MemoryStore.MS.hasContainer(c)) { r = Response.created(uri).build(); } else { r = Response.noContent().build(); } MemoryStore.MS.createContainer(c); return r; } 复制代码 缺省的,如果没有显示的实现对应的方法,JAX-RS运行时会自动的支持HEAD方法和OPTIONS方法。对HEAD方法,运行时会调用实现了的GET方法并忽略response实体。对OPTIONS,响应头Allow会被设置到资源支持的一组HTTP方法。另外,JAX-RS运行时会返回一个Web应用程序定义语言(WADL)文档来描述资源。更多的信息见 https://wadl.dev.java.net/ 。 由请求方法指示符修饰的方法必须返回void、Java编程语言的类型或javax.ws.rs.core.Response对象。可以使用PathParam或QueryParam注解来从URI中抽取多个参数,详细描述见第246页的“抽取request参数”。Java类型和实体段之间的转换是实体提供者(如MessageBodyReader和MessageBodyWriter)的责任。 想要在response中提供额外的元数据方法应该返回一个Response类的实例。ResponseBuilder类使用builder模式提供了一个创建Response实例的简便的方法。HTTP PUT和POST方法期望有HTTP request体,因此应该对响应PUT和POST请求的方法使用MessageBodyReader。 @PUT和@POST都能够被使用来创建和更新资源。POST可以表示任何事情,因此在使用POST时,由应用程序来定义其语义。PUT有定义好的语义。当使用PUT来创建的时候,客户声明了新创建的资源的URI。 PUT有很明确的语义来创建和更新一个资源。客户发送的表述必须是使用GET收到的同样的表述,只是给出不同的媒体类型。PUT不允许一个资源被部分更新,这是使用PUT方法时的一个很常见的错误。一个通用的应用程序模式是使用POST类创建资源并返回一个201响应,将新创建的资源的URI的值设置为location头。这种模式下,web service声明了新创建的资源的URI。 使用实体提供者来映射HTTP Response和Request实体段 实体提供者提供了在表述和相关的Java类型之间的映射服务。两种类型的实体提供者是MessageBodyReader和MessageBodyWriter。对于HTTP request,MessageBodyReader被用来将HTTP request实体段映射为方法参数。在response方面,使用MessageBodyWriter来将返回值映射为HTTP response实体段。如果应用程序需要提供附加的元数据,例如HTTP头或不同的状态码,方法可以返回一个包装了这些实体的Response实例,该实例可以用Response.ResponseBuilder创建。 下表显示了自动支持的标准的类型,只有当不使用这些标准类型的时候才需要编写实体提供者。Java类型
支持的媒体类型
byte[]
所有的媒体类型(*/*)
java.lang.String
所有的文本媒体类型(text/*)
java.io.InputStream
所有的媒体类型(*/*)
java.io.Reader
所有的媒体类型(*/*)
java.io.File
所有的媒体类型(*/*)
javax.activation.DataSource
所有的媒体类型(*/*)
javax.xml.transform.Source
XML媒体类型(text/xml,application/xml和application/*+xml)
javax.xml.bind.JAXBElement和应用程序提供的JAXB类
XML媒体类型(text/xml,application/xml和application/*+xml)
MultivaluedMap<String,String>
表单内容(application/x-www-form-urlencoder)
StreamingOutPut
所有的媒体类型(*/*),只对MessageBodyWriter有效
下面的例子显示了怎样与@Consumes和@Provider注解一起使用MessageBodyReader: @Consumes("application/x-www-form-urlencoded") @Provider public class FormReader implements MessageBodyReader<NameValuePair> { 复制代码 下面的例子显示了怎样与@Produces和@Provider注解一起使用MessageBodyWriter: @Produces("text/html") @Provider public class FormWriter implements MessageBodyWriter<Hashtable<String, String>> { 复制代码 下面的例子显示了怎样使用ResponseBuilder: @GET public Response getItem() { System.out.println("GET ITEM " + container + " " + item); Item i = MemoryStore.MS.getItem(container, item); if (i == null) throw new NotFoundException("Item not found"); Date lastModified = i.getLastModified().getTime(); EntityTag et = new EntityTag(i.getDigest()); ResponseBuilder rb = request.evaluatePreconditions(lastModified, et); if (rb != null) return rb.build(); byte[] b = MemoryStore.MS.getItemData(container, item); return Response.ok(b, i.getMimeType()). lastModified(lastModified).tag(et).build(); } 复制代码 使用@Consumes和@Produces来客户化Request和Response 发送给资源的信息和传回客户端的信息都被指定了MIME媒体类型,是在HTTP request或response的头中指定的。可以使用下面的注解来指定资源能够响应或生产的MIME媒体类型: javax.ws.rs.Consumes javax.ws.rs.Produces 复制代码 默认的,一个资源能够响应和生产所有的MIMIE媒体类型。 @Produces注解 注解@Produces是用来指定一个资源能够产生并发送回客户端的MIME媒体类型或表现。如果@Produces是应用在类级别上,那么默认的资源的所有的方法都能够生产指定的MIME类型。如果是应用在方法级别上,那么这个注解会覆盖应用在类级别的@Produces注解。如果资源中没有方法能够生产客户端请求的MIME类型,那么JAX-RS运行时会发送回一个HTTP的“406 Not Acceptable”错误。 注解@Produces的值是一个MIME类型的字符串数组,例如 @Produces({"image/jpeg,image/png"}) 复制代码 下面的例子显示了怎样在类级别和方法级别应用@Produces注解: @Path("/myResource") @Produces("text/plain") public class SomeResource { @GET public String doGetAsPlainText() { ... } @GET @Produces("text/html") public String doGetAsHtml() { ... } } 复制代码 方法doGetAsPlainText()默认使用的是类级别上定义的@Produces注解指定的MIME媒体类型。方法doGetAsHtml上的@Produces注解覆盖了类级别的设置,因此该方法能够生成的是HTML类型,而不是普通文本。 如果一个资源类能够生产超过一种MIME媒体类型,那么资源方法的选择就对应最能够接受的客户端声明的媒体类型。具体来说,HTTP请求的Accept头属性中声明了最可接受的MIME类型。例如,如果Accept头的值是Accept:text/plain,那么方法doGetAsPlainText会被调用。如果Accept头的值是Accept:text/plain;q=0.9,text/html,这声明了客户端能够接受媒体类型text/plain和test/html,但是更喜欢后者,因此doGetAsHtml方法会被调用。 一个@Produces注解中可以声明多个媒体类型。下面的代码例子显示了怎样做到这点: @Produces({"application/xml", "application/json"}) public String doGetAsXmlOrJson() { ... } 复制代码 当可接受的媒体类型是application/xml或application/json的时候这个doGetAsXmlOrJson方法会被调用。如果两个媒体类型是同样可接受的,那么会选择声明在前面的一个。 上面的例子中,为了更明白,我们使用的是明确的MIME媒体类型。也可以使用相应的常量值,这样可以减少拼写错误。相关的信息见MediaType类的常量字段,位于 https://jsr311.dev.java.net/nonav/releases/1.0/javax/ws/rs/core/MediaType.html 。 @Consumes注解 注解@Consumes被用来指定资源能够接受或消费的来自客户端的MIME媒体类型。如果@Consumes是应用在类级别上的,该类的所有的响应方法默认的接受指定的MIME类型。如果是应用在方法级别上,那么方法级别上的@Consumes注解会覆盖应用在类级别上的@Consumes注解。 如果资源不能够消费客户请求中的MIME类型,JAX-RS运行时会发送回一个HTTP 415 (“Unsupported Media Type”)错误。 @Consumes注解的值是一个可接受的MIME类型的字符串数组。例如: @Consumes({"text/plain,text/html"}) 复制代码 下面的例子显示了怎样在类级别和方法级别上使用@Consumes注解。 @Path("/myResource") @Consumes("multipart/related") public class SomeResource { @POST public String doPost(MimeMultipart mimeMultipartData) { ... } @POST @Consumes("application/x-www-form-urlencoded") public String doPost2(FormURLEncodedProperties formData) { ... } } 复制代码 方法doPost默认的接受类级别的@Consumes注解指定的MIME类型。方法doPost2的@Consumes注解覆盖了类级别的@Consumes注解,因此doPost2方法可接受的MIME类型是application/x-www-form-urencoded。 如果没有任何的资源方法能够响应请求中的MIME类型,那么一个HTTP 415错误会被返回给客户端。 本节中前面讨论的HelloWorld例子中,我们可以使用@Consume注解,如同我们下面的代码所做的 @POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message } 复制代码 在这个例子中,这个方法会消费由MIME媒体类型text/plain指定的表现。注意这里资源的方法返回的是void,这意味着没有任何表现被返回,因此一个状态码为HTTP 204(“No Content”)的响应会被返回。 提取请求参数 资源方法的参数可能被添加了基于参数的注解来从请求中提取信息。在以前的例子中我们展现了时候@PathParam参数来从匹配@Path中声明的路径的request的URL中提取路径参数。 可以在资源类中提取下面类型的参数: QueryURI PathFormCookieHeaderMatrix Query参数是从请求URI的查询参数中抽取的,在方法参数中使用javax.ws.rs.QueryParam注解来指定。下面的代码例子来自sparklines例子程序,演示了怎样使用@QueryParam注解来从请求URL中抽取query参数: @Path("smooth") @GET public Response smooth( @DefaultValue("2") @QueryParam("step") int step, @DefaultValue("true") @QueryParam("min-m") boolean hasMin, @DefaultValue("true") @QueryParam("max-m") boolean hasMax, @DefaultValue("true") @QueryParam("last-m") boolean hasLast, @DefaultValue("blue") @QueryParam("min-color") ColorParam minColor, @DefaultValue("green") @QueryParam("max-color") ColorParam maxColor, @DefaultValue("red") @QueryParam("last-color") ColorParam lastColor ) { ... } 复制代码 如果query参数step在请求URI的查询部分中存在,那么将从URI中抽取step的值并将其解析为32位的有符号整数并赋值给方法参数step。如果在请求URI的查询部分中不存在step参数,那么@DefaultValue注解所声明的缺省值2将被赋给方法参数step。如果step参数在请求URI中存在,但是无法被解析为32位的符号整数,那么一个HTTP 400(“Client Error”)响应将会被返回。 用户自定义的Java编程语言类型也可以被用来作为query参数。下面的代码例子是上面的例子中使用的ColorParam类。 public class ColorParam extends Color { public ColorParam(String s) { super(getRGB(s)); } private static int getRGB(String s) { if (s.charAt(0) == ’#’) { try { Color c = Color.decode("0x" + s.substring(1)); return c.getRGB(); } catch (NumberFormatException e) { throw new WebApplicationException(400); } } else { try { Field f = Color.class.getField(s); return ((Color)f.get(null)).getRGB(); } catch (Exception e) { throw new WebApplicationException(400); } } } } 复制代码 类ColorParam的构造方法接受一个String作为参数。 @QueryParam和@PathParam都只能被应用到以下的Java类型: 除char之外的原始类型除Character之外的原始类型封装类有接受单独的字符串做参数的构造函数的类包含名为valueOf(String)的静态方法的类List<T>,Set<T>,SortedSet<T>,这里T是上面所列的类型之一。有时候,同一个名字的参数可能包含多个值,在这种情况下,使用这些类型可以获取所有的值 如果@DefaultValue没有被使用,在请求中又没有找到相应的query参数,那么对List,Set和SortedSet类型的参数其值是空的collection,对其他的对象类型值为null,对原始类型则是各自的默认值。 URI路径参数是从request的URI中提取的,参数的名字对应类级别的@Path注解指定的URI路径模板中的变量名。在方法参数中使用javax.ws.rs.PathParam注解来指定URI路径参数。下面的例子显示了怎样使用@Path注解和在方法中使用@Path注解: @Path("/{username}") public class MyResourceBean { ... @GET public String printUsername(@PathParam("username") String userId) { ... } } 复制代码 在这个例子中,URI路径模板的变量名为username,该变量被指定为printUserName方法的参数。@PathParam注解的值被设置为变量名username。在运行的时候,printUserName被调用之前,username的值被从URI中提取出来并转换成字符串。转换的结果对printUserName方法生效并作为userId变量。 如果路径模板的变量无法被转换成指定的类型,JAX-RS运行时会返回一个HTTP 400(“Bad Request”)错误给客户端。如果@PathParam注解不能转换成指定的类型,JAX-RS运行时会返回一个HTTP 404(“Not Found”)错误给客户端。 @PathParam参数和其他的基于参数的注解(@MatrixParam,@HeaderParam,@CookieParam和@FormParam)遵守和@Query相同的规则。 Cookie参数是使用javax.ws.rs.CookieParam注解的参数,这种参数会从cookie相关的HTTP头声明的cookie中提取信息。Header参数是使用javax.ws.rs.HeaderParam注解的参数,这种参数从HTTP头中提取信息。Matrix参数是使用javax.ws.rs.MatrixParam的参数,这种参数会从URL路径段中提取信息。Form参数是使用javax.ws.rs.FormParam的参数,这种参数从MIME类型是application/x-www-form-urlencoded的请求表现中提取信息并遵从HTML表单指定的编码,如同 http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1 描述的一样。这种类型的参数对从以POST方式发送的HTML表单中提取信息很有用。 下面的例子中我们从POST的表单数据中提取name参数: @POST @Consumes("application/x-www-form-urlencoded") public void post(@FormParam("name") String name) { // Store the message } 复制代码 要获得所有的query或path参数的参数名称和值的Map,使用如下的代码: @GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); } 复制代码 下面的方法获得header参数和cookie参数的名称和值的Map: @GET public String get(@Context HttpHeaders hh) { MultivaluedMap<String, String> headerParams = ui.getRequestHeaders(); Map<String, Cookie> pathParams = ui.getCookies(); } 复制代码 通常,@Context被用来获取和request或response相关的上下文的Java类型。 对form参数,我们可以进行以下的操作: @POST @Consumes("application/x-www-form-urlencoded") public void post(MultivaluedMap<String, String> formParams) { // Store the message }