JAX-RS基本概念理解

JAX-RS,全称为Java API for RESTful Web Services.的核心概念是resource,即面向资源。

JAX-RS的JavaDoc可以在这里找到。 
JAX-RS的标准可以在这里找到。

1. Root Resource Classes
满足下列2个条件的POJO类被称为Root Resource Class:

使用@Path注解
至少有一个方法使用@Path或者资源方法注解(如@GET,@DELETE)
下面的HelloworldResource就是这样一样例子:
 

import javax.ws.rs.Path;
import javax.ws.rs.Produces;

@Path("helloworld") // 条件1
public class HelloWorldResource {
    public static final String CLICHED_MESSAGE = "Hello World!";

    @GET // 条件2
    @Produces("text/plain")
    public String getHello() {
        return CLICHED_MESSAGE;
    }
}

1.1. @Path
@Path注解的值是一个相对的URI路径。@Path的有没有/开头是一样的,同理,结尾有没有包含/也是一样的。上面例子中的/helloworld是最简单的一个例子,但是JAX-RS允许我们在路径中嵌入各种变量。

路径模板在路径中嵌入了以{}包含的变量,这个变量在运行时(资源被请求时)替换成实际的值。例如:

@Path("/users/{username}")

参数的实际值在资源方法中使用@PathParam提取:

@Path("/users/{username}")
public class UserResource{
    @GET
    @Produces("text/xml")
    public String getUser(@PathParam("username") String username){
        ...
    }
}

我们还可以对模板参数的格式做约束,例如我们只允许大小写字符以及数字,则可以使用下面的正则表达式来限制模板参数:

@Path("users/{username: [a-zA-z_0-9]*}")

如果请求路径不符合要求,将会返回404.

1.2 @GET, @PUT, @POST, @DELETE, … (HTTP Methods)
@GET, @PUT, @POST, @DELETE, @HEAD这些注解称为resource method designator,与HTTP规范中定义的方法一致。这些方法决定资源的行为。

1.3 @Produce
@Produce注解指定返回给客户端的MIME媒体类型。可以用于注解类或者注解方法。

@Path("/myResource")
@Produces("text/plain")
public class SomeResource {
    @GET
    public String doGetAsPlainText() {
        ...
    }

    @GET
    @Produces("text/html")
    public String doGetAsHtml() {
        ...
    }
}

如果类中的方法没有指定,则默认使用类级别的@Produce值。@Produce注解可以指定多个值,同时可以指定quality factor:

@GET
@Produces({"application/xml; qs=0.9", "application/json"})
public String doGetAsXmlOrJson() {
    ...
}

@Consumes
该注解用于指定可以接受的客户端请求的MIME媒体类型:

@POST
@Consumes("text/plain")
public void postClichedMessage(String message) {
    // Store the message
}


注意上述方法返回void,表示没有内容,此时给客户端返回204(No Content)

2. 参数注解(@*Param)
参数注解用于从请求中提取参数,例如上面的@PathParam用于提取路径中的参数。

2.1 @QueryParam
@QueryParam注解用于提取查询参数:

@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) {
    ...
}



如果请求参数无法被正确地转化为相应的类型,返回404. 参数类型可以自定义:

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



对这个类的约束就是要有一个接收字符串的构造函数。如果没有@DefaultValue注解,并且请求中未包含该参数,则方法的参数为各类型的“空值”。

2.2 @MatrixParam
从url片段中提取参数,即url中冒号后面的参数。

2.3 @HeaderParam
从请求的头部提取Header。

2.4 @CookieParam
提取cookie。

2.5 @FormParam
用于提取请求中媒体类型为”application/x-www-form-urlencoded” 的参数,根据相应的表单类型提取其中的参数。

@POST
@Consumes("application/x-www-form-urlencoded")
public void post(@FormParam("name") String name) {
    // Store the message
}

2.6 @BeanParam
该注解用于从请求的各部分中提取参数,并注入到对应的Bean中,例如我们有如下定义的Bean:

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;
    }
    ...
}


这个Bean的各个属性都是使用前面的参数注解注解的,然后我们可以在resource class类的方法中使用这个类:

@POST
public void post(@BeanParam MyBeanParam beanParam, String entity) {
    final String pathParam = beanParam.getPathParam(); // contains injected path parameter "p"
    ...
}

当接到请求时,RS实现将从查询参数、头部、Cookie等各处提取参数,并注入到beanParam的各个属性中。

可以组合使用多种参数注解:

