Java RESTful Web Service实战(第2版) 1.6 快速了解Java REST服务

简介:

1.6 快速了解Java REST服务

1.6.1 REST工程类型

在REST服务中,资源类是接收REST请求并完成响应的核心类,而资源类是由REST服务的“提供者”来调度的。这一概念类似其他框架中自定义的Servlet类,该类会将请求分派给指定的Controller/Action类来处理。本节将讲述REST中的这个提供者,即JAX-RS2中定义的Application以及Servlet。

Application类在JAX-RS2(JSR339,详见参考资料)标准中定义为javax.ws.rs.core.Application,相当于JAX-RS2服务的入口。如果REST服务没有自定义Application的子类,容器将默认生成一个javax.ws.rs.core.Application类。

本节根据JAX-RS2规范第2章中对REST服务场景的定义,将REST服务分为四种类型,如图1-1所示。

图1-1将JAX-RS2标准中对REST服务的类型图形化,依据不同的条件分为了四种类型。

类型一:当服务中没有Application子类时,容器会查找Servlet的子类来做入口,如果Servlet的子类也不存在,则REST服务类型为类型一,对应图1-1中的例1。

类型二:当服务中没有Application子类时,存在Servlet的子类,则REST服务类型为类型二,对应图1-1中的例2。

类型三:服务中定义了Application的子类,而且这个Application的子类使用了@ApplicationPath注解,则REST服务类型为类型三,对应图1-1中的例3。

类型四:如果服务中定义了Application的子类,但是这个Application的子类没有使用@ApplicationPath注解,则REST服务类型为类型四,对应图1-1中的例4。

 

图1-1 REST工程类型示意图

上面提到的四个示例在下面的“阅读指南”中给出了源代码目录和Github下载地址,需要读者仔细体会示例之间的差异,以更好地理解和使用不同类型的REST服务。

1. REST服务类型一

类型一对应的是图1-1中的例1,相应的逻辑是服务中同时不存在Application的子类和Servlet子类。在JAX-RS2(JSR339)中定义这种情况下应作如下处理:为REST服务动态生成一个名称为javax.ws.rs.core.Application的Servlet实例,并自动探测匹配资源。与此同时,需要根据Servlet的不同版本,在web.xml定义REST请求处理的Servlet为这个动态生成的Servlet,并定义该Servlet对资源路径的匹配。在没有Application的子类存在的情况下,在web.xml中定义Servlet是必不可少的配置。

阅读指南

REST服务类型一所对应的示例,即例1的源代码地址如下。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.1.myrest-servlet2-webxml。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.2.myrest-servlet3-webxml。

请使用mvn jetty:run启动服务,使用curl http://localhost:8080/webapi/myresource测试服务。

REST服务类型一的示例包含两个小项目,分别对应Servlet2和Servlet3两种容器依赖场景。我们只须关注Maven配置文件(pom.xml)和Web服务配置文件(web.xml)的区别即可理解无Application子类情况下,如何实现基于Servlet2和Servlet3容器内的服务。

