Prechádzať zdrojové kódy

提供基于索引生成基础方法. (#6652)

https://github.com/baomidou/mybatis-plus/issues/6572
nieqiurong 4 mesiacov pred
rodič
commit
0b1f60fcdb
15 zmenil súbory, kde vykonal 748 pridanie a 9 odobranie
  1. 48 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/IGenerateMapperMethodHandler.java
  2. 32 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/builder/Mapper.java
  3. 24 1
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java
  4. 73 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/AbstractMapperMethodHandler.java
  5. 156 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/DefaultGenerateMapperLambdaMethodHandler.java
  6. 155 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/DefaultGenerateMapperMethodHandler.java
  7. 56 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapper.java
  8. 79 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/model/MapperMethod.java
  9. 5 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/query/DefaultQuery.java
  10. 54 0
      mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/util/KotlinTypeUtils.java
  11. 15 2
      mybatis-plus-generator/src/main/resources/templates/mapper.java.btl
  12. 16 2
      mybatis-plus-generator/src/main/resources/templates/mapper.java.ej
  13. 17 2
      mybatis-plus-generator/src/main/resources/templates/mapper.java.ftl
  14. 17 2
      mybatis-plus-generator/src/main/resources/templates/mapper.java.vm
  15. 1 0
      mybatis-plus-generator/src/test/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapperTest.java

+ 48 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/IGenerateMapperMethodHandler.java

@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator;
+
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.model.MapperMethod;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Mapper层方法生成处理器
+ *
+ * @author nieqiurong
+ * @since 3.5.10
+ */
+public interface IGenerateMapperMethodHandler {
+
+    /**
+     * 获取生成方法
+     *
+     * @param tableInfo 表信息
+     * @return 索引方法
+     */
+    List<MapperMethod> getMethodList(TableInfo tableInfo);
+
+    /**
+     * 获取需要导入的包
+     *
+     * @param tableInfo 表信息
+     * @return 导包列表
+     */
+    Set<String> getImportPackages(TableInfo tableInfo);
+
+}

+ 32 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/builder/Mapper.java

@@ -20,6 +20,8 @@ import com.baomidou.mybatisplus.generator.config.ConstVal;
 import com.baomidou.mybatisplus.generator.config.StrategyConfig;
 import com.baomidou.mybatisplus.generator.config.po.TableInfo;
 import com.baomidou.mybatisplus.generator.function.ConverterFileName;
+import com.baomidou.mybatisplus.generator.IGenerateMapperMethodHandler;
+import com.baomidou.mybatisplus.generator.model.MapperMethod;
 import com.baomidou.mybatisplus.generator.util.ClassUtils;
 import lombok.Getter;
 import org.apache.ibatis.cache.Cache;
@@ -29,8 +31,11 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import java.lang.annotation.Annotation;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * 控制器属性配置
@@ -160,6 +165,13 @@ public class Mapper implements ITemplate {
         return this.cache == null ? LoggingCache.class : this.cache;
     }
 
+    /**
+     * Mapper层方法生成
+     *
+     * @since 3.5.10
+     */
+    private IGenerateMapperMethodHandler generateMapperMethodHandler;
+
     @Override
     @NotNull
     public Map<String, Object> renderData(@NotNull TableInfo tableInfo) {
@@ -179,6 +191,14 @@ public class Mapper implements ITemplate {
         data.put("superMapperClass", ClassUtils.getSimpleName(this.superClass));
         data.put("generateMapperXml", this.generateMapperXml);
         data.put("generateMapper", this.generateMapper);
+        List<MapperMethod> methodList = null;
+        Set<String> importPackages = null;
+        if (generateMapperMethodHandler != null) {
+            methodList = generateMapperMethodHandler.getMethodList(tableInfo);
+            importPackages = generateMapperMethodHandler.getImportPackages(tableInfo);
+        }
+        data.put("importPackages", importPackages == null ? Collections.emptySet() : importPackages);
+        data.put("mapperMethodList", methodList == null ? Collections.emptyList() : methodList);
         return data;
     }
 
@@ -396,6 +416,18 @@ public class Mapper implements ITemplate {
             return this;
         }
 
+        /**
+         * Mapper层方法生成处理器
+         *
+         * @param generateMapperMethodHandler 处理器
+         * @return this
+         * @since 3.5.10
+         */
+        public Builder generateMapperMethodHandler(IGenerateMapperMethodHandler generateMapperMethodHandler) {
+            this.mapper.generateMapperMethodHandler = generateMapperMethodHandler;
+            return this;
+        }
+
         @NotNull
         public Mapper get() {
             return this.mapper;

+ 24 - 1
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/config/po/TableInfo.java

@@ -23,7 +23,9 @@ import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
 import com.baomidou.mybatisplus.generator.config.builder.Entity;
 import com.baomidou.mybatisplus.generator.config.builder.Service;
 import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
+import com.baomidou.mybatisplus.generator.jdbc.DatabaseMetaDataWrapper;
 import lombok.Getter;
+import lombok.Setter;
 import org.jetbrains.annotations.NotNull;
 
 import java.io.Serializable;
@@ -42,11 +44,13 @@ public class TableInfo {
     /**
      * 策略配置
      */
+    @Getter
     private final StrategyConfig strategyConfig;
 
     /**
      * 全局配置信息
      */
+    @Getter
     private final GlobalConfig globalConfig;
 
     /**
@@ -134,6 +138,23 @@ public class TableInfo {
      */
     private final Entity entity;
 
+    /**
+     * 索引信息
+     *
+     * @since 3.5.10
+     */
+    @Setter
+    @Getter
+    private List<DatabaseMetaDataWrapper.Index> indexList;
+
+    /**
+     * 字段信息
+     *
+     * @since 3.5.10
+     */
+    @Getter
+    private final Map<String, TableField> tableFieldMap = new HashMap<>();
+
     /**
      * 构造方法
      *
@@ -184,7 +205,9 @@ public class TableInfo {
         if (entity.matchIgnoreColumns(field.getColumnName())) {
             // 忽略字段不在处理
             return;
-        } else if (entity.matchSuperEntityColumns(field.getColumnName())) {
+        }
+        tableFieldMap.put(field.getName(), field);
+        if (entity.matchSuperEntityColumns(field.getColumnName())) {
             this.commonFields.add(field);
         } else {
             this.fields.add(field);

+ 73 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/AbstractMapperMethodHandler.java

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator.index;
+
+import com.baomidou.mybatisplus.generator.IGenerateMapperMethodHandler;
+
+/**
+ * @author nieqiurong
+ * @since 3.5.10
+ */
+public abstract class AbstractMapperMethodHandler implements IGenerateMapperMethodHandler {
+
+    /**
+     * 生成Java方法(default)
+     * <pre>
+     * default ${returnValue} ${methodName}(${args}) {
+     *    return ${returnBody};
+     * }
+     * <pre/>
+     * Example:
+     * <pre>
+     * default UserInfo selectByCardNo(String cardNo) {
+     *    return selectOne(Wrappers.<UserInfo>query().eq(TUserInfo.CARD_NO, cardNo));
+     * }
+     * </pre>
+     */
+    public String buildMethod(String methodName, String args, String returnValue, String returnBody) {
+        return "default" + " " +
+            returnValue + " " + methodName + "(" + args + ")" + " " + "{" + "\n" +
+            "        return " + returnBody + ";" + "\n" +
+            "    }\n";
+    }
+
+    /**
+     * 构建Kotlin方法
+     * <pre>
+     * fun ${methodName}(${args}) :${returnValue} {
+     *    return ${returnBody};
+     * }
+     * </pre>
+     * Example:
+     * <pre>
+     * fun selectByCardNo(cardNo: String) :UserInfo? {
+     *    return selectOne(Wrappers.query<UserInfo>().eq(UserInfo.CARD_NO, cardNo));
+     * }
+     * </pre>
+     *
+     * @param methodName  方法名
+     * @param args        参数列表
+     * @param returnValue 返回值
+     * @param returnBody  返回体
+     * @return 方法
+     */
+    public String buildKotlinMethod(String methodName, String args, String returnValue, String returnBody) {
+        return "fun " + methodName + "(" + args + ")" + " :" + returnValue + " {" + "\n" +
+            "        return " + returnBody + ";" + "\n" +
+            "    }\n";
+    }
+
+}

+ 156 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/DefaultGenerateMapperLambdaMethodHandler.java

@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator.index;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper;
+import com.baomidou.mybatisplus.extension.kotlin.KtUpdateWrapper;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.jdbc.DatabaseMetaDataWrapper;
+import com.baomidou.mybatisplus.generator.model.MapperMethod;
+import com.baomidou.mybatisplus.generator.util.KotlinTypeUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 使用Lambda方式生成索引方法
+ *
+ * @author nieqiurong
+ * @since 3.5.10
+ */
+public class DefaultGenerateMapperLambdaMethodHandler extends AbstractMapperMethodHandler {
+
+    @Override
+    public List<MapperMethod> getMethodList(TableInfo tableInfo) {
+        Map<String, List<DatabaseMetaDataWrapper.Index>> indexlistMap = tableInfo.getIndexList().stream()
+            .collect(Collectors.groupingBy(DatabaseMetaDataWrapper.Index::getName));
+        String entityName = tableInfo.getEntityName();
+        GlobalConfig globalConfig = tableInfo.getGlobalConfig();
+        Set<Map.Entry<String, List<DatabaseMetaDataWrapper.Index>>> entrySet = indexlistMap.entrySet();
+        List<MapperMethod> methodList = new ArrayList<>();
+        for (Map.Entry<String, List<DatabaseMetaDataWrapper.Index>> entry : entrySet) {
+            String indexName = entry.getKey();
+            List<DatabaseMetaDataWrapper.Index> indexList = entry.getValue();
+            int indexSize = indexList.size();
+            if ("PRIMARY".equals(indexName)) {
+                if (indexSize == 1) {
+                    continue;
+                }
+            }
+            Map<String, TableField> tableFieldMap = tableInfo.getTableFieldMap();
+            StringBuilder baseMethodNameBuilder = new StringBuilder();
+            StringBuilder argsBuilder = new StringBuilder();
+            StringBuilder baseWrapperBuilder = new StringBuilder();
+            boolean uniqueKey = false;
+            List<TableField> tableFieldList = new ArrayList<>();
+            for (int i = 0; i < indexSize; i++) {
+                DatabaseMetaDataWrapper.Index index = indexList.get(i);
+                if (index.isUnique()) {
+                    uniqueKey = true;
+                }
+                TableField tableField = tableFieldMap.get(index.getColumnName());
+                tableFieldList.add(tableField);
+                baseMethodNameBuilder.append(tableField.getCapitalName());
+                if (indexSize > 1) {
+                    baseWrapperBuilder.append("eq(ObjectUtils.isNotNull(").append(tableField.getPropertyName()).append(")").append(", ").append(entityName).append("::");
+                } else {
+                    baseWrapperBuilder.append("eq(").append(entityName).append("::");
+                }
+                if (globalConfig.isKotlin()) {
+                    baseWrapperBuilder.append(tableField.getPropertyName()).append(",").append(" ").append(tableField.getPropertyName()).append(")");
+                    argsBuilder.append(tableField.getPropertyName()).append(":").append(" ")
+                        .append(KotlinTypeUtils.getStringType(tableField.getColumnType()));
+                } else {
+                    if ("boolean".equals(tableField.getPropertyType())) {
+                        baseWrapperBuilder.append("is").append(tableField.getCapitalName());
+                    } else {
+                        baseWrapperBuilder.append("get").append(tableField.getCapitalName());
+                    }
+                    baseWrapperBuilder.append(",").append(" ").append(tableField.getPropertyName()).append(")");
+                    argsBuilder.append(tableField.getColumnType().getType()).append(" ").append(tableField.getPropertyName());
+                }
+                if (i < indexSize - 1) {
+                    baseWrapperBuilder.append(".");
+                    baseMethodNameBuilder.append("And");
+                    argsBuilder.append(", ");
+                }
+            }
+            boolean returnList = (indexSize > 1 || !uniqueKey);
+            String baseMethodName = baseMethodNameBuilder.toString();
+            String args = argsBuilder.toString();
+            String baseWrapper = baseWrapperBuilder.toString();
+            if (globalConfig.isKotlin()) {
+                String selectByMethod;
+                if (returnList) {
+                    selectByMethod = buildKotlinMethod("selectBy" + baseMethodName, args, "List<" + tableInfo.getEntityName() + ">?",
+                        "selectList(KtQueryWrapper(" + tableInfo.getEntityName() + "::class.java)." + baseWrapper + ")");
+                } else {
+                    selectByMethod = buildKotlinMethod("selectBy" + baseMethodName, args, tableInfo.getEntityName() + "?",
+                        "selectOne(KtQueryWrapper(" + tableInfo.getEntityName() + "::class.java)." + baseWrapper + ")");
+                }
+                String updateByMethod = buildKotlinMethod("updateBy" + baseMethodName, "entity:" + " " + tableInfo.getEntityName() + ", " + args, "Int",
+                    "update(entity, KtUpdateWrapper(" + tableInfo.getEntityName() + "::class.java)." + baseWrapper + ")");
+                String deleteByMethod = buildKotlinMethod("deleteBy" + baseMethodName, args, "Int",
+                    "delete(KtUpdateWrapper(" + tableInfo.getEntityName() + "::class.java)." + baseWrapper + ")");
+                methodList.add(new MapperMethod(indexName, selectByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, updateByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, deleteByMethod, tableFieldList));
+            } else {
+                String selectByMethod;
+                if (returnList) {
+                    selectByMethod = buildMethod("selectBy" + baseMethodName, args, "List<" + entityName + ">",
+                        "selectList(Wrappers.<" + tableInfo.getEntityName() + ">lambdaQuery()." + baseWrapper + ")");
+                } else {
+                    selectByMethod = buildMethod("selectBy" + baseMethodName, args, entityName,
+                        "selectOne(Wrappers.<" + tableInfo.getEntityName() + ">lambdaQuery()." + baseWrapper + ")");
+                }
+                String updateByMethod = buildMethod(
+                    "updateBy" + baseMethodName, tableInfo.getEntityName() + " entity" + ", " + args,
+                    "int", "update(entity, Wrappers.<" + tableInfo.getEntityName() + ">lambdaUpdate()." + baseWrapper + ")");
+                String deleteByMethod = buildMethod("deleteBy" + baseMethodName, args, "int",
+                    "delete(Wrappers.<" + tableInfo.getEntityName() + ">lambdaUpdate()." + baseWrapper + ")");
+                methodList.add(new MapperMethod(indexName, selectByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, updateByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, deleteByMethod, tableFieldList));
+            }
+        }
+        return methodList;
+    }
+
+    @Override
+    public Set<String> getImportPackages(TableInfo tableInfo) {
+        GlobalConfig globalConfig = tableInfo.getGlobalConfig();
+        Set<String> imports = new HashSet<>();
+        imports.add(ObjectUtils.class.getName());
+        imports.add(List.class.getName());
+        if (globalConfig.isKotlin()) {
+            imports.add(KtQueryWrapper.class.getName());
+            imports.add(KtUpdateWrapper.class.getName());
+        } else {
+            imports.add(Wrappers.class.getName());
+        }
+        return imports;
+    }
+
+}

+ 155 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/index/DefaultGenerateMapperMethodHandler.java

@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator.index;
+
+import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.generator.config.GlobalConfig;
+import com.baomidou.mybatisplus.generator.config.builder.Entity;
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+import com.baomidou.mybatisplus.generator.config.po.TableInfo;
+import com.baomidou.mybatisplus.generator.jdbc.DatabaseMetaDataWrapper;
+import com.baomidou.mybatisplus.generator.model.MapperMethod;
+import com.baomidou.mybatisplus.generator.util.KotlinTypeUtils;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * 按字符串或者字符串常量方法生成查询条件
+ *
+ * @author nieqiurong
+ * @see Entity.Builder#enableColumnConstant()
+ * @since 3.5.10
+ */
+public class DefaultGenerateMapperMethodHandler extends AbstractMapperMethodHandler {
+
+    @Override
+    public List<MapperMethod> getMethodList(TableInfo tableInfo) {
+        Map<String, List<DatabaseMetaDataWrapper.Index>> indexlistMap = tableInfo.getIndexList().stream()
+            .collect(Collectors.groupingBy(DatabaseMetaDataWrapper.Index::getName));
+        String entityName = tableInfo.getEntityName();
+        GlobalConfig globalConfig = tableInfo.getGlobalConfig();
+        Entity entity = tableInfo.getStrategyConfig().entity();
+        boolean columnConstant = entity.isColumnConstant();
+        Set<Map.Entry<String, List<DatabaseMetaDataWrapper.Index>>> entrySet = indexlistMap.entrySet();
+        List<MapperMethod> methodList = new ArrayList<>();
+        for (Map.Entry<String, List<DatabaseMetaDataWrapper.Index>> entry : entrySet) {
+            String indexName = entry.getKey();
+            List<DatabaseMetaDataWrapper.Index> indexList = entry.getValue();
+            int indexSize = indexList.size();
+            if ("PRIMARY".equals(indexName)) {
+                if (indexSize == 1) {
+                    continue;
+                }
+            }
+            List<TableField> tableFieldList = new ArrayList<>();
+            Map<String, TableField> tableFieldMap = tableInfo.getTableFieldMap();
+            StringBuilder baseMethodNameBuilder = new StringBuilder();
+            StringBuilder argsBuilder = new StringBuilder();
+            StringBuilder baseWrapperBuilder = new StringBuilder();
+            boolean uniqueKey = false;
+            for (int i = 0; i < indexSize; i++) {
+                DatabaseMetaDataWrapper.Index index = indexList.get(i);
+                if (index.isUnique()) {
+                    uniqueKey = true;
+                }
+                TableField tableField = tableFieldMap.get(index.getColumnName());
+                tableFieldList.add(tableField);
+                baseMethodNameBuilder.append(tableField.getCapitalName());
+                if (indexSize > 1) {
+                    if (columnConstant) {
+                        baseWrapperBuilder.append("eq(ObjectUtils.isNotNull(").append(tableField.getPropertyName()).append(")").append(", ").append(entityName).append(".").append(tableField.getName().toUpperCase());
+                    } else {
+                        baseWrapperBuilder.append("eq(ObjectUtils.isNotNull(").append(tableField.getPropertyName()).append(")").append(", ").append("\"").append(tableField.getColumnName()).append("\"");
+                    }
+                } else {
+                    if (columnConstant) {
+                        baseWrapperBuilder.append("eq(").append(entityName).append(".").append(tableField.getName().toUpperCase());
+                    } else {
+                        baseWrapperBuilder.append("eq(").append("\"").append(tableField.getColumnName()).append("\"");
+                    }
+                }
+                baseWrapperBuilder.append(",").append(" ").append(tableField.getPropertyName()).append(")");
+                if (globalConfig.isKotlin()) {
+                    argsBuilder.append(tableField.getPropertyName()).append(":").append(" ")
+                        .append(KotlinTypeUtils.getStringType(tableField.getColumnType()));
+                } else {
+                    argsBuilder.append(tableField.getColumnType().getType()).append(" ").append(tableField.getPropertyName());
+                }
+                if (i < indexSize - 1) {
+                    baseWrapperBuilder.append(".");
+                    baseMethodNameBuilder.append("And");
+                    argsBuilder.append(", ");
+                }
+            }
+            String baseMethodName = baseMethodNameBuilder.toString();
+            String args = argsBuilder.toString();
+            String baseWrapper = baseWrapperBuilder.toString();
+            boolean returnList = (indexSize > 1 || !uniqueKey);
+            if (globalConfig.isKotlin()) {
+                String selectByMethod;
+                if (returnList) {
+                    selectByMethod = buildKotlinMethod("selectBy" + baseMethodName, args,
+                        "List<" + tableInfo.getEntityName() + ">?", "selectList(Wrappers.query<" + tableInfo.getEntityName() + ">()." + baseWrapper + ")");
+                } else {
+                    selectByMethod = buildKotlinMethod("selectBy" + baseMethodName, args,
+                        tableInfo.getEntityName() + "?", "selectOne(Wrappers.query<" + tableInfo.getEntityName() + ">()." + baseWrapper + ")");
+                }
+                String updateByMethod = buildKotlinMethod("updateBy" + baseMethodName, "entity:" + " " + tableInfo.getEntityName() + ", " + args,
+                    "Int", "update(entity, Wrappers.update<" + tableInfo.getEntityName() + ">()." + baseWrapper + ")");
+                String deleteByMethod = buildKotlinMethod("deleteBy" + baseMethodName, args,
+                    "Int", "delete(Wrappers.update<" + tableInfo.getEntityName() + ">()." + baseWrapper + ")");
+                methodList.add(new MapperMethod(indexName, selectByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, updateByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, deleteByMethod, tableFieldList));
+            } else {
+                String selectByMethod;
+                if (returnList) {
+                    selectByMethod = buildMethod("selectBy" + baseMethodName, args, "List<" + tableInfo.getEntityName() + ">",
+                        "selectList(Wrappers.<" + tableInfo.getEntityName() + ">query()." + baseWrapper + ")");
+                } else {
+                    selectByMethod = buildMethod("selectBy" + baseMethodName, args, tableInfo.getEntityName(),
+                        "selectOne(Wrappers.<" + tableInfo.getEntityName() + ">query()." + baseWrapper + ")");
+                }
+
+                String updateByMethod = buildMethod(
+                    "updateBy" + baseMethodName, tableInfo.getEntityName() + " entity" + ", " + args, "int",
+                    "update(entity, Wrappers.<" + tableInfo.getEntityName() + ">update()." + baseWrapper + ")");
+                String deleteByMethod = buildMethod("deleteBy" + baseMethodName, args, "int",
+                    "delete(Wrappers.<" + tableInfo.getEntityName() + ">update()." + baseWrapper + ")");
+                methodList.add(new MapperMethod(indexName, selectByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, updateByMethod, tableFieldList));
+                methodList.add(new MapperMethod(indexName, deleteByMethod, tableFieldList));
+            }
+        }
+        return methodList;
+    }
+
+    @Override
+    public Set<String> getImportPackages(TableInfo tableInfo) {
+        Set<String> imports = new HashSet<>();
+        imports.add(ObjectUtils.class.getName());
+        imports.add(List.class.getName());
+        imports.add(Wrappers.class.getName());
+        return imports;
+    }
+
+}

+ 56 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapper.java

@@ -19,6 +19,7 @@ import com.baomidou.mybatisplus.core.toolkit.StringPool;
 import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import lombok.Getter;
 import lombok.Setter;
+import lombok.ToString;
 import org.apache.ibatis.type.JdbcType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -78,6 +79,22 @@ public class DatabaseMetaDataWrapper {
         return getColumnsInfo(this.catalog, this.schema, tableNamePattern, queryPrimaryKey);
     }
 
+    public List<DatabaseMetaDataWrapper.Index> getIndex(String tableName) {
+        List<DatabaseMetaDataWrapper.Index> indexList = new ArrayList<>();
+        try (ResultSet resultSet = databaseMetaData.getIndexInfo(catalog, schema, tableName, false, false)) {
+            while (resultSet.next()) {
+                Index index = new Index(resultSet);
+                // skip function index
+                if (StringUtils.isNotBlank(index.getColumnName())) {
+                    indexList.add(new Index(resultSet));
+                }
+            }
+        } catch (SQLException e) {
+            throw new RuntimeException("读取索引信息:" + tableName + "错误:", e);
+        }
+        return indexList;
+    }
+
     /**
      * 获取表字段信息
      *
@@ -223,4 +240,43 @@ public class DatabaseMetaDataWrapper {
         private boolean generatedColumn;
 
     }
+
+    @Getter
+    @ToString
+    public static class Index {
+
+        /**
+         * 索引名
+         */
+        private final String name;
+
+        /**
+         * 是否唯一索引
+         */
+        private final boolean unique;
+
+        /**
+         * 索引字段
+         */
+        private final String columnName;
+
+        /**
+         * 排序方式 (A OR D OR null)
+         */
+        private final String ascOrDesc;
+
+        private final int cardinality;
+
+        private final int ordinalPosition;
+
+        public Index(ResultSet resultSet) throws SQLException {
+            this.unique = !resultSet.getBoolean("NON_UNIQUE");
+            this.name = resultSet.getString("INDEX_NAME");
+            this.columnName = resultSet.getString("COLUMN_NAME");
+            this.ascOrDesc = resultSet.getString("ASC_OR_DESC");
+            this.cardinality = resultSet.getInt("CARDINALITY");
+            this.ordinalPosition = resultSet.getInt("ORDINAL_POSITION");
+        }
+
+    }
 }

+ 79 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/model/MapperMethod.java

@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator.model;
+
+import com.baomidou.mybatisplus.generator.config.po.TableField;
+import lombok.Getter;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Unmodifiable;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author nieqiurong
+ * @since 3.5.10
+ */
+public class MapperMethod {
+
+    /**
+     * 索引名称
+     */
+    @Getter
+    @NotNull
+    private final String indexName;
+
+    /**
+     * 方法体
+     */
+    @Getter
+    @NotNull
+    private final String method;
+
+    /**
+     * 索引字段信息
+     */
+    @NotNull
+    private final List<TableField> tableFieldList = new ArrayList<>();
+
+    /**
+     * 扩展参数
+     */
+    @NotNull
+    private final Map<String, Object> extendData = new HashMap<>();
+
+    public MapperMethod(@NotNull String indexName, @NotNull String method, @NotNull List<TableField> tableFieldList) {
+        this.indexName = indexName;
+        this.method = method;
+        this.tableFieldList.addAll(tableFieldList);
+    }
+
+    public void addExtendData(@NotNull String key, @NotNull Object data) {
+        this.extendData.put(key, data);
+    }
+
+    public @Unmodifiable @NotNull Map<String, Object> getExtendData() {
+        return Collections.unmodifiableMap(this.extendData);
+    }
+
+    public @Unmodifiable @NotNull List<TableField> getTableFieldList() {
+        return Collections.unmodifiableList(this.tableFieldList);
+    }
+
+}

+ 5 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/query/DefaultQuery.java

@@ -132,10 +132,15 @@ public class DefaultQuery extends AbstractDatabaseQuery {
             field.setMetaInfo(metaInfo);
             tableInfo.addField(field);
         });
+        tableInfo.setIndexList(getIndex(tableName));
         tableInfo.processTable();
     }
 
     protected Map<String, DatabaseMetaDataWrapper.Column> getColumnsInfo(String tableName) {
         return databaseMetaDataWrapper.getColumnsInfo(tableName, true);
     }
