# CRUD 接口

# 快速上手

fly-rest模块能够快速生成指定实体的标准Restful风格的基础CRUD接口,具体步骤为:

  1. Controller上添加@Crud注解,使用注解中的entityClass属性指定实体类;
  2. Controller实现CRUD interface

简单示例如下:

@RestController
@RequestMapping("/news")
@Crud(entityClass = NewsEntity.class)
public class NewsEntityController implements FlexibleCrudCreate {}

FlexibleCrudCreate对应创建接口,最终生成的接口请求类型及路径为:

POST /news

若想约定创建接口的请求参数及返回数据格式,可以改为实现CrudCreateCustomized interface,更多使用可见下文。

# @Crud

@Crud注解配置在Controller上,能够影响Controller下接口的参数:如指定entityClass后,接口参数CrudContext中保存的entityType为对应的实体;指定filtersDefault后,影响QueryBase参数的filters属性默认值。从而在实现不同的CRUD interfaces后,生成指定实体的操作接口。

@RestController
@RequestMapping("/news")
@Crud(entityClass = NewsEntity.class, filtersDefault = "name eq '1'")
public class NewsEntityController {}
注解属性 说明 类型 默认值
entityClass 必填CRUD操作对应的实体类 Class<?> -
idVariable 单数据操作接口路径的主键占位符名称,如修改接口/news/{id}中的{id} String id
filtersDefault QueryBase接口参数的默认filters表达式 String -
orderByDefault QueryBase接口参数的默认orderBy表达式 String -
condition QueryBase接口参数的conditions表达式 String -
queryParameters 使用参考@Parameters QueryParameter[] -

# 可实现接口

目前可实现接口有:

以下接口都处于fly.rest.data.crud.operation包中,CU分别为传入的创建和更新对象类型,R为返回类型,示例中{path}表示当前controller的路径。

# 创建

下列接口生成API均为:[POST] /{controller-path},只是接收参数和返回类型有所区别。

接口 说明 返回类型
CrudCreate<R> 基础创建,不需指定接收参数,需指定返回类型 R
CrudCreateCustomized<C, R> CrudCreate基础上还需指定接收的参数C R
FlexibleCrudCreate 不需指定接收参数且返回类型为Record(一般为实体的所有字段) Record

# 查询

接口 说明 生成 API 返回类型
CrudExists 根据过滤条件判断数据是否存在 [GET] /{controller-path}/exists boolean
CrudFind<R> 单条数据查询 [GET] /{controller-path}/{id} R
CrudQuery<R> 列表查询 [GET] /{controller-path} Page<R>
FlexibleCrudFind CrudFind基础上,默认返回类型为Record [GET] /{controller-path}/{id} Record
FlexibleCrudQuery CrudQuery基础上,默认返回类型为Record [GET] /{controller-path} Page<Record>
  • CrudQuery生成的查询API接收参数为Query(详细使用可见Query 参数规范)。

# 更新

接口 说明 生成 API 返回类型
CrudUpdate 基础更新,不需指定创建对象类型,自动获取指定实体的属性 [PATCH] /{controller-path}/{id} void
CrudUpdateCustomizedByPut<U> CrudUpdate不同需指定接收的对象类型 [PUT] /{controller-path}/{id} void

# 删除

接口 说明 生成 API 返回
CrudDelete 基础删除 [DELETE] /{controller-path}/{id} void

# 组合使用

针对常用场景,设计了若干组合快速引入增删改查接口:

接口 说明
CrudAll<R> 包含所有基础的增删改查接口
CrudAllRead<R> 包含所有查询接口(单条数据、列表查询)
CrudAllWithoutCreate<R> 除创建外的所有基础接口
CrudAllWithoutCreateUpdate<R> 除创建/更新外的所有基础接口
CrudAllWithoutUpdate<R> 除更新外的所有基础接口
FlexibleCrudAll CrudAll基础上,所有接口返回对象类型为Record
FlexibleCrudAllWithoutCreate CrudAllWithoutCreate基础上,所有接口返回对象类型为Record
FlexibleCrudAllWithoutCreateUpdate CrudAllWithoutCreateUpdate基础上,所有接口返回对象类型为Record
FlexibleCrudAllWithoutUpdate CrudAllWithoutUpdate基础上,所有接口返回对象类型为Record
FlexibleCrudRead CrudAllRead基础上,多继承了CrudExists接口,所有接口返回对象类型为Record

以上接口内部方法具体参数类型,可借助源码深入了解及使用。

# 拦截器

目前提供Controller和全局级别的增删改查拦截(Controller级别拦截方法优先执行),需实现任一接口:

接口 说明
CrudCreateInterceptor 拦截创建操作
CrudUpdateInterceptor 拦截更新操作
CrudFindInterceptor 拦截单数据查询操作
CrudQueryInterceptor 拦截列表查询操作
CrudDeleteInterceptor 拦截删除操作
CrudAllInterceptor 上列增删改查拦截的组合

接口内方法名命名规则为:pre前缀为在操作前调用;post前缀为操作后调用。均为默认实现,实现接口后,需要自行重写方法。

# Controller 级别

  • Controller实现接口,对该Controller的所有api进行拦截
