【方向盘】版本历史&代码示例之:JAX-RS

开发 前端
本文详细介绍了JAX-RS规范,并代码演示了其官方推荐实现Jersey的使用。在Spring MVC大行其道的今天,由于Java EE技术仍有不少受众群体(特别是国外开源软件),所以此部分知识点依旧不可或缺。

前言

读开源框架源码,你会经常遇到Jersey。

Java EE 6引入了一项新技术:JAX-RS(Java API for RESTful Web Services),隶属于JSR 311规范。该规范旨在定义一个统一的规范(主要是@Get、@Post这些注解),目标是让Java 程序员可以使用一套固定的接口来开发REST应用,避免强依赖于具体的第三方框架技术,这一点和JPA的目的保持一致。

[[430747]]

可能你对JAX-RS感到陌生,但对它的参考实现Jersey,和其它实现如著名的Apache CXF、Axis以及JBooss的RESTEasy等等多少有些耳闻。在JAX-RC“出生”之际官方对其有过隆重介绍,擅长英文阅读的同学这里看官方介绍:https://docs.oracle.com/javaee/6/tutorial/doc/giepu.html

本文将带你走进JSR 311规范,演示通过Jersey构建REST服务,看看Eureka是如何使用Jersey的。另外,“竞品”Spring MVC它为何成为了实际标准且还不去兼容JSR 311,胆子忒太了。

所属专栏

  • 【方向盘】-Java EE

相关下载

  • 【本专栏源代码】:https://github.com/yourbatman/FXP-java-ee
  • 【技术专栏源代码大本营】:https://github.com/yourbatman/tech-column-learning
  • 【女娲Knife-Initializr工程】访问地址:http://152.136.106.14:8761
  • 【程序员专用网盘】公益上线啦,注册送1G超小容量,帮你实践做减法:https://wangpan.yourbatman.cn
  • 【Java开发软件包(Mac)】:https://wangpan.yourbatman.cn/s/rEH0 提取码:javakit

版本约定

  • Java EE:6、7、8
  • Jakarta EE:8、9、9.1

正文

JAX-RS

JAX-RS全称是:Java API for RESTful Services。它是一个社区驱动的标准,用于使用 Java 构建 RESTful Web 服务。它不仅定义了一套用于构建 RESTful 网络服务的 API,同时也通过增强客户端 API 功能简化了REST 客户端的构建过程。

话外音:既规范了Server服务端也规范了Client客户端

Jersey的Server是基于Servlet构建的web应用,所以需要部署到任何实现Servlet容器里运行。由于它是一套标准规范,因此可以在不改任何代码的情况下,任意切换JAX-RS实现框架。

JAX-RS常用注解

  • @Path:标注在类/方法上。类似于@RequestMapping中的path路径
  • @GET,@PUT,@POST,@DELETE等:标注在方法上。含义你懂的。等同于这个注解@HttpMethod("GET/POST")@Produces:标注在类/方法上。可以返回的MIME类型
  • @Consumes:标注在类/方法上。可以接受的 MIME 类型
  • @PathParam,@QueryParam,@HeaderParam,@CookieParam,@MatrixParam,@FormParam:分别获取不同位置上的参数(@MatrixParam获取数组/集合类型的value)
  • @DefaultValue:默认值
  • @ApplicationPath:标注在类上,表示本应用路径。所有@Path的前缀,一个应用只需有一个
  • @BeanParam:标注在方法、方法参数、属性上,since 2.0版本。效果类似于@RequestBody

Restful、JAX-RS、Jersey异同点

  • Restful:一种网络应用程序的设计风格,基于http,适用于业务接口场景。它崇尚约定大于配置,有了统一的规范,在接口设计时能够保证理解的一致性,所以对构建大型项目很友好
  • JAX-RS:它是Java EE的一向规范,实现了Restful风格。它通过Path将网络上的资源唯一的标识出来。值得注意的是:它只提供标准,自己并没提供实现
  • Jersey:一个框架,JAX-RS的官方参考实现。类似于Spring MVC一样实现了MVC设计思想

Spring MVC对比Jersey

首先,Spring MVC是一个完整的 Web层框架,它除了提供JSON/XML的Restful处理能力之外,还包括对HTML以及其它模板(引擎)的支持。而Jersey只支持REST

说明:Spring MVC最初只支持处理Html等格式,直到2010年2月重磅发布了Spring 3.0版本,从此一骑绝尘,将其它框架越甩越远

其次,Spring MVC是Spring家族的亲儿子,和Spring容器天然集成。所以从集成的方便度来看,Jersey自然比不上Spring MVC。当然,你的应用可能并非构建在Spring之上,那么实现了Java EE/JAX-RS规范的Jersey的移植性可能更好,这也是为什么像Eureka这种开源框架选择Jersey的原因

最后,Spring MVC和Jersey都是基于Servlet构建Web应用的(Spring 5后可选基于Reactor)。Spring MVC核心类为DispatcherServlet;Jersey核心类为ServletContainer