+
+    protected List<DatabaseMetaDataWrapper.Index> getIndex(String tableName) {
+        return databaseMetaDataWrapper.getIndex(tableName);
+    }
 }

+ 54 - 0
mybatis-plus-generator/src/main/java/com/baomidou/mybatisplus/generator/util/KotlinTypeUtils.java

@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2011-2024, baomidou (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.baomidou.mybatisplus.generator.util;
+
+import com.baomidou.mybatisplus.generator.config.rules.DbColumnType;
+import com.baomidou.mybatisplus.generator.config.rules.IColumnType;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Kotlin类型处理工具类
+ *
+ * @author nieqiurong
+ * @since 3.5.10
+ */
+public class KotlinTypeUtils {
+
+    private static final Map<IColumnType, String> JAVA_TO_KOTLIN_TYPE = new HashMap<>();
+
+    static {
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_INT, "Int");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.INTEGER, "Int");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_DOUBLE, "Double");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_FLOAT, "Float");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_LONG, "Long");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_BOOLEAN, "Boolean");
+        JAVA_TO_KOTLIN_TYPE.put(DbColumnType.BASE_CHAR, "Char");
+    }
+
+    /**
+     * 转换Java类型至Kotlin类型
+     *
+     * @param columnType {@link DbColumnType}
+     * @return Kotlin类型
+     */
+    public static String getStringType(IColumnType columnType) {
+        return JAVA_TO_KOTLIN_TYPE.getOrDefault(columnType, columnType.getType());
+    }
+
+}

