七、构建 RESTful 服务

本章概要

  • REST 简介
  • JPA 实现 REST
  • MongoDB 实现 REST

7.1 REST 简介

REST(Representainal State Transfer)是一种 Web 软件架构风格,它是一种风格,而不是标准,匹配或兼容这种框架风格的网络服务称为 REST 服务器。REST 服务简洁并且有层次,REST 通常基于 HTTP、URI 和 XML 以及 HTML 折现现有的广泛流行的协议和标准。
在 REST 中,资源是有 URI 来指定的,对资源的增删改查操作可以通过 HTTP 协议提供的 GET、POST、PUT、DELETE 等方法实现。使用 REST 可以更高效地利用缓存来提高响应速度,同时 REST 中的通信会话状态由客户端来维护,这可以让不同的服务器来处理一系列请求中的不同请求,进而提高服务器的扩展性,在前后端分离项目中,一个设计良好的 Web 软件架构必然要满足 REST 风格。
在 Spring MVC 框架中,开发者可以通过 @RestController 注解开发一个 RESTful 服务,不过,Spring Boot 对此提供了自动化配置方案,开发者只需要添加相关依赖就能快速构建一个 RESTful 服务。

7.2 JPA 实现 REST

在 Spring Boot 中,使用 Spring Data JPA 和 Spring Data Rest 可以快速开发出一个 RESTful 应用。

7.2.1 基本实现

1. 创建项目

创建 Spring Boot 项目,添加以下依赖。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.9</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>

在 application.properties 中配置基本的数据库连接信息

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/jparestful
spring.jpa.hibernate.ddl-auto=update
spring.jpa.database=mysql
spring.jpa.properties.hibernate.dialect=org.hibernate.dialect.MySQL57Dialect
spring.jpa.show-sql=true

2. 创建实体类

@Entity(name = "t_book")
public class Book {
    
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    private String name;
    private String author;

    @Override
    public String toString() {
    
    
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                '}';
    }

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getAuthor() {
    
    
        return author;
    }

    public void setAuthor(String author) {
    
    
        this.author = author;
    }
}

3. 创建 BookRepository

public interface BookRepository extends JpaRepository<Book, Integer> {
    
    
}

继承 JpaRepository , JpaRepository 中默认提供了一些基本的操作方法,源码如下

@NoRepositoryBean
public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
    
    
    List<T> findAll();

    List<T> findAll(Sort sort);

    List<T> findAllById(Iterable<ID> ids);

    <S extends T> List<S> saveAll(Iterable<S> entities);

    void flush();

    <S extends T> S saveAndFlush(S entity);

    <S extends T> List<S> saveAllAndFlush(Iterable<S> entities);

    /** @deprecated */
    @Deprecated
    default void deleteInBatch(Iterable<T> entities) {
    
    
        this.deleteAllInBatch(entities);
    }

    void deleteAllInBatch(Iterable<T> entities);

    void deleteAllByIdInBatch(Iterable<ID> ids);

    void deleteAllInBatch();

    /** @deprecated */
    @Deprecated
    T getOne(ID id);

    /** @deprecated */
    @Deprecated
    T getById(ID id);

    T getReferenceById(ID id);

    <S extends T> List<S> findAll(Example<S> example);

    <S extends T> List<S> findAll(Example<S> example, Sort sort);
}

由这段源码可以看到,基本的增删改查、分页查询方法 JpaRepository 都提供了

4. 测试

经过如上几部,一个 RESTful 服务就构建完成了。明明什么都没写,或许这就是 Spring Boot 的魅力所在。
RESTful 的测试首先需要一个测试工具,可以直接使用浏览器中的插件,例如 Firefox 中的 RESTClient ,或者直接使用 Postman 等工具。

5. 添加测试

RESTful 服务构建成功后,默认的请求路径是实体类名小写加上后缀。
此时向数据库添加一条数据非常容易,发起一个 post 请求,请求地址为 http://localhost:8080/books
在这里插入图片描述

