Jersey入门到放弃-4

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删除资源

还有另外一些注解如@OPTION 、@HEAD不常用,有兴趣的朋友可以自己去了解下。

@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);
            }
        }
    }
}

一般情况下方法参数的类型可以是:

  1. 基本数据类型
  2. 构造器接受String参数的类
  3. 包含接收String参数的静态方法valueOf/fromString的类
  4. Have a registered implementation of javax.ws.rs.ext.ParamConverterProvider JAX-RS extension SPI that returns a javax.ws.rs.ext.ParamConverter instance capable of a "from string" conversion for the type. or 【这一点不是很明白,先mark吧】
  5.  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, HttpServletRequestHttpServletResponse 都是可以注入到资源类的。

 

转载于:https://my.oschina.net/javastorm/blog/877451

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值