说明:Jersey和Spring框架整合的核心类为SpringServlet

  1. <!-- javax命名空间版本(Tomcat 9.x及以下版本支持) --> 
  2. <dependency> 
  3.     <groupId>javax.ws.rs</groupId> 
  4.     <artifactId>javax.ws.rs-api</artifactId> 
  5.     <version>2.1.1</version> 
  6. </dependency> 
  7.  
  8. <!-- jakarta命名空间版本(Tomcat 10.x及以上版本支持) --> 
  9. <dependency> 
  10.     <groupId>jakarta.ws.rs</groupId> 
  11.     <artifactId>jakarta.ws.rs-api</artifactId> 
  12.     <version>3.0.0</version> <!-- Jakarta命名空间 --> 
  13.     <!-- <version>2.1.6</version> 此版本命名空间同javax --> 
  14. </dependency> 

版本历程

  • 2.0版本新特性:新增@BeanParam注解,可以将参数自动封装进POJO(类似于@RequestBody注解);新增Client API来规范化客户端的开发方式;增加了Filters和interceptors来分离关注点,更好的实现代码复用;引入异步处理(在客户端返回Future对象);引入Bean Validation支持;
  • 2.1版本新特性:对客户端增加JSON-P和JSON-B的绑定实现

说明:Jersey从2.26版本起就适配JAX-RS 2.1新特性啦

生存现状

JAX-RS隶属于Java EE规范,但实际的规范已然易主:Spring MVC。它在国内几乎不可见,但在海外崇尚Java EE的国度尚有一定忠诚粉丝。

总的来讲:不容乐观,不可忽视。

实现(框架)

  • Jersey:官方参考实现(推荐)
  • Apache CXF:开源的Web服务框架
  • RESTEasy:JBoss提供的实现
  • Restlet:最早的REST框架,先于JAX-RS出现
  • Apache Wink:一个是使用简单,稳定的Java框架。包含服务器端模块和客户端模块

代码示例

使用官方参考实现Jersey来构建Server端Web程序。

加入Maven依赖:

  1. <dependencies> 
  2.     <!-- API规范 --> 
  3.     <!--<dependency>--> 
  4.     <!--    <groupId>jakarta.ws.rs</groupId>--> 
  5.     <!--    <artifactId>jakarta.ws.rs-api</artifactId>--> 
  6.     <!--    <version>2.1.6</version>--> 
  7.     <!--</dependency>--> 
  8.  
  9.     <dependency> 
  10.         <groupId>org.glassfish.jersey.core</groupId> 
  11.         <artifactId>jersey-server</artifactId> 
  12.     </dependency> 
  13.     <!-- 使用Servelt容器启动,就得导入它 --> 
  14.     <dependency> 
  15.         <groupId>org.glassfish.jersey.containers</groupId> 
  16.         <artifactId>jersey-container-servlet</artifactId> 
  17.     </dependency> 
  18.     <!-- 若遇上java.lang.IllegalStateException: InjectionManagerFactory not found.异常,导入此包 --> 
  19.     <dependency> 
  20.         <groupId>org.glassfish.jersey.inject</groupId> 
  21.         <artifactId>jersey-hk2</artifactId> 
  22.     </dependency> 
  23.     <dependency> 
  24.         <groupId>javax.servlet</groupId> 
  25.         <artifactId>javax.servlet-api</artifactId> 
  26.         <scope>provided</scope> 
  27.     </dependency> 
  28. </dependencies> 