import fly.rest.data.crud.interceptor.CrudCreateInterceptor;

@RestController
@RequestMapping("/entity")
@Crud(entityClass = Entity.class)
public class EntityController implements CrudCreate<EntityCreateParams, Entity>, CrudCreateInterceptor {
    
    // 创建前调用
    @Override
    public void preCreate(CrudContext context, Map<String, Object> fields) {
        // 重写方法
    }
    
}

# 全局级别

创建一个类,实现接口:

import fly.rest.data.crud.interceptor.CrudCreateInterceptor;
import fly.rest.data.crud.interceptor.CrudUpdateInterceptor;

public class GlobalCrudInterceptor implements CrudCreateInterceptor, CrudUpdateInterceptor {
    
    // 所有实体创建前调用
    @Override
    public void preCreate(CrudContext context, Map<String, Object> fields) {
        // 重写方法
    }
    
    // 所有实体更新前调用
    @Override
    public void preUpdate(CrudContext context, Object params, Map<String, Object> idOrKeyWithFilters, Map<String, Object> fields) {
        // 重写方法
    }
    
}

使用Spring的方式注入RestCrudConfigurer,调用add*Interceptor()(这里的*可以为Create/Update/Find/Query/Delete,对应拦截器接口的操作类型)方法传入对象,注册为全局拦截器:

import fly.rest.data.crud.RestCrudConfigurer;

@SpringBootApplication
public class Application {
    
    @Autowired
    protected void configureInterceptors(RestCrudConfigurer configurer) {
        GlobalCrudInterceptor global = new GlobalCrudInterceptor();
        
        // 注册
        configurer.addCreateInterceptor(global)
            .addUpdateInterceptor(global);
    }
    
    // 忽略非关键代码
    
}

# 默认查询条件

通过注解的方式,在Controller级别或API级别设置默认查询条件,默认查询条件最终会赋值于符合条件的方法参数中。

符合条件的方法参数有:

  1. 参数实现fly.core.data.query.Querable接口;
  2. 参数继承于fly.core.data.query.QueryBase类。

本小节中介绍的注解包路径为fly.core.web.data.annotation,非该包内的注解会另外注明。

# 根据请求参数指定

  1. @QueryParameter
  • 作用范围:方法

一般在API方法上使用,根据请求参数指定查询条件,需要用到@Condition注解,设当传入exists请求参数时,值为true与值为false时默认添加的条件不同:

@GetMapping("")
@QueryParamter(name = "exists", type = Boolean.class, 
               conditions = {
                   @Condition(onValue = "true",
                              expression = "exists (...)"),
                   @Condition(onValue = "false",
                              expression = "(...) or exists (...)")
               })
public Page<Entity> query(QueryBase query) {
    // 获取生效的默认查询条件
    query.getConditions();
    
    return dao.createQuery(Entity.class).page(query);
}
注解属性 说明 类型 默认值
name ※ 必填请求参数名 String -
type 请求参数类型 Class<?> String.class
desc 请求参数描述 String -
conditions 请求参数值及对应的过滤条件,详细配置属性见下文 Condition[] -

@Condition配置属性:

注解属性 说明 类型 默认值
onValue 参数对应的值 String -
matchIfMissing 指定如果未设置参数,条件是否应匹配 boolean false
expression SQL过滤表达式 String -
  1. @QueryParameters
  • 作用范围:方法

API方法上使用,为该API定义多个@QueryParameter

@GetMapping("")
@QueryParameters({
	@QueryParamter(name = "exists", type = Boolean.class, 
                   conditions = {
                       @Condition(onValue = "true",
                                  expression = "exists (...)"),
                       @Condition(onValue = "false",
                                  expression = "(...) or exists (...)")
                   })
})
public Page<Entity> query(QueryBase query) {...}

# 数据过滤

@FiltersDefault

  • 作用范围:方法

API方法上使用,为该API符合条件的参数里添加默认过滤条件,优先级最高

@GetMapping("")
@FiltersDefault("enabled eq true")
public Page<Entity> query(QueryBase query) {
    // 获取生效的默认查询条件
    query.getFilters();
    
    return dao.createQuery(Entity.class).page(query);
}

# 数据排序

@OrderByDefault

  • 作用范围:方法

API方法上使用,为该API符合条件的参数里添加默认排序条件,优先级最高

@GetMapping("")
@OrderByDefault("name desc")
public Page<Entity> query(QueryBase query) {
    // 获取生效的默认查询条件
    query.getOrderBy();
    
    return dao.createQuery(Entity.class).page(query);
}

# 统一配置

@QuerySettings

  • 作用范围:类

一般在Controller类上使用,该类下的所有API均添加默认查询条件:

@RestController
@RequestMapping("/entity")
@QuerySettings(filtersDefault = "enabled = 1")
public class EntityController {}
注解属性 说明 类型 默认值
filtersDefault 默认SQL过滤表达式,相当于@FiltersDefault注解,但优先级较低 String -
orderByDefault 默认SQL排序表达式,相当于@OrderByDefault注解,但优先级较低 String -
parameters 使用参考@Parameters QueryParameter -
顶部