Jersey用户指南是Jersey的官方文档,
英文原版在这:https://jersey.github.io/documentation/latest/index.html
中文翻译版在这:https://github.com/waylau/Jersey-2.x-User-Guide
一、 Root Resource Classes 根资源类
这是一个简单的根资源类
//Path注解来设置url访问路径
@Path("/hello")
public class HelloWorld {
//GET注解设置接受请求类型为GET
@GET
//Produces表明发送出去的数据类型为text/plain
//与Produces对应的是@Consumes,表示接受的数据类型为text/plain
@Produces("text/plain")
public String getString() {
return "hello jersey!";
}
}
1、首先@Path是一个URI的相对路径,文档里的原话是 “URI 的路径模版是由 URIs 和嵌入 URI 语法的变量组成,变量在运行时将会被匹配到的 URI 的那部分多代替”,简单理解就是这里Path注解的内容将决定你在浏览器将使用怎么样的链接才能访问到这个类。
例如下面的这样:
@Path("/hello/2333")
想要在浏览器中获得资源就需要输入这样的地址“http://localhost:8090/hello/2333”,如果输入之前的"http://localhost:8090/hello"浏览器就会显示找不到 localhost 的网页。
然后还有例如这样的:
@Path("/users/{username}")
这里的{username}就是一个变量的写法,例如:用户输入了名字“Galileo”,那么服务器就会响应 http://example.com/users/Galileo
。就像c语言的Printf方法一样。
为了接受到这个用户变量,@PathParam 用在接收请求的方法的参数上,例如:
@Path("/users/{username}")
public class UserResource {
@GET
@Produces("text/xml")
public String getUser(@PathParam("username") String userName) {
...
}
}
这里支持正则表达式,但是要求正则表达式精确到大小写。
一个 @Path的内容是否以"/"开头都没有区别,同样是否以"/"结尾也没有什么区别,也就是说
@Path("/hello/2333/")
@Path("/hello/2333")
@Path("hello/2333/")
@Path("hello/2333")
这四种写法是一样的。
2、@GET, @PUT, @POST, @DELETE, ... (HTTP 方法)
- HTTP GET:读取/列出/检索单个或资源集合。
- HTTP POST:新建资源。
- HTTP PUT:更新现有资源或资源集合。
- HTTP DELETE:删除资源或资源集合。
3、@Produces
@Produces是定义返回值给客户端的 MIME 媒体类型,@Produces
可以作为class注释,也可以作为方法注释,方法的@Produces
注释将会覆盖class的注释。
@Path("/myResource")
@Produces("text/plain")
public class SomeResource {
@GET
public String doGetAsPlainText() {
...
}
@GET
@Produces("text/html")
public String doGetAsHtml() {
...
}
}
这个例子中将@Produces("text/plain")作为class注释,如果方法没有@Produces那就设为类的@Produces,如滚方法有不一样的@Produces就是用方法自己的@Produces。
如果一个资源类是能够生产多个 MIME 媒体类型,资源的方法的响应将会对应对于客户端来说最可接受的媒体类型。HTTP 请求头部宣布接受什么是最容易被接受的。例如,如果接受头部是 Accept: text/plain
然后dogetasplaintext 方法会被调用。如果接受标题是Accept: text/plain;q=0.9, text/htm
,即客户可以接受 text/plain
和 text/html
,但更容易接收后者的媒体类型,然后 dogetashtml 方法会被调用。
指定多个MIME类型
指定一个MIME类型 >@Produces("application/json")
指定多个MIME类型 >@Produces({"application/json","application/xml"})
设置优先级
@GET
@Produces({"application/xml; qs=0.9", "application/json"})
public String doGetAsXmlOrJson() {
...
}
在上面的示例,如果客户端是接受application/xml
或者 application/json
,那么服务器总是发送application/json
,因为 application/xml
有一个较低的qs。
4、@Consumes
@Consumes注释是用来指定表示可由资源消耗的 MIME 媒体类型。
@POST
@Consumes("text/plain")
public void postClichedMessage(String message) {
// Store the message
}
在这个例子中,该 Java 方法将接受的参数的MIME 媒体类型应该要是 text/plain
。
二、arameter Annotations (@*Param) 参数注解
1、使用@PathParam
可以获取URI中指定规则的参数,比如:
import javax.ws.rs.*;
//Path注解来设置url访问路径
@Path("/hello/{username}")
public class HelloWorld {
//GET注解设置接受请求类型为GET
@GET
//Produces表明发送出去的数据类型为text/plain
//与Produces对应的是@Consumes,表示接受的数据类型为text/plain
@Produces("text/plain")
public String getString(@PathParam("username") String userName) {
return userName;
}
}
这样访问的URI将是一个http://localhost:8090/hello/“username”,引号的位置是需要输入的参数,如果我在浏览器中输入这样的URI:http://localhost:8090/hello/2333,
这个2333就是从URI获取的
2、@QueryParam 用于从请求 URL 的查询组件中提取查询参数。
//Path注解来设置url访问路径
@Path("/hello")
public class HelloWorld {
//GET注解设置接受请求类型为GET
@GET
//Produces表明发送出去的数据类型为text/plain
//与Produces对应的是@Consumes,表示接受的数据类型为text/plain
@Produces("text/plain")
public String getString(@QueryParam("name") String Name, @QueryParam("age") int age) {
return "name: " + Name + "\nage: " + age;
}
}
如果输入这样的URI:http://localhost:8090/hello?name=2333&age=2222,将得到这样的结果
如果需要为参数设置默认值,可以使用@DefaultValue
,如:
import javax.ws.rs.*;
//Path注解来设置url访问路径
@Path("/hello")
public class HelloWorld {
//GET注解设置接受请求类型为GET
@GET
//Produces表明发送出去的数据类型为text/plain
//与Produces对应的是@Consumes,表示接受的数据类型为text/plain
@Produces("text/plain")
public String getString(@QueryParam("name") String Name, @DefaultValue("22")@QueryParam("age") int age) {
return "name: " + Name + "\nage: " + age;
}
}
如果使用URI:http://localhost:8090/hello?name=2333,那么
这里的age就是使用的默认值,如果 @DefaultValue不与 @QueryParam联合使用,查询参数在请求中如果不存在,List、Set 或者 SortedSet 类型将会是空值集合,对象类型将为空,Java 的定义默认为原始类型。
3、FromParam
@FormParam比较特殊,因为它提取信息,先是请求所表示的MIME媒体类型为 application/x-www-form-urlencoded
,并且符合指定的 HTML 编码的形式。如:
@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
// ...
}
4、BeanParam
当请求参数很多时,比如客户端提交一个修改用户的PUT请求,请求中包含很多项用户信息。这时可以用@BeanParam
。
@POST
@Consumes("application/x-www-form-urlencoded")
public void update(@BeanParam User user) {
// Store the user data
}
User Bean定义如下:
@XmlRootElement(name = "user")
public class User {
@PathParam("userName)
private String userName;
@FormParam("name")
private String name;
@FormParam("telephone")
private String telephone;
@FormParam("email")
private String email;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
...
}
三、Sub-resources 子资源
@Path 可以用在类上,这样的类称为根资源类。也可以被用来根资源类的方法上。这类方法是被称为子资源方法(sub-resource method)
import javax.ws.rs.*;
//Path注解来设置url访问路径
@Path("/hello")
public class HelloWorld {
@GET
@Produces("text/plain")
@Path("/2333")
public String getString(@QueryParam("name") String Name, @DefaultValue("22")@QueryParam("age") int age) {
return "/2333name: " + Name + "\nage: " + age;
}
@GET
@Produces("text/plain")
public String getString1(@QueryParam("name") String Name, @DefaultValue("22")@QueryParam("age") int age) {
return "name: " + Name + "\nage: " + age;
}
}
如果请求 URL 的路径是“hello”,那么资源的方法中没有 @Path 注解的getString1将被选择。
如果请求的 URL 请求的路径是“printers/2333”,则首先在根资源类中进行匹配,然后在子资源中,相匹配的方法“2333”将被选择,在这种情况下,子资源方法是 getString。因此,在这个例子中的 URL 路径将会分层匹配进行。
四、Rules of Injection 注入规则
注入可以用在属性,构造函数参数,资源/子资源/子资源定位方法的参数和 bean setter方法。
@Path("{id:\\d+}")
public class InjectedResource {
// 注入到属性
@DefaultValue("q") @QueryParam("p")
private String p;
// 注入到构造函数参数
public InjectedResource(@PathParam("id") int id) { ... }
// 注入到资源参数
@GET
public String get(@Context UriInfo ui) { ... }
// 注入子资源方法参数
@Path("sub-id")
@GET
public String get(@PathParam("sub-id") String id) { ... }
// 注入子资源方法参数定位器方法参数
@Path("sub-id")
public SubResource getSubResource(@PathParam("sub-id") String id) { ... }
// 注入 bean setter 方法
@HeaderParam("X-header")
public void setHeader(String header) { ... }
}
当注射到一个生命周期为单域的资源类。在这种情况下,类的属性或构造函数的参数不能被注入请求特定的参数。所以,例如,以下是不允许的。
@Path("resource")
@Singleton
public static class MySingletonResource {
@QueryParam("query")
String param; //错误:不能将特定参数注入单例资源,
//会使程序初始化失败
@GET
public String get() {
return "query param: " + param;
}
}
换句话说,如果你希望一个资源实例的服务很多请求,则资源实例不能绑定到一个特定的请求参数。
存在例外,特定请求对象可以注入到构造函数或类属性。这些对象的运行时注入的代理可以同时服务多个请求。这些请求的对象是HttpHeaders, Request, UriInfo, SecurityContex。这些代理可以使用 @Context 注释进行注入。
@Path("resource")
@Singleton
public static class MySingletonResource {
@Context
Request request; // 这个是允许的:
//请求的代理将会被注入进单例
public MySingletonResource(@Context SecurityContext securityContext) {
// 这个也是允许的:
// SecurityContext的代理将会被注入进单例
}
@GET
public String get() {
return "query param: " + param;
}
}
总结,可以为以下结构注入:
Java 构造 | 描述 |
---|---|
Class fields | 将值直接注入类属性。这属性 可以是 private 但一定不能是 final 。除了上面提到的代理类型方法外,不能用在单例范围。 |
Constructor parameters | 构造函数会调用注入值。如果多个构造函数其中存在一个最可注的射参数则将被调用。除了上面提到的代理类型方法外,不能用在单例范围。 |
Resource methods | 资源的方法(带有 @GET, @POST, ...注解)包含的参数可以在执行时注射。可以在任何范围使用。 |
Sub resource locators | 子资源的方法(带有 @GET, @POST, ...注解)包含的参数可以在执行时注射。可以在任何范围使用。 |
Setter methods | 值可以被注入 setter 方法将初始化属性,而不是直接将值注入属性的。注射只能用于 @Context 注释。这意味着它不能使用,例如将查询参数注入,但可以用在请求注入。setter 方法将会在对象创建后执行,且只有一次。该方法的名称不必要有一个 setter 模式。除了上面提到的代理类型,不能在单例范围内使用。 |
下面的示例显示所有可能的值可以被注入的 Java 构建函数。
@Path("resource")
public static class SummaryOfInjectionsResource {
@QueryParam("query")
String param; // injection into a class field 注入类的属性
@GET
public String get(@QueryParam("query") String methodQueryParam) {
// injection into a resource method parameter 注入资源的方法参数
return "query param: " + param;
}
@Path("sub-resource-locator")
public Class<SubResource> subResourceLocator(@QueryParam("query") String subResourceQueryParam) {
// injection into a sub resource locator parameter注入子资源定位器参数
return SubResource.class;
}
public SummaryOfInjectionsResource(@QueryParam("query") String constructorQueryParam) {
// injection into a constructor parameter注入构造器的参数
}
@Context
public void setRequest(Request request) {
// injection into a setter method注入setter方法
System.out.println(request != null);
}
}
public static class SubResource {
@GET
public String get() {
return "sub resource";
}
}