Servlet3的最简配置示例代码如下。

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/Java EE" xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://java.sun.com/xml/ns/Java EE http://java.sun.com/xml/ns/Java EE/web-app_3_0.xsd">

    <servlet>

        <servlet-name>javax.ws.rs.core.Application</servlet-name>

    </servlet>

    <servlet-mapping>

        <servlet-name>javax.ws.rs.core.Application</servlet-name>

        <url-pattern>/webapi/*</url-pattern>

    </servlet-mapping>

</web-app>

相对于Servlet2而言,在Servlet3中,servlet的定义可以只包含servlet-name。再次强调,Jersey的Servlet3的容器支持包是jersey-container-servlet。 Servlet2的最简配置示例代码如下。

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/Java EE" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/Java EE http://java.sun.com/xml/ns/Java EE/web-app_2_5.xsd">

    <servlet>

        <servlet-name>Jersey Web Application</servlet-name>

        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>

        <init-param>

            <param-name>jersey.config.server.provider.packages</param-name>

            <param-value>com.example</param-value>

        </init-param>

        <load-on-startup>1</load-on-startup>

    </servlet>

    <servlet-mapping>

        <servlet-name>Jersey Web Application</servlet-name>

        <url-pattern>/webapi/*</url-pattern>

    </servlet-mapping>

</web-app>

servlet的定义包含servlet-name和servlet-class,其初始化参数需要显示给出要加载的资源类所在的包名,可以看出Servlet2的支持包jersey-container-servlet-core不具备自动扫描资源类的功能。

2. REST服务类型二

类型二对应的是图1-1中的例2,相应的逻辑是不存在Application的子类但存在Servlet的子类。

阅读指南

REST服务类型二所对应的示例,即例2的源代码地址如下。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.3.myrest-subservlet。

本例定义了Servlet子类AirServlet,该类继承自org.glassfish.jersey.servlet.ServletContainer类,这是Jersey2中Servlet的基类,继承自HttpServlet。AirServlet类的代码示例如下。

@WebServlet(

initParams = @WebInitParam(

name = "jersey.config.server.provider.packages", value = "com.example"),

urlPatterns = "/webapi/*",

loadOnStartup = 1)

public class AirServlet extends ServletContainer {

AirServlet使用了WebServlet注解来配置Servlet参数。包括初始化参数initParams中定义扫描的资源类所在的包名:com.example,Servlet匹配的资源路径:urlPatterns="/webapi/*"和启动时的加载标识:loadOnStartup=1。

例2是基于Servlet3容器的REST服务,使用了WebServlet注解和无web.xml等Servlet3引入而Servlet2没有的功能。在自定义Servlet3.x子类的场景下,web.xml可以省略,但需要修改Maven的maven-war-plugin插件的配置,添加failOnMissingWebXml为false,这样编译时才不会报错。Maven配置文件中相关信息如下所示。

<plugin>

    <groupId>org.apache.maven.plugins</groupId>

    <artifactId>maven-war-plugin</artifactId>

    <version>2.3</version>

    <configuration>

        <failOnMissingWebXml>false</failOnMissingWebXml>

    </configuration>

</plugin>

<dependency>

    <groupId>javax.servlet</groupId>

    <artifactId>javax.servlet-api</artifactId>

    <version>3.1.0</version>

    <scope>provided</scope>

</dependency>

3. REST服务类型三

类型三对应的是图1-1中的例3,相应的逻辑是存在Application的子类并且定义了@ApplicationPath注解。

阅读指南

REST服务类型三所对应的示例,即例3的源代码地址如下。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.4.myrest-servlet3-application。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.5.myrest-servlet2-rc。

REST服务类型三的示例包含两个小项目。其中,servlet2-rc项目基于Servlet2,AirResourceConfig类继承自Application的子类ResourceConfig类;servlet3-application项目基于Servlet3,AirApplication类继承自Application类。基于Servlet2的REST服务需要定义web.xml(但内容可以是“空的”,即只有web-app的基本定义),基于Servlet3的REST服务可以省略此文件。AirApplication类代码示例如下。

@ApplicationPath("/webapi/*")

public class AirApplication extends Application {

    @Override

    public Set<Class<?>> getClasses() {

        final Set<Class<?>> classes = new HashSet<Class<?>>();

        classes.add(MyResource.class);

        return classes;

    }

}

AirApplication类覆盖了getClasses()方法,注册了资源类MyResource,这样在服务启动后,MyResource类提供的资源路径将被映射到内存,以便请求处理时匹配相关的资源类和方法。AirResourceConfig类代码示例如下。

@ApplicationPath("/webapi/\*")

public class AirResourceConfig extends ResourceConfig {

    public AirResourceConfig() {

        packages("com.example");

    }

}

AirResourceConfig类在构造子中提供了扫描包的全名,这样在服务启动后,com.example包内资源类所提供的资源路径将被映射到内存。

4. REST服务类型四

类型四对应的是图1-1中的例4,相应的逻辑是一有二无:一有是存在Application的子类;二无是不存在Servlet子类、不存在或者不允许使用注解@ApplicationPath。

阅读指南

REST服务类型四所对应的示例,即例4的源代码地址如下。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.6.myrest-servlet2-application。

https://github.com/feuyeux/jax-rs2-guide-II/tree/master/1.6.7.myrest-servlet3-application。

REST服务类型四的示例包含两个小项目,演示了基于Servlet2和Servlet3两个版本的REST服务,其差异仅此而已,关于差异性配置前面的例子已经讲过,不再冗述。如下以servlet3-application为例说明。AirApplication类是Application的子类,代码示例如下。

public class AirApplication extends Application {

    @Override

    public Set<Class<?>> getClasses() {

        final Set<Class<?>> classes = new HashSet<Class<?>>();

        classes.add(MyResource.class);

        return classes;

    }

}

代码和类型三的示例相仿,但是该类没有定义@ApplicationPath注解,因此我们需要在web.xml中配置Servlet和映射资源路径,代码示例如下。

<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="http://java.sun.com/xml/ns/Java EE" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/Java EE http://java.sun.com/xml/ns/Java EE/web-app_3_0.xsd"version="3.0">

    <servlet>

        <servlet-name>com.example.AirApplication</servlet-name>

    </servlet>

    <servlet-mapping>

        <servlet-name>com.example.AirApplication</servlet-name>

        <url-pattern>/webapi/\*</url-pattern>

    </servlet-mapping>

</web-app>

在servlet-name中使用自定义的Application子类com.example.AirApplication的全名作为Servlet名称,并在url-pattern中映射资源路径。

1.6.2 REST应用描述

在明白如何创建和部署各种类型的REST服务后,我们来了解一下部署好的REST服务中一个特殊的成员,REST应用的描述:以XML格式展示当前REST环境中所提供的REST服务接口。这种XML格式的描述就是WADL(Web Application Description Language,Web应用描述语言)。

WADL是用来描述基于HTTP协议的REST式Web服务部署情况的。它采用XML格式,支持多种数据类型的描述。WADL由Sun公司提出,尚未成为W3C或者OASIS的标准,JAX-RS标准中并没有关于WADL的定义和说明。Jersey作为JAX-RS2的参考实现默认支持服务的WADL。通过浏览器访问“服务根路径/application.wadl”即可打开该服务的WADL内容。相对于REST服务,WSDL更为人们所熟知,WSDL是RPC风格的基于SOAP的Web服务的描述语言。两者缩写类似而且都使用XML格式,此外共性不多。

1. 应用的描述

以REST服务类型四的示例项目1.6.7.myrest-servlet3-application为例,该应用的WADL路径如下:http://localhost:8080/myrest-servlet3-application/webapi/application.wadl。

通过浏览器访问该路径,可以一览WADL的schema结构。WADL的最外层标签是application,代表应用。然后自上而下分别是doc、grammars和resources。resources是应用提供的资源集合,里面至少包含application.wadl,以及应用中包含的资源描述,比如本例的资源信息描述在资源路径myresource之内,如下所示。

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<application>

    <doc jersey:generatedBy="Jersey: 2.3 2013-09-20 13:59:07"/>

    <grammars/>

<resources

base="http://localhost:8080/myrest-servlet3-application/webapi/">

        <resource path="myresource">...</resource>

        <resource path="application.wadl">...</resource>

    </resources>

</application>

2. 资源的描述

可以展开myresource来查看具体某个方法的WADL,也可以通过发送一条请求并定义请求头信息来获取。以cURL(详见1.8节)为例,命令如下。

curl -X OPTIONS -H "Allow: application/vnd.sun.wadl+xml" -v  http://localhost: 8080/myrest-servlet3-application/webapi/myresource

myrest-servlet3-application提供的资源接口,对照服务器返回的XML,可以更清晰地理解WADL的内容。其WADL内容如下。

<resource path="myresource">

    <method id="getIt" name="GET">

        <response>

            <representation mediaType="text/plain"/>

        </response>

    </method>

    <method id="apply" name="OPTIONS">

        <request>

            <representation mediaType="*/*"/>

        </request>

        <response>

            <representation mediaType="application/vnd.sun.wadl+xml"/>

        </response>

    </method>

    <method id="apply" name="OPTIONS">

        <request>

            <representation mediaType="*/*"/>

        </request>

        <response>

            <representation mediaType="text/plain"/>

        </response>

    </method>

    <method id="apply" name="OPTIONS">

        <request>

            <representation mediaType="*/*"/>

        </request>

        <response>

            <representation mediaType="*/*"/>

        </response>

    </method>

