本节将介绍RESTful风格接口,并通过Spring Boot来实现RESTful。
1、REST简介
2、Spring Boot整合REST
3、Spring Data REST
4、REST服务测试
REST即表现层状态转化(英文:Representational State Transfer,简称REST)是Roy Thomas Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。
REST是一组架构约束条件和原则。这些约束有:
1.使用客户/服务器模型。客户和服务器之间通过一个统一的接口来互相通讯。
2.层次化的系统。在一个REST系统中,客户端并不会固定地与一个服务器打交道。
3.无状态。在一个REST系统中,服务端并不会保存有关客户的任何状态。也就是说,客户端自身负责用户状态的维持,并在每次发送请求时都需要提供足够的信息。
4.可缓存。REST系统需要能够恰当地缓存请求,以尽量减少服务端和客户端之间的信息传输,以提高性能。
5.统一的接口。一个REST系统需要使用一个统一的接口来完成子系统之间以及服务与用户之间的交互。这使得REST系统中的各个子系统可以独自完成演化。
满足这些约束条件和原则的应用程序或设计就是RESTful。需要注意的是,REST是设计风格而不是标准。REST通常基于HTTP、URI、XML以及HTML这些现有的广泛流行的协议和标准。
资源(Resources)
“表现层状态转化”中的“表现层”其实指的是“资源”的“表现层”。
“资源”就是网络上的一个实体,或者说是网络上的一个具体信息。“资源”可以是一段文本、一张图片、一段视频,总之就是一个具体的实体。我们可以使用一个URI(统一资源定位符)指向资源,每种资源对应一个特定的URI。我们需要获取资源时,访问它的URI即可,因此URI是每个资源的地址或独一无二的标识符。REST风格的Web服务,是通过一个简洁清晰的URI来提供资源链接,客户端通过对URI发送HTTP请求获得这些资源,而获取和处理资源的过程让客户端应用的状态发生改变。
表现层(Representation)
“资源”是一种信息实体,可以有多种外在的表现形式。我们将“资源”呈现出来的形式称为它的“表现层”。例如,文本可以使用txt格式表现,也可以使用XML格式、JSON格式表现。
状态转化(State Transfer)
客户端访问一个网站,就代表了它和服务器的一个互动过程。在这个互动过程中,将涉及数据和状态的变化。我们知道HTTP协议是一个无状态的通信协议,这意味着所有状态都保存在服务器端。因此,如果客户端操作服务器,需要通过某种手段(如HTTP协议)让服务器端发生“状态变化”。而这种转化是建立在表现层之上的,所以就是“表现层状态转化”
在流行的各种Web框架中,包括Spring Boot都支持REST开发。REST并不是一种技术或者规范,而是一种架构风格,包括了如何标识资源、如何标识操作接口及操作的版本、如何标识操作的结果等,主要内容如下:
1.使用“api”作为上下文
在REST架构中,建议使用“api”作为上下文,示例如下;
http://localhost:8080/api
2.增加一个版本标识
在REST架构中,可以通过URL标识版本信息,示例如下:
http://localhost:8080/api/v1.0
3.标识资源
在REST架构中,可以将资源名称放到URL中,示例如下:
http://localhost:8080/api/v1.0/user
4.确定HTTP Method
HTTP协议有5个常用的表示操作方式的动词:GET、POST、PUT、DELETE、PATCH。它们分别对应5种基本操作:GET用来获取资源,POST用来增加资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源,PATCH用来更新资源的部分属性。示例如下:
1)新增用户
POST http://localhost:8080/api/v1.0/user
2)查询id为123的用户
GET http://localhost:8080/api/v1.0/user/123
3)更新id为123的用户
PUT http://localhost:8080/api/v1.0/user/123
4)删除id为123的用户
DELETE http://localhost:8080/api/v1.0/user/123
5.确定HTTP Status
服务器向用户返回的状态码和提示信息,常用的如下:
1)200 OK - [GET]:服务器成功返回用户请求的数据。
2)201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
3)202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)。
4)204 NO CONTENT - [DELETE]:用户删除数据成功。
5)400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作。
6)401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
7)403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
8)404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作。
9)406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
10)410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
11)422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
12)500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
在Spring Boot的Web应用中,自动支持REST。也就是说,只要spring-boot-starter-web依赖在pom中,就支持REST。
【例6-9】一个RESTful应用示例
假如,在ch6_2应用的控制器类中有如下处理方法:
@RequestMapping("/findArticleByAuthor_id/{id}")
public List<Article> findByAuthor_id(@PathVariable("id") Integer id) {
return authorAndArticleService.findByAuthor_id(id);
}
那么,我们可以使用如下所示的REST风格的URL访问上述处理方法:
http://localhost:8080/ch6_2/findArticleByAuthor_id/2
在【例6-9】中使用了URL模板模式映射@RequestMapping("/findArticleByAuthor_id/{id}")
,其中{XXX}为占位符,请求的URL可以是“/findArticleByAuthor_id/1
”或“/findArticleByAuthor_id/2
”。通过在处理方法中使用@PathVariable获取{XXX}中的XXX变量值。@PathVariable用于将请求URL中的模板变量映射到功能处理方法的参数上。如果{XXX}中的变量名XXX和形参名称一致,则@PathVariable不用指定名称。
目前,Spring Data REST支持将Spring Data JPA、Spring Data MongoDB、Spring Data Neo4j、Spring Data GemFire以及Spring Data Cassandra的repository自动转换成REST服务。
通过SpringBootRepositoryRestConfigurer
类的源码我们可以得出,Spring Boot已经自动配置了RepositoryRestConfiguration
,所以在Spring Boot应用中使用Spring Data REST
只需引入spring-boot-starter-data-rest
的依赖即可使用。
【例6-10】Spring Data REST的构建过程。
1.创建Spring Boot应用ch6_7
创建Spring Boot应用ch6_7,依赖为Spring Data JPA和Rest Repositories。
2.修改pom.xml文件,添加MySQL依赖
<!-- 添加MySQL依赖 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.22</version><!--$NO-MVN-MAN-VER$-->
<!-- My
3.设置应用ch6_7的上下文路径及数据源配置信息
在ch6_7的application.properties文件中配置以下内容:
server.servlet.context-path=/api
###
##数据源信息配置
###
#数据库地址
spring.datasource.url=jdbc:mysql://localhost:3306/springbootjpa?useSSL=false&serverTimezone=UTC&characterEncoding=utf-8
#数据库用户名
spring.datasource.username=root
#数据库密码
spring.datasource.password=123456
#数据库驱动
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
####
#JPA持久化配置
####
#指定数据库类型
spring.jpa.database=MYSQL
#指定是否在日志中显示SQL语句
spring.jpa.show-sql=true
#指定自动创建、更新数据库表等配置,update表示如果数据库中存在持久化类对应的表就不创建,不存在就创建对应的表
spring.jpa.hibernate.ddl-auto=update
#让控制器输出的JSON字符串格式更美观
spring.jackson.serialization.indent-output=true
4.创建持久化实体类Student
创建名为com.ch.ch6_7.entity的包,并在该包中创建名为Student持久化实体类。
Student的具体代码如下:
package com.ch.ch6_7.entity;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "student_table")
public class Student implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;//主键
private String sno;
private String sname;
private String ssex;
public Student() {
super();
}
public Student(int id, String sno, String sname, String ssex) {
super();
this.id = id;
this.sno = sno;
this.sname = sname;
this.ssex = ssex;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSno() {
return sno;
}
public void setSno(String sno) {
this.sno = sno;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public String getSsex() {
return ssex;
}
public void setSsex(String ssex) {
this.ssex = ssex;
}
}
5.创建数据访问层
在com.ch.ch6_7.repository包中,创建名为StudentRepository的接口,该接口继承JpaRepository接口。
StudentRepository的代码如下:
package com.ch.ch6_7.repository;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import org.springframework.data.rest.core.annotation.RestResource;
import com.ch.ch6_7.entity.Student;
public interface StudentRepository extends JpaRepository<Student, Integer>{
/**
* 自定义接口查询方法,暴露为REST资源
*/
@RestResource(path = "snameStartsWith", rel = "snameStartsWith")
List<Student> findBySnameStartsWith(@Param("sname") String sname);
}
在上述数据访问接口中,定义了findBySnameStartsWith,并使用@RestResource注解将该方法暴露为REST资源。
至此,基于Spring Data的REST资源服务已经构建完毕,接下来就是使用REST客户端测试此服务。
在Web和移动端开发时,常常会调用服务器端的RESTful接口进行数据请求,为了调试,一般会先用工具进行测试,通过测试后才开始在开发中使用。本节将介绍如何使用 Wisdom REST Client进行上面的RESTful接口请求测试。
Wisdom REST Client是用Java编写的REST客户端,是GitHub上的开源项目。可以通过https://github.com/Wisdom-Projects/rest-client地址下载。该客户端使用方便,解压后双击tools下的restclient-1.2.jar包,即可运行。
1.获得列表数据
在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与实体名对应。一般来说,数据库中的表都是同种记录的“集合”(collection),所以API中的名词也应该使用复数,如students。
运行上面的程序,并在student_table中手动添加几条学生信息后,在Wisdom REST Client中,使用GET方式访问“http://localhost:8080/api/students
”请求路径获得所有学生信息。
在Wisdom REST Client中,使用GET方式访问“http://localhost:8080/api/students/2”请求路径获得id为2的学生信息。
在Wisdom REST Client中,search调用自定义的接口查询方法。因此,可以使用GET访问“http://localhost:8080/api/students/search/snameStartsWith?sname=王”请求路径调用List findBySnameStartsWith(@Param(“sname”) String sname)接口方法,获得姓名前缀为“王”的学生信息。
在Wisdom REST Client中,使用GET方式访问“http://localhost:8080/api/students/?page=0&size=2”请求路径获得第一页的学生信息(page=0即第一页,size=2即每页数量为2)。
在Wisdom REST Client中,使用GET方式访问“http://localhost:8080/api/students/?sort=sno,desc”请求路径获得按照sno属性倒序的列表。
在Wisdom REST Client中,发起POST方式请求实现新增功能,将要保存的数据放置在请求体中,数据类型为JSON。
假如,我们需要更新新增的id为5的数据,可以在Wisdom REST Client中,使用PUT方式访问“http://localhost:8080/api/students/5”,修改提交的数据。
8.删除
假如,我们需要删除新增的id为5的数据,可以在Wisdom REST Client中,使用DELETE方式访问“http://localhost:8080/api/students/5”,删除数据。
从返回的状态码204可以看出,用户数据删除成功。
1、 技术笔记 1 遍
2、CSDN 技术博客 1 篇