小明接手了项目。业务方的需求包括很多组织管理、人事管理、事件管理的需求。这些业务包括对终端客户的询问和对内部经理的管理。需求复杂度不高,很多涉及到表单的增删改查。但要求太多,小明还是要加班加点当码农。
其实对于这种场景,很多公司都尝试使用打破层级界限的编码工具,比如全球第一编码语言PHP、ruby/rails等,方便快捷。然而,当业务变得复杂时,他们就不得不慢慢迁移到企业级开发语言java。也有企业开始尝试低代码平台,通过简单的拖拽完成后端管理界面的开发。但目前的低代码开发实际上只能对上述需求进行增删改查。
有没有一种方法,既能满足Java企业级开发中复杂需求的开发,又能快速完成简单的增删改查(有一定的业务逻辑),同时保证技术统一?那么连续性又如何呢?
fluid-Mybatis完成了对mybatis的封装,实现了在java代码中使用流式语言,满足条件设置、复杂关联、嵌套、并集、多数据库支持、个性化扩展等。超越便利。现在又上线了,专门针对表单级别的增删改查,一剑斩断喉咙的能力。
哈哈哈,作者吹牛不用纳税。我们来看一个简单的例子:
我们定义一个springrest api接口如下
@RestController@FormService(表= “学生”)公共 接口 StudentQueryApi { @PostMapping("/学生") 学生findStudentBy(@RequestBody学生查询学生); @PostMapping("/listStudentBy") List listStudentBy(@RequestBody StudentQuery 学生) ;}@Data@Accessors(链= true)公共 班级 学生查询 实现 可序列化 { 私有 字符串 用户名; @Entry(类型= EntryType.LikeLeft) 私有 字符串地址; @Entry(类型 = 之间) 私人 整数[] 年龄; 私人 整数性别; /** * 默认正序 */ @Entry(类型=EntryType.OrderBy,值= “用户名称") 私有 booleanbyUserName = true; /** * 默认倒序 */ @Entry(类型= EntryType.OrderBy,值= “年龄”) 私有 布尔值 byAge;}@Data@Accessors(链= true)公共 班级 学生 实现 可序列化 { 私有 字符串用户名; 私有 字符串状态; 私人 字符串电话; @Entry("电子邮件") 私人 String 他的电子邮件; 私人 整数年龄; 私有 字符串地址;}
然后用@FormServiceScan注解把API路径加入到spring配置中,最适合和mybatis的@MapperScan类似
@FormServiceScan
spring配置
@MapperScan
@FormServiceScan({"您定义api的包路径"})public class SpringConfig { //你的其他bean配置}
非常简单。虽然你只定义了一个接口,没有写一行实现代码,但是你已经完整的实现了一个查询逻辑。查询输入参数包括相等条件、之间条件、相似条件和排序设置。
启动springboot应用程序。让我们用休息客户端来调用它,看看
是不是很简单呢?声明就是执行。单表CRUD,产品原型绘制完成,开发基本完成。 form-service功能也可以看作是一个低代码实现框架。
form-service
@FormService,定义在接口类上,表示该接口是FormService接口
@FormService
@FormServiceScan,定义在Spring的@Configuration类上,功能与类似Mybatis的@MapperScan,使用 扫描所有@FormService接口
@Configuration
@FormMethod,可选,在 Service 方法上定义。如果是插入或更新方法,则必须声明它。如果是查询方法则无需声明
@FormMethod
@Entry,可选,在表单字段上定义,@Entry
@Entry
同时,除了定义接口和属性上的表单服务注解之外,还需要进行以下增强
@RestController+@PostMapping
javax.validate
当然,以上所有功能都是建立在你按照FluentMybatis的规范生成数据库Entity类的基础上的。
FluentMybatis
但这并不是Fluent-mybatis FormService的全部功能。 FormService还可以通过简单的声明来解决1对1和1对N的相关查询,同时解决查询列表时带来的1+N查询问题,而这一切都不需要你编写代码。有一定编码经验的学生会问您是否愿意这样做! ! !
Fluent MyBatis Entity
@Relation
@Tables(url= URL,用户名= “根”,密码= “密码”, srcDir = SrcDir,testDir = TestDir,basePack =基础包 + 2, gmtCreated = “gmt_created”,gmtModified = “gmt_modified” ,逻辑删除 = “已删除”, 表 = { @Table(值= {“学生”,“学生分数” }, 列= @Column (值= “版本”,isLarge = true) ), 关系={ @Relation(方法= “findDeskMate”,类型=RelationType.OneWay_0_1, 源= “学生”,目标="学生",其中 = "id=desk_mate_id "), @Relation(源= “学生”,目标= “学生分数”,类型 = RelationType.TwoWay_1_N, 其中 = "id=student_id") })静态 班级 RelationDef1 {}
上面代码生成的Entity类如下
@FluentMybatis( 表="学生", 模式= "fluid_mybatis")公共类 StudentEntity 扩展 RichEntity { // ... 省略属性定义 /** * 一对一关联查询方法 */ @RefMethod(" deskM ateId = id") 公共 StudentEntity findDeskMate() { 返回 超级.invoke("findDeskMate" , true); } /** * 一对多关联查询方式 */ @ RefMethod("studentId = id") public列表 findStudentS coreList() { returnsuper.invoke("findStudentScoreList", 真);}}
定义查询接口返回值中的关联对象,例如以下
@Data@Accessors(链= true)public 类 学生 { 私有长id; 私有 字符串用户名; 私人 字符串状态; 私人 字符串电话; @Entry("电子邮件") 私人 字符串他的电子邮件; 私人 整数年龄; private String address; /** * 同桌对象, 对应findDeskMate方法 */ 私人学生同桌; /** * 分数列表, 属性名称是scores, 无法按规则和findStudentScoreList对应 * 需在@Entry注解中显式指定关联方法 */ @Entry(值= “findStudentScoreList”) 私人 列表 分数;}
现在我们重新执行listStudentBy的测试方法,看看一下结果情况
listStudentBy
@BeforeEachvoid 设置() { //准备2个学生的数据,他们同桌彼此 ATM.dataMap.student.table(2) .env.values("test_env") .userName.values( "李明" ,“小强”).age.values(23,34) .email.values("xxx@test") 。 address.values("杭州滨江") .deskMateId.values(2, 1) .cleanAndInsert(); //准备3件分数数据,黎明有两个分数,小强有一个分数 ATM.dataMap.studentScore.table(3) .env.values("test_env" ) 。 StudentId.values(1, 1, 2) .subject.values("语文", "英语") .score 。值(79, 67, 98) .cleanAndInsert();} @TestvoidlistEntity() { 列表 学生 = service.listStudentBy(new StudentQuery() .setAddress("杭州") .setAge(new Integer[]{20, 40}));/ / 验证列表数据 Want.object(学生) 。 “李明”,“小强”) 。 .address.values("杭州滨江") . kv("他的电子邮件", "xxx@test")); /*同桌=我自己*/想要.object( Students.get(0)).eqReflect(students.get(1).getDeskMate(), EqMode.IGNORE_DEFAULTS); /* 验证分数列表 */ 想要.对象( Students.get(0).getScores()).eqDataMap(new DataMap(2) .kv( "分数" 、79、 67) ."英语")); Want.object (students.get(1).getScores())。 eqDataMap(new DataMap (1) .kv("分数",98) .kv("主题", "英语")); }
然后我查看控制台,打印出sql语句,一共执行了3条sql
查看学生名单
查询学生同桌,情况 desk_mate_id IN (?, ?)
desk_mate_id IN (?, ?)
查询学生成绩、状况 student_id IN (?, ?)
student_id IN (?, ?)
==> 准备: SELECT `id`, `...省略字段` FROM `student` WHERE `is_deleted` =? AND`env`=?和“地址”之类的?和“年龄”之间?和 ? ORDER BY `user_name` ASC, `age` DESC ==> 参数:false(布尔)、test_env(字符串)、hangzhou%(字符串)、20(整数)、40(整数) <== 总计: 2 ==> 正在准备: SELECT `id`, `...结果字段` FROM `student` WHERE `is_deleted` =? AND`env`=? AND `desk_mate_id` IN (?, ?) ==> 参数: false(布尔值), test_env(字符串), 1(长整型), 2(长整型) <== 总计: 2 ==> 准备: SELECT `id`, `...省略字段` FROM `student_score` WHERE `is_deleted` = ? AND`env`=? AND `student_id` IN (?, ?)==> 参数:false(布尔值)、test_env(字符串)、1(长整型)、2(长整型)<== 至塔尔: 3
通过上面的观察,框架完美的解决了1+N查询的问题
maven参考,详细使用文档请参考Fluent mybatis文档
<依赖项> <groupId>com.github.atoolgroupId > <artifactId>流利-mybatisartifactId> <版本>1.9.3版本>依赖项><依赖项 > <groupId>com.github.atoolgroupId> artifactId>Fluent-mybatis-处理器 artifactId> <版本>1.9.3版本> <范围>提供范围>依赖>
完整示例: