leniu MyBatis 规范
项目特征速查
项 值
XML 位置 与 Mapper 接口同目录(非 resources/mapper/ )
分页 PageHelper → PageMethod.startPage(PageDTO) → PageVO.of(list)
逻辑删除 1=删除,2=正常(与 RuoYi 相反)
Service 无接口,直接 @Service 类,Mapper 字段名统一用 baseMapper
循环依赖 跨模块依赖用 @Autowired @Lazy
Mapper 接口模板
基础 Mapper
@Mapper public interface XxxMapper extends BaseMapper<XxxEntity> {
List<XxxVO> listByParam(@Param("param") XxxParam param);
}
忽略租户隔离(方法级)
@Mapper public interface XxxMapper extends BaseMapper<XxxEntity> {
@InterceptorIgnore(tenantLine = "true")
List<XxxVO> queryWithoutTenant(@Param("param") XxxParam param);
}
全量忽略拦截器(类级别)
@Mapper @InterceptorIgnore // 无参数,跳过所有拦截器(租户、数据权限等) public interface XxxMapper extends BaseMapper<XxxEntity>, BaseExistsMapper<XxxEntity> {
List<XxxVO> listVoByIds(@Param("orderIds") List<Long> ids, @Param("tenantId") String tenantId);
@QueryExtension
List<XxxIdDateVO> queryXxx(@Param("param") XxxSearchParam param,
@Param("permission") XxxUserPermissionDTO permission);
}
-
BaseExistsMapper 提供 existsOne(Wrapper) 方法(比 selectCount > 0 高效)
-
适用于数据量大、需跨租户查询的核心表
XML 模板
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="net.xnzn.core.xxx.mapper.XxxMapper">
<select id="listByParam" resultType="net.xnzn.core.xxx.vo.XxxVO">
SELECT
t.id,
t.name,
t.status
FROM table_name t
<where>
t.del_flag = 2
<if test="param.status != null">
AND t.status = #{param.status}
</if>
<if test="param.keyword != null and param.keyword != ''">
AND t.name LIKE CONCAT('%', #{param.keyword}, '%')
</if>
</where>
ORDER BY t.crtime DESC
</select>
</mapper>
XML 编写规则
规则 说明
禁止 SELECT *
必须明确指定字段
del_flag = 2
正常数据条件
#{} 占位符 禁止 ${} (SQL 注入)
<where> 标签 自动处理 AND 前缀
特殊字符 < / > 或 <![CDATA[ ]]>
常用动态 SQL 片段
<!-- IN 查询 --> <if test="param.ids != null and param.ids.size() > 0"> AND t.id IN <foreach collection="param.ids" item="id" open="(" separator="," close=")"> #{id} </foreach> </if>
<!-- 多条件 OR --> <if test="param.keyword != null and param.keyword != ''"> AND (t.name LIKE CONCAT('%', #{param.keyword}, '%') OR t.code LIKE CONCAT('%', #{param.keyword}, '%')) </if>
<!-- 时间范围 --> <if test="param.startDate != null"> AND t.crtime >= #{param.startDate} </if> <if test="param.endDate != null"> AND t.crtime <= #{param.endDate} </if>
LambdaQuery 使用
List<XxxEntity> list = mapper.selectList( Wrappers.lambdaQuery(XxxEntity.class) .eq(XxxEntity::getStatus, 1) .eq(XxxEntity::getDelFlag, 2) // 2=正常 .in(CollUtil.isNotEmpty(idList), XxxEntity::getId, idList) .like(StrUtil.isNotBlank(name), XxxEntity::getName, name) .ge(startDate != null, XxxEntity::getCrtime, startDate) .le(endDate != null, XxxEntity::getCrtime, endDate) .orderByDesc(XxxEntity::getCrtime) );
Service 注入规范
@Slf4j @Service @Validated public class XxxService {
@Autowired
private XxxMapper baseMapper; // ✅ 统一命名 baseMapper
@Autowired @Lazy
private XxxDetailService xxxDetailService; // ✅ 跨模块用 @Lazy
public XxxEntity getOne(Long id) {
return baseMapper.selectById(id);
}
public boolean exists(String macOrderId) {
return baseMapper.existsOne(
Wrappers.lambdaQuery(XxxEntity.class)
.eq(XxxEntity::getMacOrderId, macOrderId)
.eq(XxxEntity::getDelFlag, 2)
);
}
}
分页查询
public PageVO<XxxVO> pageList(XxxParam param) { // ✅ 传入 PageDTO 对象(不要拆 pageNum/pageSize) if (Objects.nonNull(param.getPage())) { PageMethod.startPage(param.getPage()); }
List<XxxVO> records = xxxMapper.listByParam(param);
return PageVO.of(records); // 自动提取 total 等信息
}
Mapper 方法返回 List<XxxVO> 即可,PageHelper 拦截器自动处理分页。
报表 Mapper(无 BaseMapper)
@Mapper public interface ReportXxxMapper { // ✅ 不继承 BaseMapper
List<XxxVO> listSummary(
@Param("param") XxxParam param,
@Param("authPO") MgrUserAuthPO authPO,
@Param("dataPermission") ReportDataPermissionParam dataPermission
);
XxxVO getSummaryTotal( // 合计行
@Param("param") XxxParam param,
@Param("authPO") MgrUserAuthPO authPO,
@Param("dataPermission") ReportDataPermissionParam dataPermission
);
}
命名规律:listXxx() 分页数据 / listXxx_COUNT() 计数 / getSummaryTotal() 合计行 / listXxxByDay() 按维度
合计行查询
<!-- 列表查询 --> <select id="listByParam" resultType="XxxVO"> SELECT id, name, amount, count FROM table_name <where>...</where> ORDER BY id DESC </select>
<!-- 合计查询:只返回数值字段 --> <select id="getSummaryTotal" resultType="XxxVO"> SELECT SUM(amount) AS amount, SUM(count) AS count FROM table_name <where>...</where> </select>
除零处理:
CASE WHEN SUM(count) = 0 THEN 0 ELSE SUM(amount) / SUM(count) END AS avgAmount
禁止项
// ❌ 继承 RuoYi TenantEntity import org.dromara.common.mybatis.core.domain.TenantEntity;
// ❌ delFlag: 0=正常(leniu 是 2=正常) wrapper.eq(XxxEntity::getDelFlag, 0);
// ❌ XML 放 resources/mapper/(必须与 Mapper 接口同目录)
// ❌ MapstructUtils(用 BeanUtil.copyProperties) MapstructUtils.convert(source, Target.class);
// ❌ Service 继承 IService / ServiceImpl public interface IXxxService extends IService<XxxEntity> {}
XML 文件位置
net.xnzn.core.xxx.mapper/ ├── XxxMapper.java # 接口 └── XxxMapper.xml # XML(同目录!)
参考文档
- 报表 Mapper 完整示例:详见 references/report-mapper.md