本篇要点

  • Spring Data REST的基本介绍。
  • SpringBoot快速构建restful风格接口。

Spring Data REST概述

REST Web服务已经成为Web上应用程序集成的第一大手段。 REST的核心是定义一个包含与客户端进行交互资源的系统。 这些资源以超媒体驱动的方式实现。

Spring MVC和Spring WebFlux各自提供了构建REST服务的坚实基础。 但是,即使为multi-domain对象系统实现最简单的REST Web服务原则也可能很繁琐,并且会导致大量样板代码。

Spring Data REST旨在解决这个问题,它建立在Spring Data存储库之上,并自动将其导出为REST资源,客户端可以轻松查询并调用存储库本身暴露出来的接口。

SpringBoot快速构建restful风格接口

SpringBoot构建Spring Data REST是相当方便的,因为自动化配置的存在,spring-boot-starter-data-rest可以让你不需要写多少代码,就能轻松构建一套完整的rest应用。

除此之外,你需要引入数据存储的依赖,它支持SpringData JPA、Spring Data MongoDB等,这里就使用JPA啦。正好我们前几篇介绍过JPA的简单使用:SpringBoot整合Spring Data JPA

SpringBoot使用快速构建restful应用,学废了吗

创建项目,导入依赖

        <!--jpa-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!--restful-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>
        <!--web-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

yml配置

server:
  port: 8081
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/restful?serverTimezone=GMT%2B8
    username: root
    password: 123456
    hikari:
      maximum-pool-size: 20
      minimum-idle: 5
  jpa:
    database: mysql
    #在建表的时候,将默认的存储引擎切换为 InnoDB
    database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
    # 配置在日志中打印出执行的 SQL 语句信息。
    show-sql: true
    # 配置指明在程序启动的时候要删除并且创建实体类对应的表。
    hibernate:
      ddl-auto: update

定义实体类

@Entity(name = "t_user")
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String username;
    private String password;

    @Column(length = 20)
    private Integer age;
}

定义Repository接口

public interface UserDao extends JpaRepository<User, Long> {
}

到这里为止,其实可以发现,和JPA文章没啥差异,除了多引入了一个rest依赖。ok,启动项目,先把表生成了再说。

启动项目,我们就会发现JPA已经为我们将表结构创建完成,并且,一个基于Restful风格的增删改查应用也已诞生,我们可以使用接口测试工具,进行测试。

测试Restful接口

默认的请求路径是 类名首字母小写+后缀s,这里就是users。

测试添加功能

POST: http://localhost:8081/users
{
    "username": "summerday",
    "password": "123456",
    "age": 18
}

添加成功之后,返回信息如下:

{
  "username": "summerday",
  "password": "123456",
  "age": 18,
  "_links": {
    "self": {
      "href": "http://localhost:8081/users/1"
    },
    "user": {
      "href": "http://localhost:8081/users/1"
    }
  }
}

测试删除功能

DELETE : http://localhost:8081/users/1
// 删除成功之后返回删除的 id = 1

测试修改功能

PUT : http://localhost:8081/users/2
{
    "username": "summerday111",
    "password": "123456111",
    "age": 181
}

同样的,修改成功,将对应id为2的信息改为传入信息,并返回更新后的信息。

{
  "username": "summerday111",
  "password": "123456111",
  "age": 181,
  "_links": {
    "self": {
      "href": "http://localhost:8081/users/2"
    },
    "user": {
      "href": "http://localhost:8081/users/2"
    }
  }
}

测试根据id查询

GET : http://localhost:8081/users/3

测试分页查询

GET : http://localhost:8081/users

分页查询结果:

