共901行

Mybaties自定义配置

2026-07-08 08:48:14

BaseMapper.java

package com.dpb.yunc.db.mapper.common;

import org.apache.ibatis.annotations.*;

import java.util.List;
import java.util.Map;

public interface BaseMapper<T, ID> {
    /**
     * 新增一条记录
     *
     * @param entity 实体
     * @return 受影响记录
     */
    @InsertProvider(type = BaseSqlProvider.class, method = "insert")
    @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
    int insert(T entity);

    /**
     * 删除一条记录
     *
     * @param id id
     * @return 受影响记录
     */
    @DeleteProvider(type = BaseSqlProvider.class, method = "delete")
    int delete(ID id);

    /**
     * 修改一条记录
     *
     * @param entity 实体
     * @return 受影响记录
     */
    @UpdateProvider(type = BaseSqlProvider.class, method = "update")
    int update(T entity);

    /**
     * 根据id查询
     *
     * @param id id
     * @return Entity
     */
    @SelectProvider(type = BaseSqlProvider.class, method = "selectById")
    T selectById(ID id);

    /**
     * 查询所有数据
     *
     * @param entity 实体
     * @return 查询结果
     */
    @SelectProvider(type = BaseSqlProvider.class, method = "selectByEntity")
    List<T> selectByEntity(T entity);

    /**
     * 查询所有数据
     *
     * @param criteriaMap - 查询参数Map
     * @return 查询结构
     */
    @SelectProvider(type = BaseSqlProvider.class, method = "selectByCriteriaMap")
    List<T> selectByCriteriaMap(Map<String, Object> criteriaMap);

    /**
     * 根据id列表查询
     *
     * @param ids id列表
     * @return 查询结果
     */
    @SelectProvider(type = BaseSqlProvider.class, method = "selectByIds")
    List<T> selectByIds(List<ID> ids);

    /**
     * 批量删除
     * @param ids id列表
     * @return 受影响记录
     */
    @DeleteProvider(type = BaseSqlProvider.class, method = "deleteAll")
    int deleteAll(List<ID> ids);

    /**
     * 批量保存
     *
     * @param entities 实体列表
     * @return 受影响记录
     */
    @InsertProvider(type = BaseSqlProvider.class, method = "insertAll")
    @Options(useGeneratedKeys = true, keyColumn = "id", keyProperty = "id")
    int insertAll(List<T> entities);

    /**
     * 逻辑删除
     * @param id id列表
     * @return 受影响记录
     */
    @UpdateProvider(type = BaseSqlProvider.class, method = "smartDelete")
    int smartDelete(ID id);

    /**
     * 批量逻辑删除
     * @param ids id列表
     * @return 受影响记录
     */
    @UpdateProvider(type = BaseSqlProvider.class, method = "smartDeleteAll")
    int smartDeleteAll(List<ID> ids);
}

1. [BaseMapper.java]

文件作用: 泛型基础Mapper接口,提供通用的数据库CRUD操作

核心设计:

提供的方法:

方法 功能 说明
insert(T entity) 新增记录 支持主键自动回填
delete(ID id) 物理删除 根据ID删除
update(T entity) 更新记录 根据ID更新
selectById(ID id) 根据ID查询 返回单个实体
selectByEntity(T entity) 按实体查询 非空字段作为查询条件
selectByCriteriaMap(Map) 按Map查询 支持复杂查询条件
selectByIds(List<ID> ids) 批量ID查询 返回实体列表
deleteAll(List<ID> ids) 批量物理删除 根据ID列表删除
insertAll(List<T> entities) 批量插入 支持主键回填
smartDelete(ID id) 逻辑删除 自动判断是否有delFlag字段
smartDeleteAll(List<ID> ids) 批量逻辑删除 同smartDelete

BaseSqlProvider.java

package com.dpb.yunc.db.mapper.common;

