Jersey入门到放弃-4
2017-04-12 00:00
204 查看
摘要: JAX-RS相关概念-资源/子资源
1. 资源类
即使用@Path标注以及至少一个方法使用@Path或使用@GET、@POST、@PUT、@DELETE等标注的普通Java类。以下示例展示如何使用Jersey构建Restful Api.
接下来分析以下上面的示例中的注解。
@Path
用于指定这是一个资源,该注解适用于类和方法,请求路径为 /helloworld, 该注解中的value是一个相对路径。该值不仅可以指定常量,还可以指定变量, 例如:
此时/users/任意value 都可以匹配到, 如果需要在方法中获取该{username}的实际值:则使用@PathParam注解在方法参数值指定,此时就可以在方法中使用了。
如果还需要指定传入的{username}符合指定的规则,我们可以使用正则表达式指定,例如只允许包含大小写字母及数字及下划线,并以大小写字母开始, 如果传入参数的不符合该规则就会回复404错误码。
另外 @Path("helloworld") 、@Path("/helloworld") 、@Path("helloworld/") 、@Path("/helloworld/") Jersey会识别为同一个api。因此加不加/没什么区别
@GET、@POST、@PUT、@DELETE等HTTP方法
这些注解用来标识该方法处理什么类型的请求, 适用于方法,一般情况对应关系如下:
还有另外一些注解如@OPTION 、@HEAD不常用,有兴趣的朋友可以自己去了解下。
@Produces
用来指定响应客户端的数据类型(json、xml、text、html等),即回复给客户端的数据类型。适用于类或方法。
doGetAsPlainText()方法指定的响应类型为text/plain,由类上的@Produce注解指定。
doGetAsHtml()方法指定的响应类型为text/html,该方法上的@Produce注解覆盖了类上的@Produce注解。
如果一个资源类支持不止一种响应类型,例如上例, 则客户端收到的响应结果是如何呢?此时由客户端所发送请求的Http header上的 Accept header 决定,
例如:Accept: text/plain时,则由doGetAsPlainText()处理。
Accept: text/plain;q=0.9, text/html,此时客户端text、html都可以接受,该如何决定呢?这是q=0.9就起作用了,代表客户端更期望text/html,则此时doGetAsHtml()被调用。
如果多个响应类型指定在同一个方法上,例如:
则此时回复什么类型呢? 与一个资源类支持不止一种响应类型”原理一致。
当客户端接受多种类型时,且具有同样的优先级【即没有指定q=0.9之类的】,则服务端可以指定优先回复某一种类型
@Comsumes
用来制定api可以接收的参数类型。适用于方法和类,可以指定接受多种类型,如下示例指定接受文本数据,一般情况下不需要指定该注解。
2.参数类型的注解
@PathParam : 获取请求url中的参数(/users/{username})
@QueryParam: 获取request中的请求参数(Get请求,/resource?username=xxx)
如果请求的参数中包含step且可以转换为int类型,则将该参数值赋予step,如果不包含step,则step等于默认值2,如果包含但不能转化为int类型,则回复404错误代码到客户端。其他参数类似。
针对上面用户自定义类型的参数ColorParam实现如下:
一般情况下方法参数的类型可以是:
基本数据类型
构造器接受String参数的类
包含接收String参数的静态方法valueOf/fromString的类
Have a registered implementation of
@MatrixParam: 从URL path segments中获取参数
@HeaderParam: 从Http请求头获取参数
@CookieParam: 从cookie中获取参数
@FormParam:获取POST请求参数
我们也可以通过以下方式获取所有的PathParam和QueryParam参数的值
针对header和cookie的所有值也可以使用如下代码
同样Post过来的所有值也可以使用如下代码
@BeanParam
提供了一种将多个请求参数组织到一个java类中的方式
如何使用该类呢?
即使在MyBeanParam中包含了要注入的参数,也可以在需要的时候单独注入,也可以注入多个bean。
关于如何接受json参数及回复json数据,将会在后续Jersey对JSON的支持一节中介绍。这个可能是很多人比较关心的一个知识点。敬请期待...。
3.子资源
在类上添加@Path注解后,我们称该类为根资源类。如果在根资源类中的方法添加该注解则称该方法为子资源。
如果添加@Path的方法没有使用类似@GET、@POST之类的注解时,则称该方法为子资源定位器,例如下面的getItemContentResource()方法。
子资源类ItemContentResource中的两个方法如何访问呢?
对于get(),访问路径为:/item/content | Get请求
对于put(), 访问路径为:/item/content/{version} | put请求
子资源类通过new的方式其生命周期不会被Jersey运行时环境所管理,如果要纳入Jersey运行时管理中,则需要按照下面的程序来创建对象:
同样也可以使用如下代码生成被Jersey运行时环境所管理的子资源类实例:
4.根资源的生命周期
默认情况下,根资源在每次请求到来时都会产生新的资源对象,其对应的注解为@RequestScoped 或不加。
@PerLookup :每个处理都会产生新的对象尽管是在同一个请求中。
@Singleton : 只会产生一个根资源对象,即单例。
5.参数注入规则
一般情况下,参数可以注入到属性,构造方法参数,根资源/子资源的方法参数,set方法【限制在@Context,领会不深,尽量少用】。
针对@Singleton注解的根资源,注入时有一些限制条件。
@ 请求的参数不能注入到根资源类的实例变量及构造器中-单例原因,因此如下代码是不允许的
使用@Singleton时,上面的 规则不适用于
以下代码示例了所有的注入可能性:
@FormParam只能用于根资源及子资源的方法上
6. @Context的使用
除了上面展示的可以使用@Context注入外,当使用servlet容器部署时,ServletConfig, ServletContext, HttpServletRequest ,HttpServletResponse 都是可以注入到资源类的。
1. 资源类
即使用@Path标注以及至少一个方法使用@Path或使用@GET、@POST、@PUT、@DELETE等标注的普通Java类。以下示例展示如何使用Jersey构建Restful Api.
package org.glassfish.jersey.examples.helloworld; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; @Path("helloworld") public class HelloWorldResource { public static final String CLICHED_MESSAGE = "Hello World!"; @GET @Produces("text/plain") public String getHello() { return CLICHED_MESSAGE; } }
接下来分析以下上面的示例中的注解。
@Path
用于指定这是一个资源,该注解适用于类和方法,请求路径为 /helloworld, 该注解中的value是一个相对路径。该值不仅可以指定常量,还可以指定变量, 例如:
@Path("/users/{username}")
此时/users/任意value 都可以匹配到, 如果需要在方法中获取该{username}的实际值:则使用@PathParam注解在方法参数值指定,此时就可以在方法中使用了。
@Path("/users/{username}") public class UserResource { @GET @Produces("text/xml") public String getUser(@PathParam("username") String userName) { } }
如果还需要指定传入的{username}符合指定的规则,我们可以使用正则表达式指定,例如只允许包含大小写字母及数字及下划线,并以大小写字母开始, 如果传入参数的不符合该规则就会回复404错误码。
@Path("users/{username: [a-zA-Z][a-zA-Z_0-9]*}")
另外 @Path("helloworld") 、@Path("/helloworld") 、@Path("helloworld/") 、@Path("/helloworld/") Jersey会识别为同一个api。因此加不加/没什么区别
@GET、@POST、@PUT、@DELETE等HTTP方法
这些注解用来标识该方法处理什么类型的请求, 适用于方法,一般情况对应关系如下:
@GET | 获取资源 |
@POST | 保存资源 |
@PUT | 修改资源 |
@DELETE | 删除资源 |
@Produces
用来指定响应客户端的数据类型(json、xml、text、html等),即回复给客户端的数据类型。适用于类或方法。
@Path("/myResource") @Produces("text/plain") public class SomeResource { @GET public String doGetAsPlainText() { } @GET @Produces("text/html") public String doGetAsHtml() { } }
doGetAsPlainText()方法指定的响应类型为text/plain,由类上的@Produce注解指定。
doGetAsHtml()方法指定的响应类型为text/html,该方法上的@Produce注解覆盖了类上的@Produce注解。
如果一个资源类支持不止一种响应类型,例如上例, 则客户端收到的响应结果是如何呢?此时由客户端所发送请求的Http header上的 Accept header 决定,
例如:Accept: text/plain时,则由doGetAsPlainText()处理。
Accept: text/plain;q=0.9, text/html,此时客户端text、html都可以接受,该如何决定呢?这是q=0.9就起作用了,代表客户端更期望text/html,则此时doGetAsHtml()被调用。
如果多个响应类型指定在同一个方法上,例如:
@GET @Produces({"application/xml", "application/json"}) public String doGetAsXmlOrJson() { }
则此时回复什么类型呢? 与一个资源类支持不止一种响应类型”原理一致。
当客户端接受多种类型时,且具有同样的优先级【即没有指定q=0.9之类的】,则服务端可以指定优先回复某一种类型
@Produces({"application/xml; qs=0.9", "application/json"})
@Comsumes
用来制定api可以接收的参数类型。适用于方法和类,可以指定接受多种类型,如下示例指定接受文本数据,一般情况下不需要指定该注解。
@POST @Consumes("text/plain") public void postClichedMessage(String message) { // Store the message }
2.参数类型的注解
@PathParam : 获取请求url中的参数(/users/{username})
@QueryParam: 获取request中的请求参数(Get请求,/resource?username=xxx)
@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) { }
如果请求的参数中包含step且可以转换为int类型,则将该参数值赋予step,如果不包含step,则step等于默认值2,如果包含但不能转化为int类型,则回复404错误代码到客户端。其他参数类似。
针对上面用户自定义类型的参数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); } } } }
一般情况下方法参数的类型可以是:
基本数据类型
构造器接受String参数的类
包含接收String参数的静态方法valueOf/fromString的类
Have a registered implementation of
javax.ws.rs.ext.ParamConverterProviderJAX-RS extension SPI that returns a
javax.ws.rs.ext.ParamConverterinstance capable of a "from string" conversion for the type. or 【这一点不是很明白,先mark吧】
List<T>,
Set<T>or
SortedSet<T>, T是上面步骤2/3的类型
@MatrixParam: 从URL path segments中获取参数
@HeaderParam: 从Http请求头获取参数
@CookieParam: 从cookie中获取参数
@FormParam:获取POST请求参数
@POST @Consumes("application/x-www-form-urlencoded") public void post(@FormParam("name") String name) { // Store the message }
我们也可以通过以下方式获取所有的PathParam和QueryParam参数的值
@GET public String get(@Context UriInfo ui) { MultivaluedMap<String, String> queryParams = ui.getQueryParameters(); MultivaluedMap<String, String> pathParams = ui.getPathParameters(); }
针对header和cookie的所有值也可以使用如下代码
@GET public String get(@Context HttpHeaders hh) { MultivaluedMap<String, String> headerParams = hh.getRequestHeaders(); Map<String, Cookie> pathParams = hh.getCookies(); }
同样Post过来的所有值也可以使用如下代码
@POST @Consumes("application/x-www-form-urlencoded") public void post(MultivaluedMap<String, String> formParams) { // Store the message }
@BeanParam
提供了一种将多个请求参数组织到一个java类中的方式
public class MyBeanParam { @PathParam("p") private String pathParam; @MatrixParam("m") @Encoded @DefaultValue("default") private String matrixParam; @HeaderParam("header") private String headerParam; private String queryParam; public MyBeanParam(@QueryParam("q") String queryParam) { this.queryParam = queryParam; } public String getPathParam() { return pathParam; } }
如何使用该类呢?
@POST public void post(@BeanParam MyBeanParam beanParam) { final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p" }
即使在MyBeanParam中包含了要注入的参数,也可以在需要的时候单独注入,也可以注入多个bean。
@POST public void post(@BeanParam MyBeanParam beanParam, @BeanParam AnotherBean anotherBean, @PathParam("p") pathParam, String entity) { // beanParam.getPathParam() == pathParam }
关于如何接受json参数及回复json数据,将会在后续Jersey对JSON的支持一节中介绍。这个可能是很多人比较关心的一个知识点。敬请期待...。
3.子资源
在类上添加@Path注解后,我们称该类为根资源类。如果在根资源类中的方法添加该注解则称该方法为子资源。
@Singleton @Path("/printers") public class PrintersResource { @GET @Produces({"application/json", "application/xml"}) public WebResourceList getMyResources() { ... } @GET @Path("/list") @Produces({"application/json", "application/xml"}) public WebResourceList getListOfPrinters() { ... } @GET @Path("/jMakiTable") @Produces("application/json") public PrinterTableModel getTable() { ... } @GET @Path("/jMakiTree") @Produces("application/json") public TreeModel getTree() { ... } @GET @Path("/ids/{printerid}") @Produces({"application/json", "application/xml"}) public Printer getPrinter(@PathParam("printerid") String printerId) { ... } @PUT @Path("/ids/{printerid}") @Consumes({"application/json", "application/xml"}) public void putPrinter(@PathParam("printerid") String printerId, Printer printer) { ... } @DELETE @Path("/ids/{printerid}") public void deletePrinter(@PathParam("printerid") String printerId) { ... } }
如果添加@Path的方法没有使用类似@GET、@POST之类的注解时,则称该方法为子资源定位器,例如下面的getItemContentResource()方法。
@Path("/item") public class ItemResource { @Context UriInfo uriInfo; @Path("content") public ItemContentResource getItemContentResource() { return new ItemContentResource(); } @GET @Produces("application/xml") public Item get() { ... } } } public class ItemContentResource { @GET public Response get() { ... } @PUT @Path("{version}") public void put(@PathParam("version") int version, @Context HttpHeaders headers, byte[] in) { ... } }
子资源类ItemContentResource中的两个方法如何访问呢?
对于get(),访问路径为:/item/content | Get请求
对于put(), 访问路径为:/item/content/{version} | put请求
子资源类通过new的方式其生命周期不会被Jersey运行时环境所管理,如果要纳入Jersey运行时管理中,则需要按照下面的程序来创建对象:
import javax.inject.Singleton; @Path("/item") public class ItemResource { @Path("content") public Class<ItemContentSingletonResource> getItemContentResource() { return ItemContentSingletonResource.class; } } @Singleton public class ItemContentSingletonResource { // this class is managed in the singleton life cycle }
同样也可以使用如下代码生成被Jersey运行时环境所管理的子资源类实例:
import org.glassfish.jersey.server.model.Resource; @Path("/item") public class ItemResource { @Path("content") public Resource getItemContentResource() { return Resource.from(ItemContentSingletonResource.class); } } @Singleton public class ItemContentSingletonResource { // this class is managed in the singleton life cycle }
4.根资源的生命周期
默认情况下,根资源在每次请求到来时都会产生新的资源对象,其对应的注解为@RequestScoped 或不加。
@PerLookup :每个处理都会产生新的对象尽管是在同一个请求中。
@Singleton : 只会产生一个根资源对象,即单例。
5.参数注入规则
一般情况下,参数可以注入到属性,构造方法参数,根资源/子资源的方法参数,set方法【限制在@Context,领会不深,尽量少用】。
@Path("{id:\\d+}") public class InjectedResource { // Injection onto field @DefaultValue("q") @QueryParam("p") private String p; // Injection onto constructor parameter public InjectedResource(@PathParam("id") int id) { ... } // Injection onto resource method parameter @GET public String get(@Context UriInfo ui) { ... } // Injection onto sub-resource resource method parameter @Path("sub-id") @GET public String get(@PathParam("sub-id") String id) { ... } // Injection onto sub-resource locator method parameter @Path("sub-id") public SubResource getSubResource(@PathParam("sub-id") String id) { ... } // Injection using bean setter method @HeaderParam("X-header") public void setHeader(String header) { ... } }
针对@Singleton注解的根资源,注入时有一些限制条件。
@ 请求的参数不能注入到根资源类的实例变量及构造器中-单例原因,因此如下代码是不允许的
Path("resource") @Singleton public static class MySingletonResource { @QueryParam("query") String param; // WRONG: initialization of application will fail as you cannot // inject request specific parameters into a singleton resource. @GET public String get() { return "query param: " + param; } }
使用@Singleton时,上面的 规则不适用于
HttpHeaders,
Request,
UriInfo,
SecurityContext
@Path("resource") @Singleton public static class MySingletonResource { @Context Request request; // this is ok: the proxy of Request will be injected into this singleton public MySingletonResource(@Context SecurityContext securityContext) { // this is ok too: the proxy of SecurityContext will be injected } @GET public String get() { return "query param: " + param; } }
以下代码示例了所有的注入可能性:
@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 System.out.println(request != null); } } public static class SubResource { @GET public String get() { return "sub resource"; } }
@FormParam只能用于根资源及子资源的方法上
6. @Context的使用
除了上面展示的可以使用@Context注入外,当使用servlet容器部署时,ServletConfig, ServletContext, HttpServletRequest ,HttpServletResponse 都是可以注入到资源类的。
相关文章推荐
- Jersey入门到放弃-3
- Jersey入门到放弃-2
- Jersey入门到放弃-1
- Jersey入门到放弃-5
- CYQ.Data V5 从入门到放弃ORM系列:教程 - Log、SysLogs两个日志类使用
- 运维工程师从入门到放弃必备书籍
- NDK开发 从入门到放弃(一:基本流程入门了解)
- 30分钟git命令入门到放弃
- React从入门到放弃(4):Redux中间件
- Python爬虫从入门到放弃(二十四)之 Scrapy登录知乎
- Python爬虫从入门到放弃(二十四)之 Scrapy登录知乎
- 翻身的废鱼——论PHP从入门到放弃需要多久?11
- Dagger2从入门到放弃再到恍然大悟
- 从入门到放弃:关于消息推送(Push)的复盘思考
- 翻身的废鱼——论PHP从入门到放弃需要多久?13
- Web前端从入门到放弃(jq选择器的归纳总结)
- RxJava2.0 从入门到放弃?
- 《Java从入门到放弃》JavaSE入门篇:数组
- Unity3D 从入门到放弃(六)-----巡逻兵
- JAX-RS之Jersey入门