+ 15 - 2
mybatis-plus-generator/src/main/resources/templates/mapper.java.btl

@@ -2,6 +2,9 @@ package ${package.Mapper};
 
 import ${package.Entity}.${entity};
 import ${superMapperClassPackage};
+<% for(pkg in importPackages){ %>
+import ${pkg};
+<% } %>
 <% if(mapperAnnotationClass!=null){ %>
 import ${mapperAnnotationClass.name};
 <% } %>
@@ -18,9 +21,19 @@ import ${mapperAnnotationClass.name};
 @${mapperAnnotationClass.simpleName}
 <% } %>
 <% if(kotlin){ %>
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
+interface ${table.mapperName} : ${superMapperClass}<${entity}> {
 <% }else{ %>
 public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
+<% } %>
 
-}
+<% for(m in mapperMethodList){ %>
+    /**
+     * generate by ${m.indexName}
+     *
+     <% for(f in m.tableFieldList) { %>
+     * @param ${f.propertyName} ${f.comment}
+     <% } %>
+     */
+    ${m.method}
 <% } %>
+}

+ 16 - 2
mybatis-plus-generator/src/main/resources/templates/mapper.java.ej

@@ -2,6 +2,10 @@ package #(package.Mapper);
 
 import #(package.Entity).#(entity);
 import #(superMapperClassPackage);
