跳转至

04-实体与数据访问 pojo-mapper

📄 创建: ZCode AI 2026-08-14 · 修改: JimWb 2026-08-14

https://doc.xpku.com/raw/tech/backend/bams-sdk/04-pojo-mapper.md

bams-pojo(50 个类)定义共享实体/DTO/VO 和类型处理器;bams-mapper(30 个类)提供 MyBatis-Plus 数据访问增强。


一、BaseEntity —— 所有业务实体的父类

cn.cnbm.bams.pojo.base.BaseEntity

@FieldNameConstants
@Data
public class BaseEntity implements Serializable

字段清单

字段 类型 注解 说明
id String @TableId + @JsonSerialize(ToStringSerializer) 主键。String 类型,雪花算法生成。JSON 序列化强制转字符串防前端精度丢失
createdBy String @TableField("created_by", fill=INSERT) 创建人 ID
createdByName String @TableField(exist=false) 创建人名称(不入库,仅展示)
createdTime LocalDateTime @TableField(fill=INSERT) + @JsonFormat 创建时间
updatedBy String @TableField(fill=INSERT_UPDATE) 更新人 ID
updatedByName String @TableField(exist=false) 更新人名称
updatedTime LocalDateTime @TableField(fill=INSERT_UPDATE) + @JsonFormat 更新时间

自动填充机制

id 的填充不由 @TableId 完成,而是由 EnergyMetaObjectHandler.insertFill()(bams-pojo)在插入时调 IDUtil.getId() 生成。

EnergyMetaObjectHandler(抽象类,cn.cnbm.bams.ibatis.handler): - insertFill:id 为空则 IDUtil.getId();createdTime/updatedTime 设当前时间;createdBy/updatedBy 从 getCurrentLoginUser().get("userId") 取(默认 0L) - updateFill:只填 updatedTime/updatedBy - 抽象方法 getCurrentLoginUser():返回 Dict,由业务应用实现

common-func 的 MyBatisPlusMetaObjectHandler 继承它,从 PermissionContextHolder 取 userId。详见 09-通用功能

继承注意事项

⚠️ 子类必须用 @EqualsAndHashCode(callSuper = true) 才能把 BaseEntity 的字段纳入 equals/hashCode。历史代码中部分子类用了 callSuper = false(BdDept/BdPerson/BdPost 等),这是遗留问题。详见 12-FAQ与注意事项

// ✅ 正确写法
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("my_table")
public class MyEntity extends BaseEntity {
    private String name;
}

// ⚠️ 不推荐(id 等字段不纳入 equals/hashCode)
@Data
@EqualsAndHashCode(callSuper = false)  // 历史遗留
public class LegacyEntity extends BaseEntity { ... }

BaseEntity.of() 静态方法

public static <T extends BaseEntity> T of(Object o, Class<T> clazz)

把 Map 或 Bean 转成目标实体(用 hutool BeanUtil),方便从 Dict 查询结果反构实体。


二、实体清单(按业务域)

bd 域 —— 基础主数据

实体 表名 包路径 说明
BdCorp bd_corp pojo.bd 公司/工厂。实现 ITreeAble<BdCorp>(树形)。含编码/类型/经纬度/联系人/def1-def10 扩展字段
BdDept bd_dept pojo.bd 部门。编码/名称/上级/corpCode/deleted
BdPerson bd_person pojo.bd 人员。编码/姓名/性别/部门/岗位/accountCode 对接底座。@CheckRepeat 校验编码唯一
BdPost bd_post pojo.bd 岗位。编码/名称/排序/corpCode/deleted
BdUnit bd_unit pojo.bd 计量单位@SequenceGenerator 自动生成编码(前缀 "U")。含换算系数/精度/量纲
BdDictionary bd_dictionary pojo.bd 字典项。dkey/dtype/dname/dvalue + 3 扩展值/colorType
BdDictionaryHead bd_dictionary_head pojo.bd 字典分类。dtype/dname
OrgInfo (约定) pojo.bd 组织机构。不继承 BaseEntity,独立定义。含 tenantId + fieldText1-15 等通用扩展字段,对接外部组织数据

sys 域 —— 系统管理