当添加成功后,服务端会返回刚刚添加成功的数据的基本信息以及浏览地址。

6. 查询测试

查询是 get 请求,http://localhost:8080/books,分页查询请求默认每页记录数是 20 条,页数为 0 (页码从 0 开始计),如果想修改请求页码和每页记录数,只需要在请求地址中携带相关参数即可,如查询第二页且一页10天记录:http://localhost:8080/books?page=1&size=10。另外默认还支持排序,例如想查询第二页数据,每页记录数为5,并且按照 id 倒序排列:http://localhost:8080/books?page=1&size=5&sort=id,desc
在这里插入图片描述

如果按照 id 查询,只需要在路径后追加 id 即可 http://localhost:8080/books/1
在这里插入图片描述

扫描二维码关注公众号,回复: 14467458 查看本文章

7. 修改测试

发送 PUT 请求可实现对数据的修改,对数据的修改是通过 id 进行的,因此请求路径中要有 id ,修改 id 为 1 的记录如下,http://localhost:8080/books/1
在这里插入图片描述

PUT 请求的返回结果就是被修改之后的记录

8. 删除测试

发送 DELETE 请求可以实现对数据的删除操作,删除id 为 1 的数据 :http://localhost:8080/books/1
在这里插入图片描述

DELETE 请求没有返回值,请求发送成功后 id 为 1 的数据就被删除掉了

7.2.2 自定义请求路径

默认情况下,请求路径都是实体类名小写加 s ,如果开发者想对请求路径进行重定义,只需要在 BookRepository 类上添加 @RepositoryRestResource 注解即可

@RepositoryRestResource(path = "bs",collectionResourceRel = "bs",itemResourceRel = "b")
public interface BookRepository extends JpaRepository<Book, Integer> {
    
    
}

@RepositoryRestResource 注解的 path 属性表示将所有请求路径中的 books 都改为 bs ,如 http://localhost:8080/bs;collectionResourceRel 属性表示将返回的 JSON 集合中 book 集合的 key 参数改为 bs;itemResourceRel 表示将返回的 JSON 集合中的单个 book 的 key 修改为 b
在这里插入图片描述

7.2.3 自定义查询方法

默认 的查询方法支持分页查询、排序查询以及按照 id 查询,如果开发者想按照某个属性查询,只需要在 BookRepository 类中定义相关方法并暴露出去即可

@RepositoryRestResource(path = "bs",collectionResourceRel = "bs",itemResourceRel = "b")
public interface BookRepository extends JpaRepository<Book, Integer> {
    
    
    @RestResource(path = "author",rel = "author")
    List<Book> findByAuthorContains(@Param("author") String author);
    @RestResource(path = "name",rel = "name")
    Book findByNameEquals(@Param("name") String name);
}

代码解释:

  • 自定义查询只需要在 BookRepository 中定义查询方法即可,方法定义好之后可以不添加 @RestResource 注解,默认路径就是方法名。以 findByAuthorContains 方法为例若不添加 @RestResource 注解,则默认该方法的调用路径为 http://localhost:8080/bs/search/findByAuthorContains?author=鲁迅。而加上 @RestResource(path = “author”,rel = “author”) 注解后的查询路径为 http://localhost:8080/bs/search/author?author=鲁迅
  • 用户可以直接访问 http://localhost:8080/bs/search 路径查看该实体类暴露出来了哪些查询方法,默认情况下,在查询方法展示时使用的路径是方法名,通过 @RestResource 注解中的 rel 属性可以对这里的路径进行重定义

在这里插入图片描述

7.2.4 隐藏方法

默认情况下,凡是继承了 Repository 接口(或者 Repository 的子类)的类都会被暴露出来,即开发者可执行基本的增删改查方法。以上面的 BookRepository 为例,如果开发者提供了 BookRepository 继承自 Repository ,就能执行对 Book 的基本操作,如果开发者继承了 Repository 但是又不想暴露相关操作,可做如下配置