+
+#for(pkg : importPackages)
+import #(pkg);
+#end
 #if(mapperAnnotationClass)
 import #(mapperAnnotationClass.name);
 #end
@@ -18,9 +22,19 @@ import #(mapperAnnotationClass.name);
 @#(mapperAnnotationClass.simpleName)
 #end
 #if(kotlin)
-interface #(table.mapperName) : #(superMapperClass)<#(entity)>
+interface #(table.mapperName) : #(superMapperClass)<#(entity)> {
 #else
 public interface #(table.mapperName) extends #(superMapperClass)<#(entity)> {
+#end
 
-}
+#for(m : mapperMethodList)
+    /**
+     * generate by #(m.indexName)
+     *
+     #for(f : m.tableFieldList)
+     * @param #(f.propertyName) #(f.comment)
+     #end
+     */
+    #(m.method)
 #end
+}

+ 17 - 2
mybatis-plus-generator/src/main/resources/templates/mapper.java.ftl

@@ -2,6 +2,10 @@ package ${package.Mapper};
 
 import ${package.Entity}.${entity};
 import ${superMapperClassPackage};
+
+<#list importPackages as pkg>
+import ${pkg};
+</#list>
 <#if mapperAnnotationClass??>
 import ${mapperAnnotationClass.name};
 </#if>
