leniu-java-mybatis

SKILL.md

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 前缀
特殊字符 &lt; / &gt;<![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 &lt;= #{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
Weekly Installs
3
GitHub Stars
8
First Seen
7 days ago
Installed on
gemini-cli3
github-copilot3
codex3
kimi-cli3
cursor3
amp3