@RepositoryRestResource(path = "bs",collectionResourceRel = "bs",itemResourceRel = "b")
public interface BookRepository extends JpaRepository<Book, Integer> {
    
    
    @Override
    @RestResource(exported = false)
    void deleteById(Integer integer);

    @RestResource(path = "author",rel = "author")
    List<Book> findByAuthorContains(@Param("author") String author);
    @RestResource(path = "name",rel = "name")
    Book findByNameEquals(@Param("name") String name);
}

@RestResource 注解的 exported 属性默认为 true ,改为 false 即可。

7.2.5 配置 CORS

默认的 RESTful 工程不需要开发者自己提供 Controller,因此添加在 Controller 的方法上的注解可以直接写在 BookRepository 上,如下

@CrossOrigin
@RepositoryRestResource(path = "bs",collectionResourceRel = "bs",itemResourceRel = "b")
public interface BookRepository extends JpaRepository<Book, Integer> {
    
    
    @Override
    @RestResource(exported = false)
    void deleteById(Integer integer);

    @RestResource(path = "author",rel = "author")
    List<Book> findByAuthorContains(@Param("author") String author);
    @RestResource(path = "name",rel = "name")
    Book findByNameEquals(@Param("name") String name);
}

此时,BookRepository 中所有的方法都支持跨域。如果只需要某一个方法支持跨域,那么将 @CrossOrigin 添加到某一个方法上即可(关于 @CrossOrigin 注解的详细用法可以参照本专栏的《四、Spring Boot 整合 Web 开发》)

7.2.6 其它配置

开发者也可以在 application.properties 中配置一些常用属性,如下

# 每页默认记录数,默认为20
spring.data.rest.default-page-size=10
# 分页查询也慢参数名,默认为page
spring.data.rest.page-param-name=page
# 分页查询记录数参数名,默认值为size
spring.data.rest.limit-param-name=size
# 分页查询排序参数名,默认值为sort
spring.data.rest.sort-param-name=sort
# 给所有请求路径都加上前缀
spring.data.rest.base-path=/api
# 添加成功时是否返回添加内容
spring.data.rest.return-body-on-create=true
# 更新成功时是否返回更新内容
spring.data.rest.return-body-on-update=true

当然,这些 XML 配置也可以配置在 Java 代码中,且代码中配置的优先级高于 application.properties 的优先级

@Configuration
public class RestConfig extends RepositoryRestConfigurerAdapter {
    
    
    @Override
    public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) {
    
    
        config.setDefaultPageSize(2)
                .setPageParamName("page")
                .setLimitParamName("size")
                .setSortParamName("sort")
                .setBasePath("/api")
                .setReturnBodyOnCreate(true)
                .setReturnBodyOnUpdate(true);
    }
}

7.3 MongoDB 实现 REST

Spring Boot 也可以结合 Spring Data MongoDB 实现快速构建 RESTful 服务

1. 创建项目

创建 Spring Boot 项目,依赖如下

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-test</artifactId>
  <scope>test</scope>
</dependency>

然后在 application.properties 中配置 MongoDB 的基本连接信息

spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=test
spring.data.mongodb.username=root1
spring.data.mongodb.password=root1
spring.data.mongodb.host=ip地址
spring.data.mongodb.port=27017

2. 创建实体类

public class Book {
    
    
    private Integer id;
    private String name;
    private String author;

    public Integer getId() {
    
    
        return id;
    }

    public void setId(Integer id) {
    
    
        this.id = id;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public String getAuthor() {
    
    
        return author;
    }

    public void setAuthor(String author) {
    
    
        this.author = author;
    }
}

3. 创建 BookRepository

public interface BookRepository extends MongoRepository<Book,Integer> {
    
    
}

如此,一个 RESTful 服务就搭建成功了。在启动项目前,记得要先启动 MongoDB 。Spring Boot 项目启动成功后,接下来的测试环节与 7.2.1 小节的第 5~8 步一致。另外,7.2.2~7.2.6 小节介绍的 Spring Data Rest 配置在这里一样适用。

猜你喜欢

转载自blog.csdn.net/GXL_1012/article/details/126178282