@@ -18,9 +22,20 @@ import ${mapperAnnotationClass.name};
 @${mapperAnnotationClass.simpleName}
 </#if>
 <#if kotlin>
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
+interface ${table.mapperName} : ${superMapperClass}<${entity}> {
 <#else>
 public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
+</#if>
 
+<#list mapperMethodList as m>
+    /**
+     * generate by ${m.indexName}
+     *
+    <#list m.tableFieldList as f>
+     * @param ${f.propertyName} ${f.comment}
+    </#list>
+     */
+    ${m.method}
+</#list>
 }
-</#if>
+

+ 17 - 2
mybatis-plus-generator/src/main/resources/templates/mapper.java.vm

@@ -2,6 +2,11 @@ package ${package.Mapper};
 
 import ${package.Entity}.${entity};
 import ${superMapperClassPackage};
+
+#foreach($pkg in ${importPackages})
+import ${pkg};
+#end
+
 #if(${mapperAnnotationClass})
 import ${mapperAnnotationClass.name};
 #end
@@ -18,9 +23,19 @@ import ${mapperAnnotationClass.name};
 @${mapperAnnotationClass.simpleName}
 #end
 #if(${kotlin})
-interface ${table.mapperName} : ${superMapperClass}<${entity}>
+interface ${table.mapperName} : ${superMapperClass}<${entity}> {
 #else
 public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
+#end
 
-}
+#foreach($m in ${mapperMethodList})
+    /**
+     * generate by ${m.indexName}
+     *
+     #foreach($f in ${m.tableFieldList})
+     * @param ${f.propertyName} ${f.comment}
+     #end
+     */
+    ${m.method}
 #end
+}

+ 1 - 0
mybatis-plus-generator/src/test/java/com/baomidou/mybatisplus/generator/jdbc/DatabaseMetaDataWrapperTest.java

@@ -19,4 +19,5 @@ public class DatabaseMetaDataWrapperTest {
         Assertions.assertTrue(name.isNullable());
         Assertions.assertEquals(JdbcType.VARCHAR, name.getJdbcType());
     }
+
 }