import cn.hutool.core.util.StrUtil;
import org.apache.ibatis.builder.annotation.ProviderContext;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class BaseSqlProvider {
    private static final Map<String, String> BASE_SQL_CACHE_MAP = new ConcurrentHashMap<>();

    public String insert(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.insertInto(tableName(context), fields(context));
            sql.values(fields(context));
            return sql.build();
        });
    }

    public String delete(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.deleteFrom(tableName(context));
            sql.where(id(context));
            return sql.build();
        });
    }

    public String update(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.update(tableName(context));
            String[] fieldsExceptId = Arrays.stream(fields(context)).filter(field -> !field.equals(id(context))).toArray(String[]::new);
            sql.set(fieldsExceptId);
            sql.whereId(id(context));
            return sql.build();
        });
    }

    public String selectById(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.select(fields(context));
            sql.from(tableName(context));
            sql.whereId(id(context));
            return sql.build();
        });
    }

    public String selectByIds(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.select(fields(context));
            sql.from(tableName(context));
            sql.whereIn(id(context));
            return sql.build();
        });
    }

    public String selectByEntity(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.select(fields(context));
            sql.from(tableName(context));
            sql.where(fields(context));
            return sql.build();
        });
    }

    public String selectByCriteriaMap(ProviderContext context, Map<String, Object> criteriaMap) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context) + ":" + criteriaMap.keySet(), value -> {
            Sql sql = new Sql();
            sql.select(fields(context));
            sql.from(tableName(context));
            sql.whereCriteria(criteriaMap.keySet().toArray(new String[0]));
            return sql.build();
        });
    }

    public String deleteAll(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.deleteFrom(tableName(context));
            sql.whereIn(id(context));
            return sql.build();
        });
    }

    public String insertAll(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            sql.insertIntoBatch(tableName(context), fields(context));
            sql.valuesBatch(fields(context));
            return sql.build();
        });
    }

    /**
     * 逻辑删除
     */
    public String smartDelete(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            if (hasDelFlag(context)) {
                sql.update(tableName(context));
                sql.sql(" SET del_flag = 1 ");
                sql.where(id(context));
            } else {
                sql.deleteFrom(tableName(context));
                sql.where(id(context));
            }
            return sql.build();
        });
    }

    public String smartDeleteAll(ProviderContext context) {
        return BASE_SQL_CACHE_MAP.computeIfAbsent(getCacheKey(context), value -> {
            Sql sql = new Sql();
            if (hasDelFlag(context)) {
                sql.update(tableName(context));
                sql.sql(" SET delFlag = 1 ");
                sql.whereIn(id(context));
            } else {
                sql.deleteFrom(tableName(context));
                sql.whereIn(id(context));
            }
            return sql.build();
        });
    }

    /**
     * 主键 默认取实体的第一个字段
     */
    public static String id(ProviderContext context) {
        return fields(context)[0];
    }

    /**
     * 所有字段名称
     */
    public static String[] fields(ProviderContext context) {
        Class<?> entityType = entityType(context);
        Field[] entityFields = entityType.getDeclaredFields();
        Field[] superFields = entityType.getSuperclass().getDeclaredFields();

        // 过滤掉序列化版本号字段
        entityFields = Arrays.stream(entityFields).filter(field -> !"serialVersionUID".equals(field.getName())).toArray(Field[]::new);
        superFields = Arrays.stream(superFields).filter(field -> !"serialVersionUID".equals(field.getName())).toArray(Field[]::new);

        Field[] fields = Arrays.copyOf(superFields, entityFields.length + superFields.length);
        System.arraycopy(entityFields, 0, fields, superFields.length, entityFields.length);
        return Arrays.stream(fields)
                .filter(field -> field.getAnnotation(IgnoreField.class) == null)
                .map(Field::getName)
                .toArray(String[]::new);
    }

    /**
     * 表名称
     */
    public static String tableName(ProviderContext context) {
        String tableName = StrUtil.toUnderlineCase(entityType(context).getSimpleName());
        return tableName.substring(0, tableName.length() - 3);
    }

    /**
     * 获取实体类型
     */
    private static Class<?> entityType(ProviderContext context) {
        Class<?> clazz = context.getMapperType();
        return (Class<?>) ((ParameterizedType) (clazz.getGenericInterfaces()[0])).getActualTypeArguments()[0];
    }

    /**
     * 缓存key
     */
    private static String getCacheKey(ProviderContext context) {
        return context.getMapperType().getSimpleName() + ":" + context.getMapperMethod().getName();
    }

    /**
     * 判断实体类是否包含 delFlag 字段
     */
    private static boolean hasDelFlag(ProviderContext context) {
        try {
            Class<?> entityType = entityType(context);

            Field[] entityFields = entityType.getDeclaredFields();
            for (Field field : entityFields) {
                if ("delFlag".equals(field.getName())) {
                    return true;
                }
            }

            Field[] superFields = entityType.getSuperclass().getDeclaredFields();
            for (Field field : superFields) {
                if ("delFlag".equals(field.getName())) {
                    return true;
                }
            }

            return false;
        } catch (Exception e) {
            return false;
        }
    }
}