</resource>

在这段代码中,公布了四个方法。其中,getIt方法代码如下。其他三个OPTIONS请求方法是Jersey默认实现的,用以描述getiIt方法,分别返回text/plain类型,*/*类型和application/vnd.sun.wadl+xml类型。

@GET

@Produces(MediaType.TEXT_PLAIN)

public String getIt() {

return "Got it!";

}

getIt方法定义为GET请求方法,@Produces中定义的媒体类型是MediaType.TEXT_PLAIN,即响应过程中生产的数据,其表述性状态以text/plain媒体类型转移。

3. WADL的配置

上述OPTIONS请求方法的实现是Jersey默认支持的,如果读者不希望在REST服务中让Jersey自动生成,可以通过配置jersey.config.server.wadl.disableWadl=true来实现。代码示例如下。

public class AirApplication extends ResourceConfig {

    public AirApplication() {

        property(ServerProperties.WADL_FEATURE_DISABLE, true);

        packages("com.example.resource");

    }

}

在构造函数中,我们通过定义ServerProperties.WADL_FEATURE_DISABLE属性为true以实现去除WADL自动生成的功能。 或者,可以通过修改Web配置文件中servlet启动参数来实现,代码示例如下。

<servlet>

    <servlet-name>com.example.AirApplication</servlet-name>

    <init-param>

        <param-name>jersey.config.server.wadl.disableWadl</param-name>

        <param-value>true</param-value>

    </init-param>

</servlet>

配置文件中定义了启动参数jersey.config.server.wadl.disableWadl,其值定义为true,以实现去除WADL自动生成的功能。

相关文章
|
15天前
|
监控 JavaScript 前端开发
《理解 WebSocket:Java Web 开发的实时通信技术》
【4月更文挑战第4天】WebSocket是Java Web实时通信的关键技术,提供双向持久连接,实现低延迟、高效率的实时交互。适用于聊天应用、在线游戏、数据监控和即时通知。开发涉及服务器端实现、客户端连接及数据协议定义,注意安全、错误处理、性能和兼容性。随着实时应用需求增加,WebSocket在Java Web开发中的地位将更加重要。
|
11天前
|
Java 测试技术
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
SpringBoot整合单元测试&&关于SpringBoot单元测试找不到Mapper和Service报java.lang.NullPointerException的错误
16 0
|
4天前
|
Web App开发 Java 应用服务中间件
【Java Web】在 IDEA 中部署 Tomcat
【Java Web】在 IDEA 中部署 Tomcat
19 0
|
13天前
|
安全 前端开发 Java
Java Web开发知识点学习总结
Java Web开发涉及Java基础、Servlet、JSP、数据库操作(SQL+JDBC)、MVC设计模式、Spring框架、Hibernate ORM、Web服务(SOAP&RESTful)、安全认证(HTTP Basic/Digest/OAuth)及性能优化(缓存、异步、负载均衡)。
15 3
|
16天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
16天前
|
前端开发 Java API
构建RESTful API:Java中的RESTful服务开发
【4月更文挑战第3天】本文介绍了在Java环境中构建RESTful API的重要性及方法。遵循REST原则,利用HTTP方法处理资源,实现CRUD操作。在Java中,常用框架如Spring MVC简化了RESTful服务开发,包括定义资源、设计表示层、实现CRUD、考虑安全性、文档和测试。通过Spring MVC示例展示了创建RESTful服务的步骤,强调了其在现代Web服务开发中的关键角色,有助于提升互操作性和用户体验。
构建RESTful API:Java中的RESTful服务开发
|
16天前
|
前端开发 安全 Java
使用Java Web框架:Spring MVC的全面指南
【4月更文挑战第3天】Spring MVC是Spring框架的一部分,用于构建高效、模块化的Web应用。它基于MVC模式,支持多种视图技术。核心概念包括DispatcherServlet(前端控制器)、HandlerMapping(请求映射)、Controller(处理请求)、ViewResolver(视图解析)和ModelAndView(模型和视图容器)。开发流程涉及配置DispatcherServlet、定义Controller、创建View、处理数据、绑定模型和异常处理。
使用Java Web框架:Spring MVC的全面指南
|
18天前
|
Java
销售业务管理系统【Web系统】(Java课设)
销售业务管理系统【Web系统】(Java课设)
13 5
|
2月前
|
Java Maven 开发者
深入剖析Spring Boot在Java Web开发中的优势与应用
深入剖析Spring Boot在Java Web开发中的优势与应用
|
2月前
|
Java 应用服务中间件 API
深入解析Java Servlet技术在Web开发中的应用
深入解析Java Servlet技术在Web开发中的应用
213 1