• 七、构建 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.bootgroupId>
      <artifactId>spring-boot-starter-data-jpaartifactId>
    dependency>
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-data-restartifactId>
    dependency>
    <dependency>
      <groupId>com.alibabagroupId>
      <artifactId>druidartifactId>
      <version>1.1.9version>
    dependency>
    <dependency>
      <groupId>mysqlgroupId>
      <artifactId>mysql-connector-javaartifactId>
      <scope>runtimescope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41

    3. 创建 BookRepository

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

    继承 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42

    由这段源码可以看到,基本的增删改查、分页查询方法 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
    在这里插入图片描述

    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> {
    }
    
    • 1
    • 2
    • 3

    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    代码解释:

    • 自定义查询只需要在 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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    @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);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    此时,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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    当然,这些 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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    7.3 MongoDB 实现 REST

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

    1. 创建项目

    创建 Spring Boot 项目,依赖如下

    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-data-mongodbartifactId>
    dependency>
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-data-restartifactId>
    dependency>
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-testartifactId>
      <scope>testscope>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后在 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    3. 创建 BookRepository

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

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

  • 相关阅读:
    每个文件夹名称空格中添加文字重命名方法
    Qt扫盲-Qt Designer 设计师使用总结
    uni-app报错“本应用使用HBuilderX x.x.x 或对应的cli版本编译,而手机端SDK版本是x.x.x不匹配的版本可能造成应用异常”
    类和对象(1):类,对象,this指针
    Java使用opencv实现人脸识别、人脸比对
    Spring Cloud 微服务架构下的 WebSocket 解决方案
    GoogLeNet的不同版本
    图解TCP/IP(第五版)&& 计算机网络 -- 学习笔记和读后感(学习补充中~~~)
    vin图像识别易语言代码
    申报消防设施设计乙级资质关于财务审计报告的要求
  • 原文地址:https://blog.csdn.net/GXL_1012/article/details/126178282