2. [BaseSqlProvider.java]

文件作用: SQL提供者,为BaseMapper生成动态SQL语句

核心机制:

  1. SQL缓存:使用ConcurrentHashMap缓存生成的SQL,避免重复解析
  2. 反射解析:通过反射获取实体类的字段和表名
  3. 命名约定

关键方法:

方法 功能
id(context) 获取主键字段(默认第一个字段)
fields(context) 获取所有字段(过滤serialVersionUID@IgnoreField标记的字段)
tableName(context) 获取表名
hasDelFlag(context) 检查是否有delFlag字段,用于判断逻辑删除

智能逻辑删除:

// smartDelete方法会自动判断:
if (hasDelFlag(context)) {
    // 有delFlag字段 → 执行 UPDATE table SET del_flag = 1
} else {
    // 无delFlag字段 → 执行 DELETE FROM table
}

Sql.java

package com.dpb.yunc.db.mapper.common;

import cn.hutool.core.util.StrUtil;

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class Sql {

    private final Criteria criteria = new Criteria();
    private static final String SELECT = "SELECT";
    private static final String FROM = "FROM";
    private static final String WHERE = "WHERE";
    private static final String AND = "AND ";
    private static final String IN = " IN ";

    private static final String INSERT_INTO = "INSERT INTO";
    private static final String VALUES = "VALUES";
    private static final String UPDATE = "UPDATE";
    private static final String DELETE_FROM = "DELETE FROM";
    private static final String COUNT = "COUNT";
    private static final String OPEN_BRACKET = "(";
    private static final String CLOSE_BRACKET = ")";
    private static final String BRACKET_NULL = "(NULL)";

    private static final String SCRIPT_HEAD = "<script>";
    private static final String SCRIPT_END = "</script>";

    private static final String WHERE_HEAD = "<where>";
    private static final String WHERE_END = "</where>";

    private static final String IF_HEAD_LIST_NOT_BLANK = "<if test = \"list != null and list.size() > 0\">";
    private static final String IF_HEAD_LIST_BLANK = "<if test = \"list == null or list.size() == 0\">";
    private static final String IF_HEAD_PREFIX = "<if test = \"";
    private static final String IF_HEAD_SUFFIX = " != null\">";
    private static final String IF_END = "</if>";

    private static final String SCRIPT_TYPE = "</";

    private static final String TRIM_HEAD_BRACKET = "<trim prefix=\"(\" suffix=\")\" suffixOverrides=\",\">";
    private static final String TRIM_END = "</trim>";

    private static final String SET_HEAD = "<set>";
    private static final String SET_END = "</set>";

    /**
     * foreach 要做foreach的对象,作为入参时,List对象默认用"list"代替作为键,数组对象有"array"代替作为键
     * 在作为入参时可以使用@Param("keyName")来设置键,设置keyName后,list,array将会失效。
     * 除了入参这种情况外,还有一种作为参数对象的某个字段的时候。举个例子:如果User有属性List ids。入参是User对象,那么这个collection = "ids"
     */
    private static final String FOREACH_HEAD_LIST = "<foreach item = \"item\" collection = \"list\" separator = \",\" index = \"index\">";
    private static final String FOREACH_HEAD_BRACKET_LIST = "<foreach item = \"item\" collection = \"list\" separator = \",\" open=\"(\" close=\")\" index = \"index\">";

    private static final String FOREACH_ITEM = "#{item}";
    private static final String FOREACH_END = "</foreach>";

    private static final String EQUALS = " = ";
    private static final String COMMA = ",";
    private static final String COMMA_CRLF_TAB = ",\n\t";
    private static final String COMMA_CRLF_TAB_TAB = ",\n\t\t";

    private final StringBuilder sql;

    public Sql() {
        this.sql = new StringBuilder();
    }

    public Sql sql() {
        return this;
    }

    public Sql sql(String str) {
        sql.append(str);
        return this;
    }

    public Sql crlf() {
        return sql("\n");
    }

    public Sql tab() {
        return sql("\t");
    }

    public Sql select(String... fields) {
        List<String> columns = Arrays.stream(fields).map(StrUtil::toUnderlineCase).collect(Collectors.toList());
        sql(SELECT).crlf();
        tab().sql(String.join(COMMA_CRLF_TAB, columns)).crlf();
        return this;
    }

    public Sql selectCount(String field) {
        sql(SELECT).crlf();
        tab().sql(COUNT).sql(OPEN_BRACKET).sql(field).sql(CLOSE_BRACKET).crlf();
        return this;
    }

    public Sql from(String tableName) {
        sql(FROM).crlf();
        tab().sql(tableName).crlf();
        return this;
    }

    public Sql where(String... fields) {
        List<String> conditions = Arrays.stream(fields).map(this::ifAndColumnFieldRel).collect(Collectors.toList());
        sql(WHERE_HEAD).crlf();
        sql(String.join("", conditions));
        sql(WHERE_END).crlf();
        return this;
    }

    public Sql whereCriteria(String... criteriaKeys) {
        List<String> conditions = Arrays.stream(criteriaKeys).map(criteria::ifAndCriteriaRel).collect(Collectors.toList());
        sql(WHERE_HEAD).crlf();
        sql(String.join("", conditions));
        sql(WHERE_END).crlf();
        return this;
    }

    public Sql whereId(String id){
        sql(WHERE_HEAD).crlf();
        sql(columnFieldRel(id));
        sql(WHERE_END).crlf();
        return this;
    }

    public Sql whereIn(String field) {
        sql(WHERE).crlf();
        foreachIn(field);
        return this;
    }

    /**
     * 插入不为null的字段
     */
    public Sql insertInto(String tableName, String... fields) {
        String[] ifColumns = Arrays.stream(fields).map(this::ifColumnComma).toArray(String[]::new);
        sql(INSERT_INTO).crlf();
        tab().sql(tableName).crlf();
        tab().trimHeadBracket();
        sql(String.join("", ifColumns));
        tab().trimEnd();
        return this;
    }

    public Sql insertIntoBatch(String tableName, String... fields) {
        String[] columns = Arrays.stream(fields).map(StrUtil::toUnderlineCase).toArray(String[]::new);
        sql(INSERT_INTO).crlf();
        tab().sql(tableName).sql(OPEN_BRACKET).crlf();
        tab().tab().sql(String.join(COMMA_CRLF_TAB_TAB, columns)).crlf();
        tab().sql(CLOSE_BRACKET).crlf();
        return this;
    }

    public Sql values(String... fields) {
        String[] ifFields = Arrays.stream(fields).map(this::ifHashFieldComma).toArray(String[]::new);
        sql(VALUES).crlf();
        tab().trimHeadBracket();
        sql(String.join("", ifFields));
        tab().trimEnd();
        return this;
    }

    public Sql valuesBatch(String... fields) {
        String[] hashListFields = Arrays.stream(fields).map(this::hashListField).toArray(String[]::new);
        sql(VALUES).crlf();
        tab().foreachHeadList();
        tab().trimHeadBracket();
        tab().tab().sql(String.join(COMMA_CRLF_TAB_TAB, hashListFields)).crlf();
        tab().trimEnd();
        tab().foreachEnd();
        return this;
    }


    public Sql update(String tableName) {
        sql(UPDATE).crlf();
        tab().sql(tableName).crlf();
        return this;
    }

    public Sql set(String... fields) {
        List<String> conditions = Arrays.stream(fields).map(this::ifColumnFieldRelComma).collect(Collectors.toList());
        sql(SET_HEAD).crlf();
        sql(String.join("", conditions)).crlf();
        sql(SET_END).crlf();
        return this;
    }
    public Sql deleteFrom(String tableName) {
        sql(DELETE_FROM).crlf();
        tab().sql(tableName).crlf();
        return this;
    }


    public Sql in() {
        return sql(IN);
    }

    public Sql ifHeadListNotBlank() {
        return sql(IF_HEAD_LIST_NOT_BLANK).crlf();
    }

    public Sql ifHeadListBlank() {
        return sql(IF_HEAD_LIST_BLANK).crlf();
    }

    public Sql ifHead(String field) {
        return sql(IF_HEAD_PREFIX).sql(field).sql(IF_HEAD_SUFFIX).crlf();
    }

    public Sql ifEnd() {
        return sql(IF_END).crlf();
    }

    public Sql bracketNull() {
        return sql(BRACKET_NULL).crlf();
    }

    public Sql foreachHeadBracketList() {
        return sql(FOREACH_HEAD_BRACKET_LIST).crlf();
    }

    public Sql foreachHeadList() {
        return sql(FOREACH_HEAD_LIST).crlf();
    }

    public Sql foreachItem() {
        return sql(FOREACH_ITEM).crlf();
    }

    public Sql foreachEnd() {
        return sql(FOREACH_END).crlf();
    }

    public Sql trimHeadBracket() {
        return sql(TRIM_HEAD_BRACKET).crlf();
    }

    public Sql trimEnd() {
        return sql(TRIM_END).crlf();
    }

    public Sql foreachIn(String field) {
        tab().sql(StrUtil.toUnderlineCase(field)).in().crlf();
        tab().ifHeadListNotBlank();
        tab().tab().foreachHeadBracketList();
        tab().tab().tab().foreachItem();
        tab().tab().foreachEnd();
        tab().ifEnd();
        tab().ifHeadListBlank();
        tab().tab().bracketNull();
        tab().ifEnd();
        return this;
    }

    @Override
    public String toString() {
        return sql.toString();
    }

    public String build() {
        if (sql.toString().contains(SCRIPT_TYPE)) {
            return SCRIPT_HEAD + "\n" + sql.toString() + SCRIPT_END;
        }
        return sql.toString();
    }

    private String columnFieldRel(String field, String rel) {
        return StrUtil.toUnderlineCase(field) + " " + rel + " " + hashField(field);
    }

    private String columnFieldRel(String field) {
        return columnFieldRel(field, EQUALS);
    }

    private String andColumnFieldRel(String field) {
        return andColumnFieldRel(field, EQUALS);
    }


    private String andColumnFieldRel(String field, String rel) {
        return AND + columnFieldRel(field, rel);
    }

    private String columnFieldRelComma(String field) {
        return columnFieldRelComma(field, EQUALS);
    }

    private String columnFieldRelComma(String field, String rel) {
        return columnFieldRel(field, rel) + COMMA;
    }

    public String ifColumnComma(String field) {
        return ifScript(field, StrUtil.toUnderlineCase(field) + COMMA);
    }

    public String ifHashFieldComma(String field) {
        return ifScript(field, hashField(field) + COMMA);
    }

    public String ifColumnFieldRel(String field) {
        return ifScript(field, columnFieldRel(field));
    }

    public String ifAndColumnFieldRel(String field) {
        return ifScriptForQuery(field, andColumnFieldRel(field));
    }

    private Sql ifHeadNotEmpty(String field) {
        return sql(IF_HEAD_PREFIX).sql(field).sql(" != null and ").sql(field).sql(".toString() != '' \">").crlf();
    }

    public String ifColumnFieldRelComma(String field) {
        return ifScript(field, columnFieldRelComma(field));
    }

    public String ifScript(String field, String express) {
        return new Sql()
                .tab().ifHead(field)
                .tab().tab().sql(express).crlf()
                .tab().ifEnd().toString();
    }

    public String ifScriptForQuery(String field, String express) {
        return new Sql()
                .tab().ifHeadNotEmpty(field)
                .tab().tab().sql(express).crlf()
                .tab().ifEnd().toString();
    }

    public String ifScriptForQueryCriteria(String field, String express) {
        return new Sql()
                .tab().ifHead(field)
                .tab().tab().sql(express).crlf()
                .tab().ifEnd().toString();
    }

    private String hashField(String field) {
        return "#{" + field + "}";
    }

    private String hashListField(String field) {
        return "#{item." + field + "}";
    }

    public class Criteria {
        private final static String CRITERIA_LIKE = "_like";
        private final static String CRITERIA_LIKE_RIGHT = "_likeRight";
        private final static String CRITERIA_LIKE_LEFT = "_likeLeft";
        private final static String CRITERIA_LT = "_lt";
        private final static String CRITERIA_GT = "_gt";
        private final static String CRITERIA_LTE = "_lte";
        private final static String CRITERIA_GTE = "_gte";
        private final static String CRITERIA_IN = "_in";
        private final static String CRITERIA_NOT_EQ = "_ne";
        private final static String CRITERIA_IS_NULL = "_isNull";
        private final static String CRITERIA_NOT_NULL = "_notNull";
        private final static String CRITERIA_BETWEEN = "_between";
        private final static String LIKE = " like ";
        private final static String CONCAT = " concat";
        private final static String PERCENT = "'%'";
        private final static String EMPTY = " ";
        private final static String LT = " &lt; ";
        private final static String LTE = " &lt;= ";
        private final static String GT = " &gt; ";
        private final static String GTE = " &gt;= ";

        private final static String BETWEEN = " between ";

        private String concat(String... express) {
            return CONCAT.concat(OPEN_BRACKET).concat(String.join(",",express)).concat(CLOSE_BRACKET).concat(EMPTY);
        }
        private String andColumnCriteriaRel(String criteria) {
            if (criteria.endsWith(CRITERIA_LIKE)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_LIKE.length()));
                return AND + field + LIKE + concat(PERCENT, hashField(criteria), PERCENT);
            } else if (criteria.endsWith(CRITERIA_LIKE_LEFT)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_LIKE_LEFT.length()));
                return AND + field + LIKE + concat(PERCENT, hashField(criteria));
            } else if (criteria.endsWith(CRITERIA_LIKE_RIGHT)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_LIKE_RIGHT.length()));
                return AND + field + LIKE + concat(hashField(criteria), PERCENT);
            } else if (criteria.endsWith(CRITERIA_LT)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_LT.length()));
                return AND + field + LT + hashField(criteria);
            } else if (criteria.endsWith(CRITERIA_GT)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_GT.length()));
                return AND + field + GT + hashField(criteria);
            } else if (criteria.endsWith(CRITERIA_LTE)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_LTE.length()));
                return AND + field + LTE + hashField(criteria);
            } else if (criteria.endsWith(CRITERIA_GTE)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_GTE.length()));
                return AND + field + GTE + hashField(criteria);
            } else if (criteria.endsWith(CRITERIA_IN)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_IN.length()));
                return foreachIn(field, criteria);
            } else if (criteria.endsWith(CRITERIA_BETWEEN)){
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_BETWEEN.length()));
                return AND + field + BETWEEN + hashField(criteria + "[0]") + AND + hashField(criteria + "[1]");
            } else if (criteria.endsWith(CRITERIA_NOT_EQ)){
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_NOT_EQ.length()));
                return AND + field + " != " + hashField(criteria);
            } else if (criteria.endsWith(CRITERIA_IS_NULL)) {
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_IS_NULL.length()));
                return AND + field + " is null ";
            } else if (criteria.endsWith(CRITERIA_NOT_NULL)){
                String field = StrUtil.toUnderlineCase(criteria.substring(0, criteria.length() - CRITERIA_NOT_NULL.length()));
                return AND + field + " is not null ";
            }else {
                return andColumnFieldRel(criteria, EQUALS);
            }
        }

        public String ifAndCriteriaRel(String criteria) {
            return ifScriptForQuery(criteria,andColumnCriteriaRel(criteria));
        }

        private String foreachIn(String field, String listName) {
            return String.format(
                    " <choose> " +
                            " <when test = '%s.length > 0' > " +
                            " AND %s in " +
                            " <foreach item = \"item\" collection = \"%1$s\" separator = \",\" open=\"(\" close=\")\" > " +
                            "  #{item}" +
                            " </foreach>" +
                            " </when> " +
                            " <otherwise> " +
                            " AND 1 = 2 " +
                            " </otherwise> " +
                            " </choose> "
                    , listName, field);
        }
    }

}

3. [Sql.java]

文件作用: SQL构建器,使用Builder模式动态构建MyBatis动态SQL

设计特点:

支持的查询条件(通过Map参数):

后缀 含义 示例
_like 模糊查询(全匹配) name_like → LIKE '%xxx%'
_likeLeft 左模糊 name_likeLeft → LIKE '%xxx'
_likeRight 右模糊 name_likeRight → LIKE 'xxx%'
_lt 小于 age_lt → < xxx
_gt 大于 age_gt → > xxx
_lte 小于等于 age_lte → ≤ xxx
_gte 大于等于 age_gte → ≥ xxx
_in IN查询 id_in → IN (x,x,x)
_ne 不等于 status_ne → != xxx
_isNull 为空 field_isNull → IS NULL
_notNull 不为空 field_notNull → IS NOT NULL
_between 区间查询 age_between → BETWEEN x AND y

生成的SQL示例:

// insert方法生成的SQL:
<script>
INSERT INTO
    user
    (<trim prefix="(" suffix=")" suffixOverrides=",">
        <if test = "id != null">id,</if>
        <if test = "name != null">name,</if>
    </trim>)
VALUES
    (<trim prefix="(" suffix=")" suffixOverrides=",">
        <if test = "id != null">#{id},</if>
        <if test = "name != null">#{name},</if>
    </trim>)
</script>

IgnoreField.java

package com.dpb.yunc.db.mapper.common;

import java.lang.annotation.*;

@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface IgnoreField {
}

4. [IgnoreField.java]

文件作用: 自定义注解,用于标记实体类中需要被忽略的字段

详细说明:

整体架构优势

  1. 零配置:无需编写XML映射文件
  2. 约定优于配置:遵循命名约定自动映射
  3. 可扩展:通过继承BaseMapper获得通用CRUD
  4. 智能适配:自动判断逻辑删除/物理删除
  5. 高性能:SQL缓存避免重复解析