mybatisplus 如何动态创建 mapper 接口。

2022-01-23 22:54:46 +08:00
 lawler

在写一个涉及单表操作较多的系统。

框架组合,spring boot + mybatis plus 。 代码结构,entity -> mapper -> service -> controller

但是要创建非常多的空白 mapper/service/controller 的 java 文件。

mapper 是个纯接口的空文件,不想写这么多空文件在代码里,如何做到动态注入“接口”文件?

@Mapper public interface EntityMapper extends BaseMapper {

}

甚至,service ,和 Iservice ,也希望通过实体动态生成,直接映射出来接口。

或者有其他方案?可以尽可能的专注业务功能。

4268 次点击
所在节点    Java
32 条回复
geligaoli
2022-01-23 23:32:01 +08:00
那你得按照 mybatis 的方式,建立 Mapper 的代理对象.实际反而更麻烦. mybatisplus 有很好的代码生成器干嘛不用.
alva0
2022-01-23 23:52:33 +08:00
Graphql 可能满足你的要求
jptx
2022-01-24 00:02:16 +08:00
service 之类的可以省掉的,直接用 ActiveRecord 模式即可,也可以顺着往下看 SimpleQuery 工具类,但是这两个都没法省下 mapper 。想省 mapper 的话还得另外想办法。
https://baomidou.com/pages/49cc81/#activerecord-%E6%A8%A1%E5%BC%8F
lawler
2022-01-24 00:42:40 +08:00
@geligaoli #1 一千多张表,生成一堆空文件在代码里,很糟心的。
EscYezi
2022-01-24 03:32:46 +08:00
@lawler 统一放一个包里(比如 generated ),只通过插件生成,不去碰那个包。眼不见心不烦
sagaxu
2022-01-24 06:25:12 +08:00
ClassLoader 八股文背的那么溜,总算有机会用了
xuanbg
2022-01-24 08:03:53 +08:00
我都是只用 mybatis ,从来不用 plus 。个人认为楼主也可以抛弃 mybatis plus ,手写 sql 它不香吗?
VeryZero
2022-01-24 08:55:23 +08:00
@xuanbg 先审题,一千多张表手写 sql ,咋想的。。
zliea
2022-01-24 08:57:38 +08:00
Graphql+1
BaseMapper ???
thetbw
2022-01-24 09:04:14 +08:00
直接前端传 sql 执行吧,我就见过这种😅
ic2y
2022-01-24 09:20:06 +08:00
封装一个通用级的动态 mapper , 支持动态传递表名、字段、where order 等。
Suaxi
2022-01-24 09:34:54 +08:00
写个通用 BaseMapper ,枚举里加一个[表名].class 字段,用的时候传具体的表名,反射出对应表的 IService 就可以了
lawler
2022-01-24 09:41:34 +08:00
@alva0 #2 @ztechstack #9 @thetbw #10
一个单体应用,并不是一个接口程序,虽然说都是 from 操作,但更多的还是数据的读取展示。

@jptx #3 有考虑过,但依然还是要生成很多空包。
@EscYezi #5 会增加包体积,增量发布时更是一言难尽,因为要人工 review 后留档发布代码的 class 图片快照。

@xuanbg #7 懒
lawler
2022-01-24 09:46:39 +08:00
@ic2y #11 @Suaxi #12
其实我尝试过,因为 spring 在加载 mybatisplus 时,会初始化 basemaper 的实现,所以通用 mapper 必须做手动实现,需要写大量代码,是非常复杂的一种方式。还有一种是加载前旁注,但会有环境上下文问题。还有一种是加载后修改,但会绑定实体失败。

如果有现成参考的例子的话,麻烦贴个地址,或者仓库名称,我去学习一下。
makinomura
2022-01-24 10:22:50 +08:00
1. 自定义注解处理器编译时自动生成接口文件
2. asm 运行时动态生成 class
lawler
2022-01-24 10:42:36 +08:00
@makinomura #15
都做过了。看我 14 楼的恢复,注入 bean 时机翻了很多资料,没找到的。。

1 ,2 步之后得到 cls(接口类),然后注册 bean 。
BeanDefinitionRegistry beanFactory = (BeanDefinitionRegistry) SpringUtil.getBeanFactory();
RootBeanDefinition bean = new RootBeanDefinition(cls);
beanFactory.registerBeanDefinition(className, bean);

问题是,在注册依赖 mapper 时报错。注册依赖改为 lazy ,可以不报错,但是 bean 是接口类,不能实例化为 bean 。lazy 首次加载时就报错了。

接下来,考虑通过 mybatisplus 的类,自动实现生成 mapper 接口的实现类,于是有了下边的代码。
MybatisConfiguration mmr=new MybatisConfiguration();
mmr.addMapper(cls); // 这个方法是通过接口类,实现实现类动态生成并加载的。经测试无效。

所以,思路应该没错,或许是时机或者方法没找对。
wolfie
2022-01-24 10:53:29 +08:00
1. 定义一个通用的 BaseService 、BaseMapper 。
2. 根据 DO 动态创建一堆 BaseService
3. 重写 com.baomidou.mybatisplus.extension.service.impl.ServiceImpl#currentModelClass
4. 通用 BaseService 方法内自定义环绕,搭配动态表名 https://baomidou.com/pages/2a45ff/#dynamictablenameinnerinterceptor
lawler
2022-01-24 11:10:09 +08:00
@wolfie #17 这个文档我看过,是一种思路,但是没有尝试,一来要做大量的改造工作,二来,看到参数是 map 不利于维护。而且跟我实际想要实现的效果不太一样。

本意是,spring 容器可以通过类型推导加载 bean 。如通过 @Autowired 注入 List<User>、List<Account>..
List 和 BaseMapper 是一样的接口类。

我只需要,
@Autowired BaseMaper<User>、BaseMaper<Account>就可以拿到对应动态生成的实现类。


换句话说,我理想中的效果是 BaseMaper<T>/Service<T>/Controller <T>,T 是任意表对象,就可以实现,一套 MVC 控制模板。
micean
2022-01-24 11:16:58 +08:00
用 jdbctemplate
自己实现 resultset 的 handler 就可以了
Suaxi
2022-01-24 11:51:17 +08:00
@lawler 直接 BaseMaper<T>/Service<T>/Controller <T>好像不行,项目组里目前用的是这种实现方式
![]( https://s6.jpg.cm/2022/01/24/LpUXnT.png)

![]( https://s6.jpg.cm/2022/01/24/LpUctE.png)

![]( https://s6.jpg.cm/2022/01/24/LpU8j6.png)

新增表的时候手动填一个 xxxDao ,枚举里再加上对应新增的表

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/830149

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX