一、REST简介
REST (Representional State Transfer 表述性状态转移)是 Web 服务的一种架构风格;使用 HTTP、URI、XML、JSON、HTML 等广泛流行的标准和协议;轻量级,跨平台,跨语言的架构设计风格。
REST架构主要原则
- 网络上的所有事物都被抽象成资源
- 每个资源都有唯一的资源标识符
- 同一个资源具有多种表现形式(XML、JSON 等)
- 对资源的各种操作不会改变资源标识符
- 所有的操作都是无状态的
符合 REST 原则的架构方式 即可 称为 RESTful。
二、Spring 支持 REST
1.支持的方式
- 控制器可以处理所有的 HTTP 方法,包括四个主要的 REST 方法:
GET
PUT
DELETE
POST
- 通过
@PathVariable
注解,控制器能够处理参数化 URL(把变量作为 URL 的一部分) - 借助 Spring 的视图 和 视图解析器,资源能够以 多种方式 进行表达,包括将模型数据 渲染成 XML、JSON、AtomRSS 的 view 实现
- 使用 ContentNegotiatingViewResolver (内容协商视图解析器) 来选择最合适的客户端的表述
- 借助
@ResponseBody
注解 和 各种 HttpMessageConverter 实现,能够替换基于视图的渲染方式 - 借助
@RequestBody
注解 和 各种 HttpMessageConverter 实现,能够将传入的 HTTP 请求数据转化为传入控制器处理方法的 Java 对象 - 借助 RestTemplate 类 Spring应用能方便地使用 REST 资源
2.资源转换
Spring 提供了两种方法将资源的 Java 表达形式 转换成 发送给客户端的表述形式。
-
内容协商(Content Negotiation):
选择一个视图,它能够将模型渲染为 呈现给客户端的表述形式。 -
消息转换器(Message Conversion):
通过一个消息转化器将控制器所返回的对象转换成 呈现给客户端的表述形式。
3.内容协商
内容协商是在 Spring MVC 之上构建的 REST 资源表述层,控制器代码无需修改,相同的一套控制器方法能够 面向人类用户 产生 HTML 内容,也能针对不是人类的 客户端 产生 JSON 或 XML。
如果面向人类用户的接口 和 面向非人类的 客户端 的接口有很多重叠的话,那么内容协商就是一种很便利的方案。(反之,它的优势就体现不出来了)
内容协商还有一个严重的限制,作为 ViewResolver 实现,它 只能决定 资源如何渲染到客户端 ,并没有涉及到 客户端要发送什么样的表述给控制器使用。如果客户端发送 JSON 或者 XML 的话,那么内容协商就无法提供帮助了。
消息转换器
消息转换器提供了一种更为直接的方法,它能够将控制器产生的数据 转换为 服务 与 客户端 的 表述形式。当使用消息转换功能时, DispatchServlet 不再需要那么麻烦地将模型数据传送到 视图中。 实际上,也根本没有了模型和视图,只有控制器产生的数据,以及消息转换器 (Message Conversion)转换数据之后所产生的资源表述。
举例:假设 客户端通过请求的 Accept 头信息 表明 它能够接受 application/json,并且 Jackson JSON 库在类路径下,那么处理方式返回的对象将交给 MappingJacksonHttpMessageConvert ,并且 它转换为 客户端的 JSON 表述形式。另外,如果请求头的信息表明 客户端相应 text/xml 格式,那么
Jaxb2RootElementHttpMessageConverter 将会作为客户端产生 XML 相应。
Spring 提供了多个 HTTP 消息转换器,用于实现资源表述与各种Java类型之间的互相转换,下面列出几个常用的消息转换器:
-
MappingJackson2HttpMessageConverter :
在JSON和类型化对象或者非类型化的 HashMap 间互相读取和写入,如果 Jackson 2 JSON 库在类路径下将进行注册。 -
GsonHttpMessageConverter :
在JSON和类型化对象或者非类型化的 HashMap 间互相读取和写入,如果
Gson 库在类路径下将进行注册。 -
FormHttpMessageConverter :
将application/x-www-form-urlencoded
内容读入到 MultiValueMap<String,String> 中,也会将 MultiValueMap<String,String> 写入到application/x-www-form-urlencoded
中或将MultiValueMap<String,Object>写入到 multipart/form-data 中。 -
StringHttpMessageConverter :
将所有媒体类型(/)读取为String,将String写入为text/plain -
Jaxb2RootElementHttpMessageConverter :
在XML(text/xml或者application/xml)和使用JAXB2注解对象间相互读取和写入,如果JAXB v2库在类路径下将进行注册
等等
尽管Spring支持了多种资源表述形式,以及多种消息转化器。但是在定义REST API的时候,不一定全部使用它们。
对于大多数客户端来说,使用 JSON 和 XML 来进行表述就足够了。
- 备注:实际在REST API中大多数情况表述都是用JSON格式
三、创建 REST 项目
首先创建Maven Web项目,选择 webapps 骨架;接下来修改项目结构:
创建WEB项目中需的目录:
在 pom.xml 中导入 jar 包依赖:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.jia</groupId>
<artifactId>SpringMVCRESTful</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>war</packaging>
<name>SpringMVCRESTful Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--Spring MVC依赖-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
<!--日志依赖-->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.25</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
<!--文件上传依赖-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<!--第一种-->
<!--MappingJacksonHttpMessageConverter依赖-->
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.8</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.jaxrs/jackson-jaxrs-json-provider -->
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.9.9</version>
</dependency>
<!--第二种-->
<!--GsonHttpMessageConverter依赖,JSON处理库-->
<!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>SpringMVCRESTful</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.1.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.2</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
接下来,配置 web.xml:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>欢迎来到Spring REST的世界</display-name>
<description>这是一个Spring REST的学习示例</description>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<!--注册ContextLoaderListener-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!--前端控制器,注册DispatherServlet-->
<servlet>
<servlet-name>servlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationServlet.xml</param-value>
</init-param>
</servlet>
<!--将DispatcherServlet映射到'/'-->
<servlet-mapping>
<servlet-name>servlet</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>