Rest API By JAX-RS 实现接口发布
2017-09-11 13:15
901 查看
原文地址:http://www.cnblogs.com/oopsguy/p/7503589.html
由于 JAX-RS 是一个 API 规范,您需要选择一个实现,在本示例中,我们将使用 Jersey 作为实现。虽然可以创建一个没有直接依赖于特定 JAX-RS 实现的 JAX-RS 应用程序,但这将使得示例更加啰嗦。
我选择 Jersey 有几个原因,主要是因为我可以不用绕圈子就可以轻松地获得简单的依赖注入,毕竟我们是把它在和 Spring 做对比。Apache Shiro 有一个示例,可在 Jersey、RestEasy 和 Apache CXF 上运行相同的代码,如果你感兴趣不妨看一看。
此示例与 Spring Boot 不同之处在于,它打包成 WAR,而 Spring Boot 是单个 JAR。此示例也可以打包进可执行的 jar 中,但此内容不在本文范围之内。
在 JAX-RS 中与
另外要指出的是,在上面的类中,
JAX-RS 资源实现看起来非常类似于上述的 Spring 版本(重命名为
我们先来分解以下片段:
类似于上面的 Spring 示例,类级别上的
与 Spring 示例不同,其中
我们看到
发出与上述相同的两个请求,我们可以发出
或者
现在我们已经看到了基本相同的代码在 Spring 和 JAX-RS 应用程序中运行,只需更改注解即可。我更喜欢 JAX-RS 的注解,他们更简洁。既然如此,为什么要在两者选择呢?Jersey 和 RestEasy 都支持 Spring(以及 Guice 和 CDI/Weld)。让我们来创建一个结合了这两者的第三个例子。
我们的
该类与之前的示例有点类似。首先,您可能注意到了用于标记此类由 Spring 管理的 `@Configuration 注解。剩下的就是指示 Jersey 再次扫描资源包,其余的都是您的处理逻辑。
进入
如果你已经是一个 Spring 用户,就使用 Spring 吧。如果你正在创建一个对象 JSON/XML REST 层,那么您选择的 DI 框架(如 Spring、Guice 等)支持 JAX-RS 资源可能是一个不错的选择。服务器端渲染页面并不是 JAX-RS 规范的一部分(虽然它是扩展支持的)。我曾在 Jersey 中使用了 Thymeleaf 视图,但我认这是 Spring MVC 该做的。
目前为止,我们还没有把 Spring Boot 应用程序与 WAR 打包的应用程序进行详细地对比。Dropwizard(使用嵌入式 Jetty 容器和 Jersey)可能是与 Spring Boot 应用程序最接近的。希望这篇文章能给你带来一些灵感,您可以做自己的对比。如果您有任何问题,欢迎 Twitter @briandemers!
JAX-RS
我们在 JAX-RS 示例中使用相同的模型和 DAO,我们所需要做的只有更改StormtroooperController类的注解。
由于 JAX-RS 是一个 API 规范,您需要选择一个实现,在本示例中,我们将使用 Jersey 作为实现。虽然可以创建一个没有直接依赖于特定 JAX-RS 实现的 JAX-RS 应用程序,但这将使得示例更加啰嗦。
我选择 Jersey 有几个原因,主要是因为我可以不用绕圈子就可以轻松地获得简单的依赖注入,毕竟我们是把它在和 Spring 做对比。Apache Shiro 有一个示例,可在 Jersey、RestEasy 和 Apache CXF 上运行相同的代码,如果你感兴趣不妨看一看。
此示例与 Spring Boot 不同之处在于,它打包成 WAR,而 Spring Boot 是单个 JAR。此示例也可以打包进可执行的 jar 中,但此内容不在本文范围之内。
在 JAX-RS 中与
SpringBootApplication相当的是一个
Application类。Jersey 的
Application子类
ResourceConfig添加了一些便捷的实用方法。以下代码配置 classpath 扫描以检测我们的各个资源类,并将
DefaultStormtrooperDao实例绑定到
StromtrooperDao接口。
@ApplicationPath("/") public class JaxrsApp extends ResourceConfig { public JaxrsApp() { // scan the resources package for our resources packages(getClass().getPackage().getName() + ".resources"); // use @Inject to bind the StormtrooperDao register(new AbstractBinder() { @Override protected void configure() { bind(stormtrooperDao()).to(StormtrooperDao.class); } }); } private StormtrooperDao stormtrooperDao() { return new DefaultStormtrooperDao(); } }
另外要指出的是,在上面的类中,
@ApplicationPath注解将这个类标记为一个
JAX-RS应用程序并绑定到一个特定的 url 路径,这匹配了上面的 Spring 例子,我们只使用了根路径:
/。资源包中检测到的每个资源都将被追加到该基本路径。
JAX-RS 资源实现看起来非常类似于上述的 Spring 版本(重命名为
StormtroooperResource,以符合命名约定):
@Path("/troopers") @Produces("application/json") public class StormtroooperResource { @Inject private StormtrooperDao trooperDao; @Path("/{id}") @GET public Stormtrooper getTrooper(@PathParam("id") String id) throws NotFoundException { Stormtrooper stormtrooper = trooperDao.getStormtrooper(id); if (stormtrooper == null) { throw new NotFoundException(); } return stormtrooper; } @POST public Stormtrooper createTrooper(Stormtrooper trooper) { return trooperDao.addStormtrooper(trooper); } @Path("/{id}") @POST public Stormtrooper updateTrooper(@PathParam("id") String id, Stormtrooper updatedTrooper) throws NotFoundException { return trooperDao.updateStormtrooper(id, updatedTrooper); } @Path("/{id}") @DELETE public void deleteTrooper(@PathParam("id") String id) { trooperDao.deleteStormtrooper(id); } @GET public Collection<Stormtrooper> listTroopers() { return trooperDao.listStormtroopers(); } }
我们先来分解以下片段:
@Path("/troopers") @Produces("application/json") public class StormtroooperResource {
类似于上面的 Spring 示例,类级别上的
@Path表示此类中的每个注解方法都将位于
/troopers基本路径下。
@Produces注解定义了默认响应内容类型(除非被其他方法的注解所覆盖)。
与 Spring 示例不同,其中
@RequestMapping注解定义了请求的路径、方法和其他属性,在 JAX-RS 资源中,每个属性都使用单独的注解。与上述类似,如果我们分解了
updateTrooper()方法:
@Path("/{id}") @POST public Stormtrooper updateTrooper(@PathParam("id") String id, Stormtrooper updatedTrooper) throws NotFoundException { return trooperDao.updateStormtrooper(id, updatedTrooper); }
我们看到
@Path("/{id}")以及
@PathParam("id")允许将路径的
id部分转换为方法参数。与 Spring 示例不同的是,
Stromtrooper参数和返回值不需要额外的注解,由于此类上的
@Produces("application/json")注解,它们将自动序列化/反序列化为 JSON。
运行 JAX-RS 示例
进入 Jersey 目录,使用 maven 命令:mvn jetty:run运行此示例。
发出与上述相同的两个请求,我们可以发出
GET请求列出所有 trooper:
$ curl http://localhost:8080/troopers HTTP/1.1 200 OK Content-Length: 3944 Content-Type: application/json Date: Tue, 08 Nov 2016 21:57:55 GMT Server: Jetty(9.3.12.v20160915) [ { "id": "FN-2187", "planetOfOrigin": "Unknown", "species": "Human", "type": "Basic" }, { "id": "FN-0064", "planetOfOrigin": "Naboo", "species": "Nikto", "type": "Sand" }, { "id": "FN-0069", "planetOfOrigin": "Hoth", "species": "Twi'lek", "type": "Basic" }, { "id": "FN-0169", "planetOfOrigin": "Felucia", "species": "Kel Dor", "type": "Jump" }, ...
或者
GET一个特定的资源:
$ curl http://localhost:8080/troopers/FN-2187 HTTP/1.1 200 OK Content-Length: 81 Content-Type: application/json Date: Tue, 08 Nov 2016 22:00:02 GMT Server: Jetty(9.3.12.v20160915) { "id": "FN-2187", "planetOfOrigin": "Unknown", "species": "Human", "type": "Basic" }
现在我们已经看到了基本相同的代码在 Spring 和 JAX-RS 应用程序中运行,只需更改注解即可。我更喜欢 JAX-RS 的注解,他们更简洁。既然如此,为什么要在两者选择呢?Jersey 和 RestEasy 都支持 Spring(以及 Guice 和 CDI/Weld)。让我们来创建一个结合了这两者的第三个例子。
JAX-RS 与 Spring 整合
针对此示例,我们需要三个类:Spring Boot 应用类、Jersey 配置类和我们的资源类。我们的
SpringBootApp和
StormtrooperResource类与之前的版本相同,唯一的区别就是 Jersey 配置类:
@Component public class JerseyConfig extends ResourceConfig { public JerseyConfig() { // scan the resources package for our resources packages(getClass().getPackage().getName() + ".resources"); } }
该类与之前的示例有点类似。首先,您可能注意到了用于标记此类由 Spring 管理的 `@Configuration 注解。剩下的就是指示 Jersey 再次扫描资源包,其余的都是您的处理逻辑。
进入
spring-jaxrs目录中,使用
mvn spring-boot:run命令启动此示例。
Spring 与 JAX-RS 对照表
为了帮助您在 Spring 和 JAX-RS 的之间作出区分,这里给出了一份对照表。尽管不是很详尽,但它包含最常见的注解。Spring Annotation | JAX-RS Annotation |
---|---|
@RequestMapping(path = "/troopers") | @Path("/troopers") |
@PostMapping | @POST |
@PutMapping | @PUT |
@GetMapping | @GET |
@DeleteMapping | @DELETE |
@ResponseBody | N/A |
@RequestBody | N/A |
@PathVariable("id") | @PathParam("id") |
@RequestParam("xyz") | @QueryParam("xyz") |
@RequestParam(value="xyz") | @FormParam("xyz") |
@RequestMapping(produces = {"application/json"}) | @Produces("application/json") |
@RequestMapping(consumes = {"application/json"}) | @Consumes("application/json") |
何时在 Spring 上使用 JAX-RS?
在我看来,它应该这样分解:如果你已经是一个 Spring 用户,就使用 Spring 吧。如果你正在创建一个对象 JSON/XML REST 层,那么您选择的 DI 框架(如 Spring、Guice 等)支持 JAX-RS 资源可能是一个不错的选择。服务器端渲染页面并不是 JAX-RS 规范的一部分(虽然它是扩展支持的)。我曾在 Jersey 中使用了 Thymeleaf 视图,但我认这是 Spring MVC 该做的。
目前为止,我们还没有把 Spring Boot 应用程序与 WAR 打包的应用程序进行详细地对比。Dropwizard(使用嵌入式 Jetty 容器和 Jersey)可能是与 Spring Boot 应用程序最接近的。希望这篇文章能给你带来一些灵感,您可以做自己的对比。如果您有任何问题,欢迎 Twitter @briandemers!
示例代码
https://github.com/oktadeveloper/jaxrs-spring-blog-example相关文章推荐
- JAX-RS REST客户端实现基本身份验证机制
- ajax调用geoServer rest接口实现数据发布
- 【绝对干货来啦】巧用jax-rs之jersey实现不确定数量、多类型文件批量一次上传接口
- swagger + spring mvc 实现rest 接口代码与api 同步维护,更新
- REST API Authenticator for JAX-RS
- jax-rs(Java API for RESTful Web Services) 实践教程 之五 —— 注入全局变量 和 rest的生命周期
- 使用 Spring + CXF 发布 REST 服务(jax-RS)
- 巧用jax-rs之jersey实现不确定数量、多类型文件批量一次上传接口
- easyradius隆重发布ROS API计费接口,支持ROS 3.3以上版本,实现简单快捷的ROS宽带计费系统云端版
- CXF系列之JAX-RS:CXF与spring集成发布REST服务
- 关于使用RESTful api上传文件,基于jax rs接口,不是实现
- CXF系列之JAX-RS:CXF发布与调用REST服务
- WebService(三)—JDK内置JAX-RS实现Rest WebService
- Java EE 7 / JAX-RS 2.0: Simple REST API Authentication & Authorization with Custom HTTP Header--reference
- 【绝对干货来啦】巧用jax-rs之jersey实现不确定数量、多类型文件批量一次上传接口
- jax-rs(Java API for RESTful Web Services) 实践教程 之四 —— @Context注入HttpServletRequest 使REST保持状态!
- 【Python】调用百度REST API实现语音识别
- MQTT的学习研究(十四) MQTT moquette 的 Callback API 消息发布订阅的实现
- springcloud入门系列(2)-Feign、Ribbon实现Rest接口请求和负载均衡
- Spring+SpringMVC+MyBatis+easyUI整合进阶篇(二)RESTful API实战笔记(接口设计及Java后端实现)