{
  "_embedded": {
    "users": [
      {
        "username": "summerday111",
        "password": "123456111",
        "age": 181,
        "_links": {
          "self": {
            "href": "http://localhost:8081/users/2"
          },
          "user": {
            "href": "http://localhost:8081/users/2"
          }
        }
      },
      {
        "username": "summerday",
        "password": "123456",
        "age": 18,
        "_links": {
          "self": {
            "href": "http://localhost:8081/users/3"
          },
          "user": {
            "href": "http://localhost:8081/users/3"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8081/users"
    },
    "profile": {
      "href": "http://localhost:8081/profile/users"
    }
  },
  "page": {
    "size": 20,
    "totalElements": 2,
    "totalPages": 1,
    "number": 0
  }
}

测试分页+排序

GET : http://localhost:8081/users?page=0&size=1&sort=age,desc

第一页,每页size为1的记录,按age逆序。

{
  "_embedded": {
    "users": [
      {
        "username": "summerday111",
        "password": "123456111",
        "age": 181,
        "_links": {
          "self": {
            "href": "http://localhost:8081/users/2"
          },
          "user": {
            "href": "http://localhost:8081/users/2"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8081/users?page=0&size=1&sort=age,desc"
    },
    "self": {
      "href": "http://localhost:8081/users?page=0&size=1&sort=age,desc"
    },
    "next": {
      "href": "http://localhost:8081/users?page=1&size=1&sort=age,desc"
    },
    "last": {
      "href": "http://localhost:8081/users?page=1&size=1&sort=age,desc"
    },
    "profile": {
      "href": "http://localhost:8081/profile/users"
    }
  },
  "page": {
    "size": 1,
    "totalElements": 2,
    "totalPages": 2,
    "number": 0
  }
}

定制查询

自定义查询接口

public interface UserDao extends JpaRepository<User, Long> {

    List<User> findUsersByUsernameContaining(@Param("username")String username);
}

访问:http://localhost:8081/users/search,查询自定义接口。

{
  "_links": {
    "findUsersByUsernameContaining": {
      "href": "http://localhost:8081/users/search/findUsersByUsernameContaining{?username}",
      "templated": true
    },
    "self": {
      "href": "http://localhost:8081/users/search"
    }
  }
}

测试一下这个方法:

GET : http://localhost:8081/users/search/findUsersByUsernameContaining?username=111

{
  "_embedded": {
    "users": [
      {
        "username": "summerday111",
        "password": "123456111",
        "age": 181,
        "_links": {
          "self": {
            "href": "http://localhost:8081/users/2"
          },
          "user": {
            "href": "http://localhost:8081/users/2"
          }
        }
      }
    ]
  },
  "_links": {
    "self": {
      "href": "http://localhost:8081/users/search/findUsersByUsernameContaining?username=111"
    }
  }
}

自定义接口名

public interface UserDao extends JpaRepository<User, Long> {
    //rel 表示接口查询中,这个方法的 key 
    //path 表示请求路径
    @RestResource(rel = "auth", path = "auth")
    User findByUsernameAndPassword(@Param("name") String username, @Param("pswd") String password);
}

继续查询自定义的接口:

    "auth": {
      "href": "http://localhost:8081/users/search/auth{?name,pswd}",
      "templated": true
    }

测试一下:

GET : http://localhost:8081/users/search/auth?name=summerday&pswd=123456

设置接口对前端隐藏

    @Override
    @RestResource(exported = false)
    void deleteById(Long aLong);

定义生成JSON字符串的相关信息

@RepositoryRestResource(collectionResourceRel = "userList",itemResourceRel = "u",path = "user")
public interface UserDao extends JpaRepository<User, Long> {
}

此时路径名为/user:

GET : http://localhost:8081/user/2

{
  "username": "summerday111",
  "password": "123456111",
  "age": 181,
  "_links": {
    "self": {
      "href": "http://localhost:8081/user/2"
    },
    "u": {
      "href": "http://localhost:8081/user/2"
    }
  }
}

其他配置属性

Spring Data REST其他可配置的属性,通过spring.data.rest.basePath=/v1的形式指定。

属性描述basePaththe root URIdefaultPageSize每页默认sizemaxPageSizepageParamName配置分页查询时页码的 key,默认是 pagelimitParamName配置分页查询时每页查询页数的 key,默认是sizesortParamName配置排序参数的 key ,默认是 sortdefaultMediaType配置默认的媒体类型returnBodyOnCreate添加成功时是否返回添加记录returnBodyOnUpdate更新成功时是否返回更新记录

如果觉得本文对你有帮助,可以点赞关注支持一下