# CRUD 接口
# 快速上手
fly-rest模块能够快速生成指定实体的标准Restful风格的基础CRUD接口,具体步骤为:
- 在
Controller上添加@Crud注解,使用注解中的entityClass属性指定实体类; 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包中,C和U分别为传入的创建和更新对象类型,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级别设置默认查询条件,默认查询条件最终会赋值于符合条件的方法参数中。
符合条件的方法参数有:
- 参数实现
fly.core.data.query.Querable接口; - 参数继承于
fly.core.data.query.QueryBase类。
本小节中介绍的注解包路径为
fly.core.web.data.annotation,非该包内的注解会另外注明。
# 根据请求参数指定
@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 | - |
@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 | - |