@POST
public void post(@BeanParam MyBeanParam beanParam, @BeanParam AnotherBean anotherBean, @PathParam("p") pathParam,
String entity) {
    // beanParam.getPathParam() == pathParam
    ...
}

3. 子资源(Sub-resources)
sub-resources的概念类似于Spring MVC框架中Controller的二级映射,及类级别上有一个@RequestMapping,方法上也有一个二级的@RequestMapping。 @Path注解可以用在类上,表示根资源(root resource),也可以用在类的方法上,这里的方法就叫sub-resource method,对应的资源叫sub-resource。

@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) { ... }
}

此例中,如果url为printers,则对应到getMyResources方法,其他二级url分别对应各方法。

@Path的另一种使用场景是用来表示资源嵌套,此时@Path不与@GET之类的HTTP方法注解一起使用,例如:

@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) {
        ...
    }
}
这里的@Path(“content”)没有指定方法注解,因此如果URL为/item/content,此时会继续往上递归,找到ItemContentResource这个资源类,然后针对该类使用URL匹配规则,所以/item/content将映射ItemContentResource的get方法,’/item/content/1.0’将映射到相应的put方法。 
这里的getItemContentResource()方法因此也叫子资源定位器(sub-resource locator)

单例资源
正常情况下,资源的scope都是针对每个请求的,也就是说每个请求都会创建不同的资源实例,如果想要每个请求都返回一样的资源,此时需要使用单例注解@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
}

4. Root Resource Classes的生命周期
root resource默认的生命周期是请求范围的,也就是器生命周期在一个请求内有效。另外Jersey支持两种不同生命周期:

Scope    注解    类全称    说明
Request    @RequestScoped或者空    org.glassfish.jersey.process.internal.RequestScoped    默认的生命周期
Per-lookup    @PerLookup    org.glassfish.hk2.api.PerLookup    
Singleton    @Singleton    javax.inject.Singleton    一个JAX-RS应用只有一个实例,可以在类上使用@Singleton注解或者使用Application注册
5. 注入规则(Rules of Injection)
正常情况下,可以将请求的各种值注入到参数注解注解的对象,例如属性,方法参数,构造函数等。但是有一些特别的注入规则,会根据注入资源的生命周期有所不同,例如有些参数无法注入单例资源:

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

事实上,所以跟某个特定请求相关的参数,都不能被注入到单例资源中,这些规则的验证会在应用启动的时候进行。

一些特殊的对象可以被注入到单例的构造函数或者属性中,此时RS运行时会注入对应的代理类,要使用这些特殊的注入,需要使用@Context注解:

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

总结一下注入类型,有:

Class fields: 注入类的域中
构造函数:注入的值将用于调用构造函数
Resource Method:资源的各方法中注入
sub resource locator:不带方法注解的@Path
setter方法:只能使用@Context注解
下面是一个综合的例子:

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

6. @Context的使用
Context注解一般用于获取request或者response相关的上下文,例如UriInfo。对于那些Java类型可以使用@Context注解,请看参考JAX-RS规范第5章。

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以按照以下步骤将JAX-WS接口替换为JAX-RS接口: 1. 创建JAX-RS接口:创建一个新的Java接口来定义您的JAX-RS服务。在接口上使用`@Path`注解指定资源的URL路径。 ```java import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; @Path("/your-resource") public interface YourResource { @GET @Produces(MediaType.APPLICATION_JSON) String getResource(); } ``` 2. 实现JAX-RS接口:创建一个类来实现您的JAX-RS接口,并实现接口中定义的方法。 ```java public class YourResourceImpl implements YourResource { @Override public String getResource() { // 实现您的业务逻辑 return "Hello JAX-RS!"; } } ``` 3. 注册JAX-RS服务:将您的JAX-RS服务注册到应用程序中。这可以通过创建一个`javax.ws.rs.core.Application`子类并在其中注册资源类来完成。 ```java import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; import java.util.HashSet; import java.util.Set; @ApplicationPath("/api") public class YourApplication extends Application { @Override public Set<Class<?>> getClasses() { Set<Class<?>> classes = new HashSet<>(); classes.add(YourResourceImpl.class); return classes; } } ``` 4. 配置JAX-RS:根据您使用的应用程序服务器,将JAX-RS的实现(如Jersey或RestEasy)添加到您的应用程序的构建配置文件中。您还需要确保在应用程序服务器上正确配置JAX-RS。 5. 测试JAX-RS接口:启动您的应用程序服务器,并使用JAX-RS客户端或浏览器等工具测试您的JAX-RS接口。 请注意,以上步骤是一般的指导,具体步骤可能因您使用的框架和工具而有所不同。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值