实体 表名 包路径 说明
SysUser sys_user pojo.sys 用户。含主子账号(pid/accountType)、superAdmin、loginName(@CheckRepeat)、密码、登录IP/时间
SysRole sys_role pojo.sys 角色。roleCode/roleName(@CheckRepeat)、dataScope 数据权限范围
SysResource sys_resource pojo.sys 菜单资源。实现 ITreeAble(树形)。menuType(dir/menu)/menuCode/path
SysConfig sys_config pojo.sys 参数配置。category/configKey/val/visible
SysLog sys_log pojo.sys 接口日志。requestIp/requestUrl/requestParams/responseBody/costTime
SysOperLog sys_oper_log pojo.sys 业务操作日志。businessType(增改删)/operName/operParam/jsonResult
SysTenantDb sys_tenant_db pojo.sys 多租户数据源配置(见下文专述)
SysBusinessStatus sys_business_status pojo.sys 业务状态配置。appCode/businessCode/businessStatus JSON
SysButton sys_button pojo.sys 资源按钮
SysMenuButton sys_menu_button pojo.sys 菜单按钮关联(含 authCode 权限码)
SysApp sys_app pojo.sys 应用管理。appCode/authMode 认证模式/supportTerminal
SysUserRole sys_user_role pojo.sys 用户-角色关联(不继承 BaseEntity,轻量 POJO)
SysRoleResource sys_role_resource pojo.sys 角色-资源关联(不继承 BaseEntity
SysRoleButton sys_role_button pojo.sys 角色-按钮关联(不继承 BaseEntity
SysAppRole sys_app_role pojo.sys 应用-角色关联(不继承 BaseEntity

规律:关联表实体(UserRole/RoleResource/RoleButton/AppRole)都是轻量 POJO,不走 BaseEntity 的审计字段。

pub 域 —— 公共

实体 表名 说明
PubFileUpload pub_file_upload 文件上传记录。fileName/content(byte[])/bizId/bizType
PubSequence pub_sequence 序列号配置。sequenceCode/resetType/前缀/后缀/步长/currNo + @Version 乐观锁

三、BaseMapperExt —— 数据访问增强

cn.cnbm.bams.mapper.ext.BaseMapperExt<T>

继承 MyBatis-Plus 的 BaseMapper<T>,新增 5 个方法。业务 Mapper 一律继承此类。

public interface MyMapper extends BaseMapperExt<MyEntity> { }

新增方法

方法签名 说明
<P extends IPage<Dict>, R extends Dict> P selectPageMaps(P page, @Param(Constants.WRAPPER) Wrapper<R> params) 核心:分页查询返回 Dict(Map 子类)而非实体。适合动态列表/报表,免去建 VO
boolean executeSqlForInsert(@Param("sql") String sql) 执行原生 INSERT SQL
Dict executeSqlForSelectOne(@Param("sql") String sql) 原生 SELECT 返回单行 Dict
List<Dict> executeSqlForSelectList(@Param("sql") String sql) 原生 SELECT 返回 Dict 列表
List<Map<String,Object>> executeSqlForList(@Param("sql") String sql) 原生 SELECT 返回 Map 列表

⚠️ 后 4 个 executeSql* 方法用 ${sql} 字符串拼接(非预编译),存在 SQL 注入风险,应由 SDK 内部受控调用,不要直接透传用户输入。

selectPageMaps 示例

// 分页查 Map 结果(无需建 VO)
Page<Dict> page = new Page<>(1, 10);
QueryWrapper<MyEntity> wrapper = new QueryWrapper<>();
wrapper.eq("status", 1);
Page<Dict> result = myMapper.selectPageMaps(page, wrapper);

Dict 类

cn.cnbm.bams.common.core.lang.Dict —— 自定义 Map 子类,重写了 getOrDefault 以区分 null 值。


四、SqlInjectorExt 机制 —— 自定义方法全局注入

三个类协作,把 selectPageMaps 自动注入到所有继承 BaseMapperExt 的 Mapper:

工作原理

SqlMethodExt(枚举,定义方法元信息)
    │ 定义方法名 "selectPageMaps" + SQL 模板
SelectPageMaps(继承 AbstractMethod)
    │ injectMappedStatement() 构造 MappedStatement
    │ 返回类型映射为 Dict.class
SqlInjectorExt(@Component,继承 DefaultSqlInjector)
    │ getMethodList() 在 MP 默认方法基础上追加 SelectPageMaps
    │ 因是 @Component,Spring Boot 启动时对所有 Mapper 全局生效

关键文件

文件 路径 说明
SqlMethodExt mapper.ext.enums 枚举,定义 SELECT_PAGE_MAP 方法元信息
SelectPageMaps mapper.ext.methods 继承 MP AbstractMethod,构造 MappedStatement
SqlInjectorExt mapper.ext.injector @Component,继承 DefaultSqlInjector,重写 getMethodList 追加自定义方法

辅助工具

说明
SqlScriptHelper 用 Druid SQL 解析器改写子查询、给列名加表前缀;遍历 @Formula 注解拼 select 列
SqlUtil 反射读 @TableName/@TableField 生成 SELECT col as field FROM table

五、@Formula 注解 —— 实体字段 = 子查询

cn.cnbm.bams.common.annotations.mybatis.Formula

标记在实体字段上,让该字段的值来自一个子查询表达式。

@Formula("(SELECT COUNT(*) FROM order WHERE order.cust_id = id)")
private Integer orderCount;  // 查询时自动执行子查询填充

ServiceExtImpl.getQueryWrapperSqlScriptHelper 会解析 @Formula 注解,把子查询拼到 SELECT 列中。getById 也重写了以支持 @Formula


六、多租户数据源机制

@TenantDataSource 注解

cn.cnbm.bams.common.annotations.TenantDataSource(在 common-tool 模块)

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface TenantDataSource {
    String value() default "master";  // 数据源标识,默认主库
}

标记类/方法走哪个数据源。如 @TenantDataSource("sys") 表示操作 sys 系统库。

SysTenantDb 实体

cn.cnbm.bams.pojo.sys.SysTenantDb(表 sys_tenant_db

承载每个租户的数据源连接信息:一个租户一行记录 = 一个独立数据库连接配置。

字段 说明
tenantCode 租户编码
dsKey 数据源标识
jdbcDriver / jdbcUrl / jdbcPort / jdbcDb 连接信息
jdbcUsername / jdbcPasswd 凭证
tenantDbInitFlag 是否已初始化库表(0否1是)
enableState 启用状态
corpCode 公司编码

⚠️ 动态数据源是半成品AbstractRoutingDataSource + ThreadLocal + Manager 框架完整,@TenantDataSource 注解已定义,但缺少 AOP 切面实现注解→自动切换,且 DynamicDataSource Bean 未注册。详见 05-业务服务层


七、DTO / VO 补充

常用 DTO

DTO 包路径 说明
TokenInfoDTO dto 底座 token 返回(accountId/orgCode/userAccount)
RedisPointData dto.redis 实时点位数据(tm/unit/val)
SysMenuButtonDTO dto.sys 按钮请求参数
SysResourceDTO dto.sys 菜单树 DTO(实现 ITreeAble)
BdCorpCacheDTO dto.bd 公司缓存(含 parentCodeList/childCodeList 祖先后代链)

常用 VO

VO 包路径 说明
QueryCondition vo 单查询条件(field/opt/value)
TableData vo 表格数据导出容器(继承 BasicParamWrapper)
TableHeader vo 表头(含 children 树形,支持 dictCode 字典翻译)
SysAccount vo 底座虚拟账户 JSON 反序列化模型
VersionInfo vo 服务版本信息
MessageVo / MqDataVo vo.mq MQ 消息/信封

BasicParamWrapper / BasicParamers

cn.cnbm.bams.pojo.basics.BasicParamWrapper(继承 BasicParamers

通用查询参数容器。前端传一个扁平 JSON,后端按操作符分桶构建 QueryWrapper。

参数 Map 操作符 示例
andMap = 精确匹配
likeMap / andLikeMap / rightLikeMap LIKE 模糊匹配
geMap / leMap >= / <= 范围
inMap / notInMap IN / NOT IN 集合
orMap OR 或条件
orderBy ORDER BY 排序
// 前端传参示例
{
  "current": 1,
  "size": 10,
  "searchVal": "关键词",
  "andMap": {"status": 1, "corp_code": "C001"},
  "likeMap": {"name": "张"},
  "orderBy": {"created_time": "desc"}
}

// Service 层使用
Page<MyEntity> page = myService.listPage(basicParamWrapper);

ServiceExtImpl.getQueryWrapper() 会解析 BasicParamWrapper 自动构建 MyBatis-Plus QueryWrapper,详见 05-业务服务层


八、ibatis 类型处理器

包路径 说明
EnergyMetaObjectHandler ibatis.handler 抽象类,BaseEntity 审计字段自动填充(见上文)
SerializableTypeHandler ibatis.handler Serializable 与 VARCHAR/BIGINT 互转
MapToBeanMapper<BEAN> ibatis.mapper Map→Bean 的 Function,.map(MapToBeanMapper.create(Xxx.class))
RefreshRedisEvent events Spring 事件,通知刷新 Redis 缓存

相关文档