简化RESTful开发,Spring Data REST让你少掉发

1 前言

Springboot + Spring MVC 大大简化了 Web 应用的 RESTful 开发,而 Spring Data REST 更简单。 Spring Data REST 是建立在 Data Repository 之上的,它能直接把 resositoryHATEOAS 风格暴露成 Web 服务,而不需要再手写 Controller 层。

HATEOAS ,即 Hypermedia as the Engine of Application State ,它是一种更成熟的 REST 模型,在资源的表达中包含了链接信息,客户端可以根据链接来发现可执行的动作。

Spring Data REST 支持 Spring Data JPASpring Data MongoDBSpring Data Neo4jSpring Data GenFireSpring Data Cassandra ,这里选择大家比较熟悉的 JPA

2 举个例子

我们用例子来感受一下吧。

2.1 创建项目

我们通过 Spring Initializr 来快速创建 Springboot 项目。选中的依赖组件如下:

  • (1) Spring Web :提供 Web 服务;
  • (2) Rest Repositories :提供 Spring Data REST 的支持;
  • (3) Spring Data JPA :通过 JPA 提供 Repository 方式的数据访问;
  • (4) H2 DatabaseH2 数据库,为了方便简洁,使用该数据库。

导入后对应的 pom.xml 中依赖如下:

  org.springframework.boot
  spring-boot-starter-web


  org.springframework.boot
  spring-boot-starter-data-jpa


  org.springframework.boot
  spring-boot-starter-data-rest


  com.h2database
  h2
  runtime

2.2 实体类

创建一个实体类 User ,如下所示:

package com.pkslow.rest.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class User {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Integer id;
    private String name;
    private Integer age;
    private String email;
  
  //getter & setter
}

2.3 Repository接口定义

定义 Repository 接口用于操作数据库,如下所示:

package com.pkslow.rest.repo;

import com.pkslow.rest.entity.User;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

@RepositoryRestResource(path = "user")
public interface UserRepository extends CrudRepository {
}

注解 RepositoryRestResourceData REST 用于暴露 Repositorypath 为访问路径,设置为 user ,则访问地址为 http://localhost:8080/user

2.4 启动访问

准备好以上代码,直接启动 Springboot 应用即可,我们把端口设置为 8080 ,访问如下:

我们用 Postman 做一个基本操作。

新增:

查询:

通过主键 ID 查询:

修改:

删除:

不难发现,返回的 Json 都带有链接,这就是 HATEOAS 风格。

3 更多探索

3.1 分页及排序功能

可以快速实现分页及排序功能,只需要把 Repository 的父接口改为 PagingAndSortingRepository 即可,如下所示:

@RepositoryRestResource(path = "user")
public interface UserRepository extends PagingAndSortingRepository {
}

其实就是多了两个方法 findAll(Sort var1)findAll(Pageable var1) ,如下所示:

public interface PagingAndSortingRepository extends CrudRepository {
    Iterable findAll(Sort var1);

    Page findAll(Pageable var1);
}

查询 http://localhost:8080/user?page=1&size=2&sort=id,desc ,表示查询第二页,每页2条记录,以 ID 倒序展示。如下:

{
  "_embedded": {
    "users": [
      {
        "name": "pkslow.com",
        "age": 18,
        "email": "pkslow@pkslow.com",
        "_links": {
          "self": {
            "href": "http://localhost:8080/user/33"
          },
          "user": {
            "href": "http://localhost:8080/user/33"
          }
        }
      },
      {
        "name": "pkslow.com",
        "age": 18,
        "email": "pkslow@pkslow.com",
        "_links": {
          "self": {
            "href": "http://localhost:8080/user/32"
          },
          "user": {
            "href": "http://localhost:8080/user/32"
          }
        }
      }
    ]
  },
  "_links": {
    "first": {
      "href": "http://localhost:8080/user?page=0&size=2&sort=id,desc"
    },
    "prev": {
      "href": "http://localhost:8080/user?page=0&size=2&sort=id,desc"
    },
    "self": {
      "href": "http://localhost:8080/user?page=1&size=2&sort=id,desc"
    },
    "next": {
      "href": "http://localhost:8080/user?page=2&size=2&sort=id,desc"
    },
    "last": {
      "href": "http://localhost:8080/user?page=17&size=2&sort=id,desc"
    },
    "profile": {
      "href": "http://localhost:8080/profile/user"
    }
  },
  "page": {
    "size": 2,
    "totalElements": 35,
    "totalPages": 18,
    "number": 1
  }
}

可以发现 page 是从 0 开始的, 1 表示第二页;返回结果还提供了第一页、上一页、本页、下一页、最后一页的链接;以及分页信息。

3.2 事件监听

REST 提供了8个基于 Repository 的事件,如下:

BeforeCreateEvent
AfterCreateEvent
BeforeSaveEvent
AfterSaveEvent
BeforeLinkSaveEvent
AfterLinkSaveEvent
BeforeDeleteEvent
AfterDeleteEvent

添加一个自定义事件如下:

package com.pkslow.rest.event;

import com.pkslow.rest.entity.User;
import org.springframework.data.rest.core.event.AbstractRepositoryEventListener;
import org.springframework.stereotype.Component;

@Component
public class PkslowEventListener extends AbstractRepositoryEventListener {

    @Override
    public void onBeforeCreate(User entity) {
        System.out.println("pkslow creating:" + entity);
    }

    @Override
    public void onBeforeSave(User entity) {
        System.out.println("pkslow saving:" + entity);
    }

    @Override
    public void onAfterDelete(User entity) {
        System.out.println("pkslow deleted:" + entity);
    }
}

分别执行了增加、修改、删除后,日志如下:

pkslow creating:User{id=null, name='pkslow.com', age=18, email='pkslow@pkslow.com'}
pkslow saving:User{id=32, name='pkslow.com', age=20, email='pkslow@pkslow.com'}
pkslow deleted:User{id=14, name='pkslow.com', age=18, email='pkslow@pkslow.com'}

说明事件成功执行,结合这个功能,可以实现很多业务逻辑,如删除后记录操作日志,并删除其它相关数据。

3.3 路径

默认基础路径是 / ,可以通过 spring.data.rest.base-path=api 进行配置,这样就变成了 localhost:8080/api/user

4 总结

本文介绍了 Spring Data REST ,可以方便大家进行 RESTful 服务开发。但据了解,项目中使用的并不多,简单学习一下,不失是一种了解 Spring 全家桶及架构理念的方式。

参考文档:

官方文档

欢迎关注微信公众号< 南瓜慢说 >,将持续为你更新…