lazy-cat是基于spring-jdbcTemplate封装的orm框架
<dependency>
<groupId>cool.lazy-cat</groupId>
<artifactId>orm-core-spring-boot-starter</artifactId>
<version>2.4.0</version>
</dependency>
启动类增加注解@PojoScan(value = {"xxx.xxx.**"}, excludes = {})
指定包下标注@Pojo的类将被lazy-cat管理 除此之外可以在配置文件中指定扫描路径和排除路径
在配置文件指定时将忽略启动类中的注解
一个例子:
@Pojo(table = @Table(schema = "app_core", tableName = "acc_user"))
public class User {
private String id;
private String name;
private Sex sex;
private Office office;
private List<UserDir> userDirList;
@Id(idGenerator = UUIdGenerator.class)
@Column(updatable = false, sort = 1, name = "acc_user_id")
public String getId() {
return id;
}
@Column(sort = 10)
public String getName() {
return name;
}
/**
* 内置的枚举类型转换器 查询、持久化时自动转换类型.
*/
@Column(sort = 40, typeConverter = SimpleEnumTypeConverter.class)
public Sex getSex() {
return sex;
}
@OneToMany(condition = {@On(foreignFiled = "id", targetFiled = "userId")},
cascadeScope = {"userDirList.userFileList.fileContentList"},
ignoreFields = {"userDirList.userFileList.fileContentList.suffix"},
sort = 10)
public List<UserDir> getUserDirList() {
return userDirList;
}
@ManyToOne(condition = @On(foreignFiled = "department", targetFiled = "id"), sort = 30, cascadeLevel = 2)
public Office getOffice() {
return office;
}
}
对于数据库表存在的字段应加注@Column注解 默认将字段驼峰转换下划线映射数据库字段
以pojo字段的getter方法标注的注解为准 请注意
对于关系映射对象, lazy-cat提供三个注解
在查询、增删改时根据 作用域 自动更新关系映射对象 也可以通过参数来控制是否更新映射对象的值
所谓 作用域 是指注解中配置的cascadeScope或者cascadeLevel参数, 优先取cascadeScope参数
cascadeScope模式更加灵活控制加载的嵌套对象, 在对象结构复杂的情况下 cascadeLevel可能造成性能问题
lazy-cat提供了BaseRepository万能类, 可以操作所有被lazy-cat管理的pojo
@Autowired
BaseRepository baseRepository;
public void test() {
List<User> ul1 = baseRepository.queryByIds(User.class, Arrays.asList(1, 2, 3));
User u2 = baseRepository.queryById(User.class, 133);
// 如果返回了多条数据,将抛出异常
User w = baseRepository.querySingle(new SearchParamImpl<>(User.class).setCondition(Condition.eq("name", "王五")));
PageResult<User> upr = baseRepository.queryPage(new SearchParamImpl<>(User.class)
.setCondition(Condition.eq("office.name", "A公司").and(Condition.lt("age", 35))));
// 更新或保存 默认更新映射对象 判断对象是否为新记录可重写isNewRecord()方法
baseRepository.save(ul1);
// 更新或保存 但不更新映射对象
baseRepository.save(ul1, false);
// 删除 默认删除映射对象
baseRepository.delete(ul1);
// 删除 担不删除映射对象
baseRepository.delete(ul1, false);
// 根据条件删除
baseRepository.deleteByCondition(User.class, Condition.eq("name", "王五").or(Condition.gte("age", 99)));
// 根据id删除
baseRepository.deleteByIds(User.class, Arrays.asList(1, 2, 3));
// 逻辑删除 默认逻辑删除映射对象 如果类没有逻辑删除字段 则什么也不做
baseRepository.logicDelete(ul1);
// 逻辑删除 但不逻辑删除映射对象 如果类没有逻辑删除字段 则什么也不做
baseRepository.logicDelete(ul1, false);
// 推断删除 如果类具有逻辑删除字段则执行逻辑删除 否则物理删除 同时更新映射对象
baseRepository.deleteByInfer(ul1);
// 同上 但不更新映射对象
baseRepository.deleteByInfer(ul1, false);
}
在查询操作时可以动态指定作用域
但增删改操作时只能使用注解声明的作用域
List<String> searchScope = Arrays.asList("office.parent.parent.childrenList",
"userDirList.userFileList.fileContentList.dir", "ftpDirList.ftpFileList.dir");
Condition condition = Condition.in("office.name", Arrays.asList("A公司", "B公司")).and(Condition.eq("sex", "女"));
// 忽略查询的字段
Ignorer ignorer = Ignorer.build("office.level", "sex", "userDirList.userFileList.fileContentList.suffix");
List<User> u = baseRepository.query(new SearchParamImpl<>(User.class).setSearchScope(searchScope).setIgnorer(ignorer).setCondition(condition));
事务控制层面提供了泛型接口BaseService<Object>
<dependency>
<groupId>cool.lazy-cat</groupId>
<artifactId>orm-api-spring-boot-starter</artifactId>
<version>2.4.0</version>
</dependency>
orm-api项目提供了api方法自动映射的功能 依赖了orm-core
api映射需要一个根入口 默认为lazy-cat 你可以配置ApiConfig的apiPath属性以修改
一个例子:
// api请求路径 = api根路径 + '/' + nameSpace + '/' + path
@ApiPojo(nameSpace = "user", entry = {
@Entry(path = "selectPage", api = QueryPageApiEntry.class, methods = {HttpMethod.POST}),
@Entry(path = "select", api = QueryApiEntry.class),
@Entry(path = "save", api = SaveApiEntry.class),
@Entry(path = "saveForce", api = SaveCascadeApiEntry.class),
@Entry(path = "delete", api = RemoveApiEntry.class, methods = HttpMethod.POST),
@Entry(path = "delete", api = RemoveApiEntry.class, methods = {HttpMethod.DELETE, HttpMethod.GET}),
@Entry(path = "deleteForce", api = RemoveCascadeApiEntry.class)
})
@Pojo(table = @Table(schema = "app_core", tableName = "acc_user"))
public class User {
}
此时, 请求http://{server:port}/lazy-cat/user/select 即可触发QueryApiEntry接口
前提是这个类必须是一个lazy-cat-orm-core扫描管理的类
你可以使用@ApiQueryFilter注解标注查询条件:
@Column(sort = 10)
// 查询条件
@ApiQueryFilter(In.class)
public String getName() {
return name;
}
@Column(validator = @Validator(type = CommonValidator.class, notNull = true, parameter = {@Parameter(name = CommonValidator.VALIDATE_INFO_KEY, value = ValidateConstant.VALIDATE_HUMAN_AGE_KEY)}), sort = 20)
// 查询条件
@ApiQueryFilter(Equals.class)
public Integer getAge() {
return age;
}
http请求参数(QueryInfo.class):
{
"pageSize": 50000,
"startIndex": 0,
"params": {
"name": [
"金克拉",
"艾莉丝"
]
},
"orderFields": [
"createDate"
],
"ignoreFields": [],
"asc": true
}
orm-api提供了7个接口
接口名 | 参数 | 代理的api方法 |
---|---|---|
QueryApiEntry | QueryInfo.class | commonApiService.select(queryInfo) |
QueryPageApiEntry | QueryInfo.class | commonApiService.selectPage(queryInfo) |
RemoveApiEntry | List<Object> |
baseService.deleteByInfer(dataList, false) |
RemoveCascadeApiEntry | List<Object> |
baseService.deleteByInfer(dataList, true) |
RemoveByIdsApiEntry | List<String> |
baseService.deleteByIdsAndInfer(pojoType, ids) |
SaveApiEntry | List<Object> |
baseService.save(dataList, false) |
SaveCascadeApiEntry | List<Object> |
baseService.save(dataList, true) |
你也可以扩展自定义的api代理 自定义请求参数、响应参数、以及真正执行业务逻辑的bean
除了使用注解配置api请求路径映射之外 orm-api还提供了基于配置文件配置api参数的方式
cool:
lazy-cat:
servlet:
# 设置api请求根路径
api-path: api
# 声明使用配置文件的方式
api-pojo-subject-registry-instance: cool.lazy.cat.orm.api.manager.provider.ConfigFileApiPojoSubjectProvider
# 配置api
api-entries:
- pojo-type: com.jason.test.pojo.mysql.User
name-space: user
properties:
- path: select
api: cool.lazy.cat.orm.api.web.entrust.method.QueryApiEntry
allow-methods: POST,GET
query-filters:
# 字段查询条件
- field: name
condition: cool.lazy.cat.orm.core.jdbc.sql.condition.type.In
# 字段查询条件
- field: age
condition: cool.lazy.cat.orm.core.jdbc.sql.condition.type.Equals
- pojo-type: com.jason.test.pojo.mysql.Office
name-space: officeTest
properties:
- path: selectPage
api: cool.lazy.cat.orm.api.web.entrust.method.QueryApiEntry
allow-methods: POST,GET
query-filters:
# 字段查询条件
- field: name
condition: cool.lazy.cat.orm.core.jdbc.sql.condition.type.In
配置: cool.lazy.cat.orm.core.jdbc.JdbcConfig
你需要先了解这些注解的功能和基本工作方式:
cool.lazy.cat.orm.annotation.*
根入口为cool.lazy.cat.orm.core.base.repository.BaseRepository. baseRepository提供了丰富的api供使用
在baseRepository之上扩展了service层面:
cool.lazy.cat.orm.core.base.service.BaseService、cool.lazy.cat.orm.core.base.service.CommonService
service层使用了编程式事务控制 org.springframework.transaction.support.TransactionTemplate
如果你不喜欢这样的事务控制方式 可以绕过service层面 直接操作baseRepository并自定义你的事务控制方式
其中baseSerive具备类泛型属性 与Pojo类型强绑定. commonService所有方法均为泛型方法, 可作为万能类型的查询方法调用
也可以注入Bean BaseService<Object>的形式, 通过泛型强转 也能将BaseService<Object>作为万能类型的持久化方式
具体可以参考example项目中test项目的示例
需要扩展: cool.lazy.cat.orm.core.jdbc.adapter.mapper.JdbcOperationHolderMapper
和cool.lazy.cat.orm.core.jdbc.adapter.mapper.DynamicNameMapper
并自定义DataSource、PlatformTransactionManager对象的构建
可参考example项目中 com.jason.test.component.datasource包下的示例
@see cool.lazy.cat.orm.core.jdbc.sql.dialect.Dialect
@see cool.lazy.cat.orm.core.jdbc.sql.dialect.function.FunctionHandler
@see cool.lazy.cat.orm.core.jdbc.sql.condition.SqlCondition、
cool.lazy.cat.orm.core.jdbc.adapter.mapper.ConditionTypeMapper
需要留意cool.lazy.cat.orm.core.jdbc.sql.condition.type包
和cool.lazy.cat.orm.core.jdbc.constant.ConditionConstant的CONDITION_TYPE_CACHE属性
可以查看example项目中的com.jason.test.component.conditiontype包下的示例
@see cool.lazy.cat.orm.base.component.CommonComponent
@see cool.lazy.cat.orm.core.jdbc.component.SpecialColumn
假设入口为service:
- service 判断当前的操作类型和pojo类型 适配对应的操作数据库源 并得到对应数据库的事务支持 将当前数据库操作信息放入上下文 开启事务 ↴
- baseRepository 组装数据... 一系列逻辑判断、赋值 ↴
- sqlExcutor 从上下文中获取数据库操作信息 如果没有 则再次适配并放入上下文 ↴
- sqlPrinter 打印sql及参数适配 ↴
- sqlExcutor 执行扩展组件、sql拦截器、并最终执行sql返回结果 释放上下文信息 ↴
- service 由spring控制事务提交或回滚 ↴
- finished
配置: cool.lazy.cat.orm.api.ApiConfig
你需要先了解这些注解的功能和基本工作方式:
cool.lazy.cat.orm.api.base.anno.*
lazy-cat以pojo字段的getter方法标注的注解为准 请注意
api模块映射了一个根路径作为入口, 又根据Pojo类限定了namespace, 一个完整的api映射路径是由 api映射根路径 + pojo namespace + apiMethod
事实上 阅读完那些注解, 已经没有什么需要额外注意的地方了.
api模块的功能实现比较简单, 在你的pojo类中标注那些注解并访问对应的接口 so, just do it
@see cool.lazy.cat.orm.api.web.entrust.EntrustApi、cool.lazy.cat.orm.api.web.entrust.method.ApiMethodEntry
EntrustApi代表了直接执行api方法的对象, ApiMethodEntry代表执行某个对象的某个方法
可以查看example项目中的实例com.jason.test.api包下的内容
那么你需要留意cool.lazy.cat.orm.core.jdbc.constant.ConditionConstant的CONDITION_TYPE_CACHE属性
api模块对查询字段条件的解析实际上是借由工具类实现的cool.lazy.cat.orm.api.util.ConditionHelper
目前api模块将配置的根路径作为一个@RequestMapping模糊匹配作为总入口 @see cool.lazy.cat.orm.api.web.entrust.BasicEntrustController
- basicEntrustController 经过mvc模糊匹配处理请求 根据当前请求的路径url匹配具体需要执行的api方法 并将当前操作的pojo信息放入上下文 ↴
- apiMethodExecutor 获取对应的ApiMethodEntry 并调用ApiMethodEntry的构建参数方法生成请求参数
执行一系列的拦截 最终执行真正的方法并返回结果 ↴
- basicEntrustController 交给mvc返回结果 并释放上下文信息 ↴
- finished
lazy-cat的第一个快照版仅仅使用了2个月就完成了全部的开发、测试和发布。
但随后代码的维护让我苦不堪言,第二个版本的代码删减、重构量基本达到了90%
足足花费了我近9个月业余时间去重构、扩展功能。由此可见保持一个良好的编码和设计风格是多么重要的一件事。
orm-api的源码2457行代码 orm-core的源码18564行代码
orm-api这个项目还是颇有争议的 目前的实现方案可能欠佳
个人邮箱: 2628452503@qq.com
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。
1. 开源生态
2. 协作、人、软件
3. 评估模型