借助ResourceConfig书写配置类来管理资源(这是方式之一,还可通过包扫描等方式注册资源):

  1. /** 
  2.  * 相当于资源管理器,启动此管理器就启用了资源 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/10/24 17:22 
  7.  * @since 0.0.1 
  8.  */ 
  9. public class MyResourceConfig extends ResourceConfig { 
  10.  
  11.     // 在构造阶段,暴露资源 
  12.     public MyResourceConfig() { 
  13.         register(HelloResource.class); 
  14.     } 

书写一个资源(类似于Controller):

  1. /** 
  2.  * 在此处添加备注信息 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/10/24 17:24 
  7.  * @since 0.0.1 
  8.  */ 
  9. @Path("/hello"
  10. public class HelloResource { 
  11.  
  12.     @Path("/demo"
  13.     @GET 
  14.     @Produces(MediaType.TEXT_PLAIN) 
  15.     public String demo() { 
  16.         return "hello jax-rs..."
  17.     } 

书写描述符web.xml:

  1. <?xml version="1.0" encoding="UTF-8"?> 
  2. <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" 
  3.          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  4.          xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" 
  5.          version="4.0"
  6.  
  7.     <!-- Jersey调度入口 --> 
  8.     <servlet> 
  9.         <servlet-name>JerseyServlet</servlet-name
  10.         <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> 
  11.         <!-- 启动Resource资源配置 --> 
  12.         <init-param> 
  13.             <param-name>javax.ws.rs.Application</param-name
  14.             <param-value>org.glassfish.jersey.server.ResourceConfig</param-value> 
  15.         </init-param> 
  16.         <!-- 通过扫包方式扫描Resource资源 --> 
  17.         <!--<init-param>--> 
  18.         <!--    <param-name>jersey.config.server.provider.packages</param-name>--> 
  19.         <!--    <param-value>cn.yourbatman.coding.jaxrs</param-value>--> 
  20.         <!--</init-param>--> 
  21.  
  22.         <load-on-startup>1</load-on-startup> 
  23.     </servlet> 
  24.     <servlet-mapping> 
  25.         <servlet-name>JerseyServlet</servlet-name
  26.         <url-pattern>/yourbatman/*</url-pattern> 
  27.     </servlet-mapping> 
  28.  
  29. </web-app> 

使用外置Tomcat,部署此war包:

启动Tomcat,浏览器就可正常访问http://localhost:9090/yourbatman/hello/demo了,如下图:

完美!

Tips:若访问时出现如下异常,请在pom里额外导入org.glassfish.jersey.inject:jersey-hk2这个jar即可解决。

上面是通过浏览器作为客户端访问HelloResource这个资源。其实,JAX-RS还提供了javax.ws.rs.client.Client客户端规范,并且Jersey-Client也给予了实现。这里也简单演示下:

导入Client依赖:

  1. <!-- Client无需单独打包,因为jersey-server里已有。只有单独使用Jersey Client时才需导入 --> 
  2. <!--<dependency>--> 
  3. <!--    <groupId>org.glassfish.jersey.core</groupId>--> 
  4. <!--    <artifactId>jersey-client</artifactId>--> 
  5. <!--</dependency>--> 

使用Jersey发送Http请求:

  1. /** 
  2.  * Jersey Client,发送Http请求 
  3.  * 
  4.  * @author YourBatman. <a href=mailto:yourbatman@aliyun.com>Send email to me</a> 
  5.  * @site https://yourbatman.cn 
  6.  * @date 2021/10/24 17:41 
  7.  * @since 0.0.1 
  8.  */ 
  9. public class JerseyClient { 
  10.  
  11.     public static void main(String[] args) { 
  12.         // ==== 创建Client的实例 === 
  13.         Client client = ClientBuilder.newClient(); 
  14.         WebTarget baseTarget = client.target("http://localhost:9090/yourbatman"); 
  15.  
  16.         // 具体请求 
  17.         WebTarget helloTarget = baseTarget.path("/hello/demo").queryParam("age""18"); 
  18.         // 发送get请求(可指定可接收的accept头) 
  19.         Response response = helloTarget.request("*").get(); 
  20.         // Response response = helloTarget.request("text/plain""text/html""text/plain").get(); 
  21.  
  22.         // 打印结果 
  23.         int status = response.getStatus(); 
  24.         String result = response.readEntity(String.class); 
  25.         System.out.println("响应状态码为:" + status + ",响应值为:" + result); 
  26.     } 

运行main方法,控制台输出:

  1. 响应状态码为:200,响应值为:hello jax-rs... 

完美。

说明:Jersey Client底层使用JDK的HttpURLConnection发送Http请求,可通过其SPI机制替换成其它Connection

总结

本文详细介绍了JAX-RS规范,并代码演示了其官方推荐实现Jersey的使用。在Spring MVC大行其道的今天,由于Java EE技术仍有不少受众群体(特别是国外开源软件),所以此部分知识点依旧不可或缺。

国内的我们几乎100%都是Spring技术栈的受众,所以如果要选择的话,当然推荐Spring,毕竟也好找工作得多得多嘛。所以说JAX-RS是官方标准,而Spring则是事实标准。

本文转载自微信公众号「Java方向盘」

 

责任编辑:姜华 来源: Java方向盘
相关推荐

2021-10-11 08:51:50

JavaMailJDBCJava

2021-10-08 06:50:32

版本历史代码

2009-09-22 13:04:19

ibmdwREST

2021-10-19 08:23:43

JMXJava 管理扩展

2021-09-15 18:54:22

BATutopia-JWebSocket

2009-12-23 09:50:45

JAX-RSJerseyRESTful

2009-12-22 09:57:36

Java EE 6RESTfulJAX-RS

2021-09-13 18:39:50

ServeltELJSP

2023-03-10 14:55:28

2010-12-21 11:36:58

职场

2021-11-01 07:55:39

Java EE开发项目

2018-01-15 09:32:34

无人驾驶GPU主机辅助驾驶

2021-12-20 08:15:25

SpringFeignClientSpring Clou

2022-04-11 08:34:27

IDEA代码补全

2021-11-29 08:13:41

Spring Boot环境变量Spring技术

2022-01-06 09:38:13

集度自动驾驶apollo

2021-12-02 15:19:34

自动驾驶技术苹果

2022-03-28 08:35:33

IDEA快捷键操作视窗

2022-04-06 08:35:13

IDEADebug调试Run运行
点赞
收藏

51CTO技术栈公众号