diff --git a/src/test/java/com/youlai/system/generator/FastAutoGeneratorTest.java b/src/test/java/com/youlai/system/generator/FastAutoGeneratorTest.java
new file mode 100644
index 00000000..2e535be0
--- /dev/null
+++ b/src/test/java/com/youlai/system/generator/FastAutoGeneratorTest.java
@@ -0,0 +1,82 @@
+package com.youlai.system.generator;
+
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+
+import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
+import com.baomidou.mybatisplus.generator.config.OutputFile;
+import com.baomidou.mybatisplus.generator.config.builder.CustomFile;
+
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 代码交互式生成
+ *
+ * 代码生成、MySQL表生成代码、自动代码生成
+ *
+ * @author Ray Hao
+ * @see 代码生成器配置新
+ * @since 2024/4/9
+ */
+public class FastAutoGeneratorTest {
+
+ private static final DataSourceConfig.Builder DATA_SOURCE_CONFIG = new DataSourceConfig
+ .Builder("jdbc:mysql://localhost:3306/youlai_boot?serverTimezone=Asia/Shanghai" , "root" , "123456");
+
+ /**
+ * 执行 run
+ */
+ public static void main(String[] args) {
+ FastAutoGenerator.create(DATA_SOURCE_CONFIG)
+ // 全局配置
+ .globalConfig((scanner, builder) -> {
+ builder.outputDir(System.getProperty("user.dir") + "/src/main/java")
+ .author("Ray Hao") // 设置作者
+ ;
+ })
+ // 包配置
+ .packageConfig(builder -> builder
+ .parent("com.youlai.system")
+ .entity("model.entity")
+ .mapper("mapper")
+ .service("service")
+ .serviceImpl("service.impl")
+ .controller("controller")
+ .pathInfo(Collections.singletonMap(OutputFile.xml, System.getProperty("user.dir") + "/src/main/resources/mapper"))
+ )
+ // 注入配置(设置扩展类的模板路径和包路径)
+ .injectionConfig(consumer -> {
+ List customFiles = new ArrayList<>();
+ customFiles.add(new CustomFile.Builder().fileName("DTO.java").templatePath("/templates/dto.java.vm").packageName("model.dto").build());
+ customFiles.add(new CustomFile.Builder().fileName("VO.java").templatePath("/templates/vo.java.vm").packageName("model.vo").build());
+ customFiles.add(new CustomFile.Builder().fileName("BO.java").templatePath("/templates/bo.java.vm").packageName("model.bo").build());
+ customFiles.add(new CustomFile.Builder().fileName("PageQuery.java").templatePath("/templates/pageQuery.java.vm").packageName("model.query").build());
+ customFiles.add(new CustomFile.Builder().fileName("Form.java").templatePath("/templates/form.java.vm").packageName("model.form").build());
+ customFiles.add(new CustomFile.Builder().fileName("Converter.java").templatePath("/templates/converter.java.vm").packageName("converter").build());
+ consumer.customFile(customFiles);
+ })
+ // 策略配置
+ .strategyConfig((scanner, builder) -> {
+
+ builder.entityBuilder()
+ .enableLombok() // 是否使用lombok
+ //.enableFileOverride() // 是否覆盖文件
+ .logicDeleteColumnName("deleted") // 逻辑删除字段名
+ ;
+
+ builder.mapperBuilder()
+ .enableBaseColumnList()
+ .enableBaseResultMap()
+ ;
+
+ builder.addTablePrefix("sys_") // 过滤移除表前缀 sys_user 表生成的实体类 User.java
+ .addInclude(scanner.apply("请输入表名,多个表名用,隔开"));
+ }
+ )
+ .execute()
+
+ ;
+ }
+}
diff --git a/src/test/resources/templates/bo.java.vm b/src/test/resources/templates/bo.java.vm
new file mode 100644
index 00000000..8e43efb9
--- /dev/null
+++ b/src/test/resources/templates/bo.java.vm
@@ -0,0 +1,143 @@
+package ${package.Entity};
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${entityLombokModel})
+import lombok.Getter;
+import lombok.Setter;
+#if(${chainModel})
+import lombok.experimental.Accessors;
+#end
+#end
+
+/**
+ * $!{table.comment}
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Getter
+@Setter
+ #if(${chainModel})
+@Accessors(chain = true)
+ #end
+#end
+#if(${table.convert})
+@TableName("${schemaName}${table.name}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+public class ${entity} extends Model<${entity}> {
+#elseif(${entitySerialVersionUID})
+public class ${entity} implements Serializable {
+#else
+public class ${entity} {
+#end
+#if(${entitySerialVersionUID})
+
+ private static final long serialVersionUID = 1L;
+#end
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+#if(${field.keyFlag})
+#set($keyPropertyName=${field.propertyName})
+#end
+#if("$!field.comment" != "")
+ /**
+ * ${field.comment}
+ */
+#end
+#if(${field.keyFlag})
+## 主键
+ #if(${field.keyIdentityFlag})
+ @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
+ #elseif(!$null.isNull(${idType}) && "$!idType" != "")
+ @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
+ #elseif(${field.convert})
+ @TableId("${field.annotationColumnName}")
+ #end
+## 普通字段
+#elseif(${field.fill})
+## ----- 存在字段填充设置 -----
+ #if(${field.convert})
+ @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
+ #else
+ @TableField(fill = FieldFill.${field.fill})
+ #end
+#elseif(${field.convert})
+ @TableField("${field.annotationColumnName}")
+#end
+## 乐观锁注解
+#if(${field.versionField})
+ @Version
+#end
+## 逻辑删除注解
+#if(${field.logicDeleteField})
+ @TableLogic
+#end
+ private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+#foreach($field in ${table.fields})
+ #if(${field.propertyType.equals("boolean")})
+ #set($getprefix="is")
+ #else
+ #set($getprefix="get")
+ #end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+ #if(${chainModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #end
+ this.${field.propertyName} = ${field.propertyName};
+ #if(${chainModel})
+ return this;
+ #end
+ }
+#end
+## --foreach end---
+#end
+## --end of #if(!${entityLombokModel})--
+#if(${entityColumnConstant})
+ #foreach($field in ${table.fields})
+
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+ #end
+#end
+#if(${activeRecord})
+
+ @Override
+ public Serializable pkVal() {
+ #if(${keyPropertyName})
+ return this.${keyPropertyName};
+ #else
+ return null;
+ #end
+ }
+#end
+#if(!${entityLombokModel})
+
+ @Override
+ public String toString() {
+ return "${entity}{" +
+ #foreach($field in ${table.fields})
+ #if($!{foreach.index}==0)
+ "${field.propertyName} = " + ${field.propertyName} +
+ #else
+ ", ${field.propertyName} = " + ${field.propertyName} +
+ #end
+ #end
+ "}";
+ }
+#end
+}
diff --git a/src/test/resources/templates/controller.java.vm b/src/test/resources/templates/controller.java.vm
new file mode 100644
index 00000000..4a43bba7
--- /dev/null
+++ b/src/test/resources/templates/controller.java.vm
@@ -0,0 +1,36 @@
+package ${package.Controller};
+
+import org.springframework.web.bind.annotation.RequestMapping;
+#if(${restControllerStyle})
+import org.springframework.web.bind.annotation.RestController;
+#else
+import org.springframework.stereotype.Controller;
+#end
+#if(${superControllerClassPackage})
+import ${superControllerClassPackage};
+#end
+
+/**
+ * $!{table.comment} 前端控制器
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${restControllerStyle})
+@RestController
+#else
+@Controller
+#end
+@RequestMapping("#if(${package.ModuleName})/${package.ModuleName}#end/#if(${controllerMappingHyphenStyle})${controllerMappingHyphen}#else${table.entityPath}#end")
+
+#if(${superControllerClass})
+public class ${table.controllerName} extends ${superControllerClass} {
+#else
+public class ${table.controllerName} {
+#end
+
+
+
+
+
+}
diff --git a/src/test/resources/templates/converter.java.vm b/src/test/resources/templates/converter.java.vm
new file mode 100644
index 00000000..aa13b954
--- /dev/null
+++ b/src/test/resources/templates/converter.java.vm
@@ -0,0 +1,29 @@
+package ${package}.converter;
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+import org.mapstruct.InheritInverseConfiguration;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Mappings;
+
+import ${package}.dto.${entity}DTO;
+import ${package}.entity.${entity};
+import ${package}.vo.${entity}PageVO;
+import ${package}.form.${entity}Form;
+import ${package}.bo.${entity}BO;
+
+
+@Mapper(componentModel = "spring")
+public interface ${entity}Converter}{
+
+ ${entity}PageVO bo2PageVo(${entity}BO bo);
+
+ Page<${entity}PageVO> bo2PageVo(Page<${entity}BO> bo);
+
+ ${entity}Form entity2Form(${entity} entity);
+
+ @InheritInverseConfiguration(name = "entity2Form")
+ ${entity} form2Entity(${entity}Form entity);
+}
\ No newline at end of file
diff --git a/src/test/resources/templates/dto.java.vm b/src/test/resources/templates/dto.java.vm
new file mode 100644
index 00000000..b3874e23
--- /dev/null
+++ b/src/test/resources/templates/dto.java.vm
@@ -0,0 +1,133 @@
+package ${package}.model.dto;
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${springdoc})
+import io.swagger.v3.oas.annotations.media.Schema;
+#elseif(${swagger})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+#if(${entityLombokModel})
+import lombok.Getter;
+import lombok.Setter;
+ #if(${chainModel})
+ import lombok.experimental.Accessors;
+ #end
+#end
+
+/**
+ * $!{table.comment} DTO
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Getter
+@Setter
+ #if(${chainModel})
+ @Accessors(chain = true)
+ #end
+#end
+#if(${table.convert})
+@TableName("${schemaName}${table.name}")
+#end
+#if(${springdoc})
+@Schema(name = "${entity}", description = "$!{table.comment}")
+#elseif(${swagger})
+@ApiModel(value = "${entity}对象", description = "$!{table.comment}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+public class ${entity} extends Model<${entity}> {
+#elseif(${entitySerialVersionUID})
+public class ${entity} implements Serializable {
+#else
+public class ${entity} {
+#end
+#if(${entitySerialVersionUID})
+
+ private static final long serialVersionUID = 1L;
+#end
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+ #if(${field.keyFlag})
+ #set($keyPropertyName=${field.propertyName})
+ #end
+ #if("$!field.comment" != "")
+ #if(${springdoc})
+ @Schema(description = "${field.comment}")
+ #elseif(${swagger})
+ @ApiModelProperty("${field.comment}")
+ #else
+ /**
+ * ${field.comment}
+ */
+ #end
+ #end
+
+private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+ #foreach($field in ${table.fields})
+ #if(${field.propertyType.equals("boolean")})
+ #set($getprefix="is")
+ #else
+ #set($getprefix="get")
+ #end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+ #if(${chainModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #end
+ this.${field.propertyName} = ${field.propertyName};
+ #if(${chainModel})
+ return this;
+ #end
+ }
+ #end
+ ## --foreach end---
+#end
+## --end of #if(!${entityLombokModel})--
+#if(${entityColumnConstant})
+ #foreach($field in ${table.fields})
+
+public static final String ${field.name.toUpperCase()} = "${field.name}";
+ #end
+#end
+#if(${activeRecord})
+
+ @Override
+ public Serializable pkVal() {
+ #if(${keyPropertyName})
+ return this.${keyPropertyName};
+ #else
+ return null;
+ #end
+}
+#end
+#if(!${entityLombokModel})
+
+ @Override
+ public String toString() {
+ return "${entity}{" +
+ #foreach($field in ${table.fields})
+ #if($!{foreach.index}==0)
+ "${field.propertyName} = " + ${field.propertyName} +
+ #else
+ ", ${field.propertyName} = " + ${field.propertyName} +
+ #end
+ #end
+ "}";
+}
+#end
+}
diff --git a/src/test/resources/templates/entity.java.vm b/src/test/resources/templates/entity.java.vm
new file mode 100644
index 00000000..8e43efb9
--- /dev/null
+++ b/src/test/resources/templates/entity.java.vm
@@ -0,0 +1,143 @@
+package ${package.Entity};
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${entityLombokModel})
+import lombok.Getter;
+import lombok.Setter;
+#if(${chainModel})
+import lombok.experimental.Accessors;
+#end
+#end
+
+/**
+ * $!{table.comment}
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Getter
+@Setter
+ #if(${chainModel})
+@Accessors(chain = true)
+ #end
+#end
+#if(${table.convert})
+@TableName("${schemaName}${table.name}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+public class ${entity} extends Model<${entity}> {
+#elseif(${entitySerialVersionUID})
+public class ${entity} implements Serializable {
+#else
+public class ${entity} {
+#end
+#if(${entitySerialVersionUID})
+
+ private static final long serialVersionUID = 1L;
+#end
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+#if(${field.keyFlag})
+#set($keyPropertyName=${field.propertyName})
+#end
+#if("$!field.comment" != "")
+ /**
+ * ${field.comment}
+ */
+#end
+#if(${field.keyFlag})
+## 主键
+ #if(${field.keyIdentityFlag})
+ @TableId(value = "${field.annotationColumnName}", type = IdType.AUTO)
+ #elseif(!$null.isNull(${idType}) && "$!idType" != "")
+ @TableId(value = "${field.annotationColumnName}", type = IdType.${idType})
+ #elseif(${field.convert})
+ @TableId("${field.annotationColumnName}")
+ #end
+## 普通字段
+#elseif(${field.fill})
+## ----- 存在字段填充设置 -----
+ #if(${field.convert})
+ @TableField(value = "${field.annotationColumnName}", fill = FieldFill.${field.fill})
+ #else
+ @TableField(fill = FieldFill.${field.fill})
+ #end
+#elseif(${field.convert})
+ @TableField("${field.annotationColumnName}")
+#end
+## 乐观锁注解
+#if(${field.versionField})
+ @Version
+#end
+## 逻辑删除注解
+#if(${field.logicDeleteField})
+ @TableLogic
+#end
+ private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+#foreach($field in ${table.fields})
+ #if(${field.propertyType.equals("boolean")})
+ #set($getprefix="is")
+ #else
+ #set($getprefix="get")
+ #end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+ #if(${chainModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #end
+ this.${field.propertyName} = ${field.propertyName};
+ #if(${chainModel})
+ return this;
+ #end
+ }
+#end
+## --foreach end---
+#end
+## --end of #if(!${entityLombokModel})--
+#if(${entityColumnConstant})
+ #foreach($field in ${table.fields})
+
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+ #end
+#end
+#if(${activeRecord})
+
+ @Override
+ public Serializable pkVal() {
+ #if(${keyPropertyName})
+ return this.${keyPropertyName};
+ #else
+ return null;
+ #end
+ }
+#end
+#if(!${entityLombokModel})
+
+ @Override
+ public String toString() {
+ return "${entity}{" +
+ #foreach($field in ${table.fields})
+ #if($!{foreach.index}==0)
+ "${field.propertyName} = " + ${field.propertyName} +
+ #else
+ ", ${field.propertyName} = " + ${field.propertyName} +
+ #end
+ #end
+ "}";
+ }
+#end
+}
diff --git a/src/test/resources/templates/form.java.vm b/src/test/resources/templates/form.java.vm
new file mode 100644
index 00000000..5e437f44
--- /dev/null
+++ b/src/test/resources/templates/form.java.vm
@@ -0,0 +1,133 @@
+package ${package}.model.dto;
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${springdoc})
+import io.swagger.v3.oas.annotations.media.Schema;
+#elseif(${swagger})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+#if(${entityLombokModel})
+import lombok.Getter;
+import lombok.Setter;
+ #if(${chainModel})
+ import lombok.experimental.Accessors;
+ #end
+#end
+
+/**
+ * $!{table.comment} 表单对象
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Getter
+@Setter
+ #if(${chainModel})
+ @Accessors(chain = true)
+ #end
+#end
+#if(${table.convert})
+@TableName("${schemaName}${table.name}")
+#end
+#if(${springdoc})
+@Schema(name = "${entity}", description = "$!{table.comment}")
+#elseif(${swagger})
+@ApiModel(value = "${entity}对象", description = "$!{table.comment}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+ public class ${entity} extends Model<${entity}> {
+#elseif(${entitySerialVersionUID})
+ public class ${entity} implements Serializable {
+#else
+ public class ${entity} {
+#end
+#if(${entitySerialVersionUID})
+
+ private static final long serialVersionUID = 1L;
+#end
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+ #if(${field.keyFlag})
+ #set($keyPropertyName=${field.propertyName})
+ #end
+ #if("$!field.comment" != "")
+ #if(${springdoc})
+ @Schema(description = "${field.comment}")
+ #elseif(${swagger})
+ @ApiModelProperty("${field.comment}")
+ #else
+ /**
+ * ${field.comment}
+ */
+ #end
+ #end
+
+private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+ #foreach($field in ${table.fields})
+ #if(${field.propertyType.equals("boolean")})
+ #set($getprefix="is")
+ #else
+ #set($getprefix="get")
+ #end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+ #if(${chainModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #end
+ this.${field.propertyName} = ${field.propertyName};
+ #if(${chainModel})
+ return this;
+ #end
+ }
+ #end
+ ## --foreach end---
+#end
+## --end of #if(!${entityLombokModel})--
+#if(${entityColumnConstant})
+ #foreach($field in ${table.fields})
+
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+ #end
+#end
+#if(${activeRecord})
+
+ @Override
+ public Serializable pkVal() {
+ #if(${keyPropertyName})
+ return this.${keyPropertyName};
+ #else
+ return null;
+ #end
+}
+#end
+#if(!${entityLombokModel})
+
+ @Override
+ public String toString() {
+ return "${entity}{" +
+ #foreach($field in ${table.fields})
+ #if($!{foreach.index}==0)
+ "${field.propertyName} = " + ${field.propertyName} +
+ #else
+ ", ${field.propertyName} = " + ${field.propertyName} +
+ #end
+ #end
+ "}";
+}
+#end
+}
diff --git a/src/test/resources/templates/mapper.java.vm b/src/test/resources/templates/mapper.java.vm
new file mode 100644
index 00000000..fc7aac8d
--- /dev/null
+++ b/src/test/resources/templates/mapper.java.vm
@@ -0,0 +1,31 @@
+package ${package.Mapper};
+
+import ${package.Entity}.${entity};
+import ${superMapperClassPackage};
+#if(${mapperAnnotationClass})
+import ${mapperAnnotationClass.name};
+#end
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+
+/**
+ * $!{table.comment} Mapper 接口
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${mapperAnnotationClass})
+@${mapperAnnotationClass.simpleName}
+#end
+
+public interface ${table.mapperName} extends ${superMapperClass}<${entity}> {
+
+ /**
+ * 获取用户分页列表
+ *
+ * @param page
+ * @param queryParams 查询参数
+ * @return
+ */
+ Page<${entity}BO> listPaged${entity}s(Page<${entity}BO> page, ${entity}PageQuery queryParams);
+
+}
diff --git a/src/test/resources/templates/mapper.xml.vm b/src/test/resources/templates/mapper.xml.vm
new file mode 100644
index 00000000..41a01c19
--- /dev/null
+++ b/src/test/resources/templates/mapper.xml.vm
@@ -0,0 +1,65 @@
+
+
+
+
+#if(${enableCache})
+
+
+
+#end
+#if(${baseResultMap})
+
+
+#foreach($field in ${table.fields})
+#if(${field.keyFlag})##生成主键排在第一位
+
+#end
+#end
+#foreach($field in ${table.commonFields})##生成公共字段
+
+#end
+#foreach($field in ${table.fields})
+#if(!${field.keyFlag})##生成普通字段
+
+#end
+#end
+
+
+#end
+#if(${baseColumnList})
+
+
+#foreach($field in ${table.commonFields})
+ ${field.columnName},
+#end
+ ${table.fieldNames}
+
+
+#end
+
+
+
+
+
diff --git a/src/test/resources/templates/pageQuery.java.vm b/src/test/resources/templates/pageQuery.java.vm
new file mode 100644
index 00000000..a247eead
--- /dev/null
+++ b/src/test/resources/templates/pageQuery.java.vm
@@ -0,0 +1,21 @@
+package ${package}.model.query;
+
+import ${package}.common.base.BasePageQuery;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+/**
+ * $!{table.comment}分页查询对象
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Schema(description ="$!{table.comment}分页查询对象")
+@Data
+public class ${entity}PageQuery extends BasePageQuery {
+
+ @Schema(description="关键字")
+ private String keywords;
+
+}
diff --git a/src/test/resources/templates/service.java.vm b/src/test/resources/templates/service.java.vm
new file mode 100644
index 00000000..54e95b6e
--- /dev/null
+++ b/src/test/resources/templates/service.java.vm
@@ -0,0 +1,58 @@
+package ${package.Service};
+
+import ${package.Entity}.${entity};
+import ${superServiceClassPackage};
+
+/**
+ * $!{table.comment} 服务类
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+public interface ${table.serviceName} extends ${superServiceClass}<${entity}> {
+
+
+ /**
+ *$!{table.comment}分页列表
+ *
+ * @return
+ */
+ IPage<${entity}PageVO> listPaged${entity}s(${entity}PageQuery queryParams);
+
+
+ /**
+ * 获取$!{table.comment}表单数据
+ *
+ * @param userId
+ * @return
+ */
+ ${entity}Form get${entity}FormData(Long id);
+
+
+ /**
+ * 新增$!{table.comment}
+ *
+ * @param formData $!{table.comment}表单对象
+ * @return
+ */
+ boolean save${entity}(${entity}Form formData);
+
+ /**
+ * 修改$!{table.comment}
+ *
+ * @param id $!{table.comment}ID
+ * @param formData $!{table.comment}表单对象
+ * @return
+ */
+ boolean update${entity}(Long id, UserForm formData);
+
+
+ /**
+ * 删除$!{table.comment}
+ *
+ * @param idsStr $!{table.comment}ID,多个以英文逗号(,)分割
+ * @return
+ */
+ boolean delete${entity}s(String idsStr);
+
+}
diff --git a/src/test/resources/templates/serviceImpl.java.vm b/src/test/resources/templates/serviceImpl.java.vm
new file mode 100644
index 00000000..4b38cf01
--- /dev/null
+++ b/src/test/resources/templates/serviceImpl.java.vm
@@ -0,0 +1,102 @@
+package ${package.ServiceImpl};
+
+import ${package.Entity}.${entity};
+import ${package.Mapper}.${table.mapperName};
+import ${package.Service}.${table.serviceName};
+import ${superServiceImplClassPackage};
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import com.youlai.system.common.util.DateUtils;
+
+/**
+ * $!{table.comment} 服务实现类
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+@Service
+@RequiredArgsConstructor
+public class ${table.serviceImplName} extends ${superServiceImplClass}<${table.mapperName}, ${entity}> implements ${table.serviceName} {
+
+ private final ${entity}Converter converter;
+
+ /**
+ * 获取$!{table.comment}分页列表
+ *
+ * @param queryParams 查询参数
+ * @return {@link IPage<${entity}PageVO>} $!{table.comment}分页列表
+ */
+ @Override
+ public IPage<${entity}PageVO> listPaged${entity}s(${entity}PageQuery queryParams) {
+
+ // 参数构建
+ int pageNum = queryParams.getPageNum();
+ int pageSize = queryParams.getPageSize();
+ Page<${entity}BO> page = new Page<>(pageNum, pageSize);
+
+ // 格式化为数据库日期格式,避免日期比较使用格式化函数导致索引失效
+ DateUtils.toDatabaseFormat(queryParams, "startTime", "endTime");
+
+ // 查询数据
+ Page<${entity}BO> boPage = this.baseMapper.listPaged${entity}s(page, queryParams);
+
+ // 实体转换
+ return converter.bo2PageVo(boPage);
+ }
+
+ /**
+ * 获取$!{table.comment}表单数据
+ *
+ * @param userId $!{table.comment}ID
+ * @return
+ */
+ @Override
+ public ${entity}Form get${entity}FormData(Long userId) {
+ return this.baseMapper.get${entity}FormData(userId);
+ }
+
+ /**
+ * 新增$!{table.comment}
+ *
+ * @param formData $!{table.comment}表单对象
+ * @return
+ */
+ @Override
+ public boolean save${entity}(${entity}Form formData) {
+ // 实体转换 form->entity
+ SysUser entity = converter.form2Entity(formData);
+ return this.save(entity);
+ }
+
+ /**
+ * 更新$!{table.comment}
+ *
+ * @param userId $!{table.comment}ID
+ * @param formData $!{table.comment}表单对象
+ * @return
+ */
+ @Override
+ @Transactional
+ public boolean update${entity}(Long id,${entity}Form formData) {
+ ${entity} entity = converter.form2Entity(formData);
+ return this.updateById(entity);
+ }
+
+ /**
+ * 删除$!{table.comment}
+ *
+ * @param idsStr $!{table.comment}ID,多个以英文逗号(,)分割
+ * @return true|false
+ */
+ @Override
+ public boolean delete${entity}s(String idsStr) {
+ Assert.isTrue(StrUtil.isNotBlank(idsStr), "删除的$!{table.comment}数据为空");
+ // 逻辑删除
+ List ids = Arrays.stream(idsStr.split(","))
+ .map(Long::parseLong)
+ .collect(Collectors.toList());
+ return this.removeByIds(ids);
+ }
+
+
+}
diff --git a/src/test/resources/templates/vo.java.vm b/src/test/resources/templates/vo.java.vm
new file mode 100644
index 00000000..78a6afd9
--- /dev/null
+++ b/src/test/resources/templates/vo.java.vm
@@ -0,0 +1,133 @@
+package ${package}.model.vo;
+
+#foreach($pkg in ${table.importPackages})
+import ${pkg};
+#end
+#if(${springdoc})
+import io.swagger.v3.oas.annotations.media.Schema;
+#elseif(${swagger})
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+#end
+#if(${entityLombokModel})
+import lombok.Getter;
+import lombok.Setter;
+ #if(${chainModel})
+ import lombok.experimental.Accessors;
+ #end
+#end
+
+/**
+ * $!{table.comment} VO
+ *
+ * @author ${author}
+ * @since ${date}
+ */
+#if(${entityLombokModel})
+@Getter
+@Setter
+ #if(${chainModel})
+ @Accessors(chain = true)
+ #end
+#end
+#if(${table.convert})
+@TableName("${schemaName}${table.name}")
+#end
+#if(${springdoc})
+@Schema(name = "${entity}", description = "$!{table.comment}")
+#elseif(${swagger})
+@ApiModel(value = "${entity}对象", description = "$!{table.comment}")
+#end
+#if(${superEntityClass})
+public class ${entity} extends ${superEntityClass}#if(${activeRecord})<${entity}>#end {
+#elseif(${activeRecord})
+public class ${entity} extends Model<${entity}> {
+#elseif(${entitySerialVersionUID})
+public class ${entity} implements Serializable {
+#else
+public class ${entity} {
+#end
+#if(${entitySerialVersionUID})
+
+ private static final long serialVersionUID = 1L;
+#end
+## ---------- BEGIN 字段循环遍历 ----------
+#foreach($field in ${table.fields})
+
+ #if(${field.keyFlag})
+ #set($keyPropertyName=${field.propertyName})
+ #end
+ #if("$!field.comment" != "")
+ #if(${springdoc})
+ @Schema(description = "${field.comment}")
+ #elseif(${swagger})
+ @ApiModelProperty("${field.comment}")
+ #else
+ /**
+ * ${field.comment}
+ */
+ #end
+ #end
+
+ private ${field.propertyType} ${field.propertyName};
+#end
+## ---------- END 字段循环遍历 ----------
+#if(!${entityLombokModel})
+ #foreach($field in ${table.fields})
+ #if(${field.propertyType.equals("boolean")})
+ #set($getprefix="is")
+ #else
+ #set($getprefix="get")
+ #end
+
+ public ${field.propertyType} ${getprefix}${field.capitalName}() {
+ return ${field.propertyName};
+ }
+
+ #if(${chainModel})
+ public ${entity} set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #else
+ public void set${field.capitalName}(${field.propertyType} ${field.propertyName}) {
+ #end
+ this.${field.propertyName} = ${field.propertyName};
+ #if(${chainModel})
+ return this;
+ #end
+ }
+ #end
+ ## --foreach end---
+#end
+## --end of #if(!${entityLombokModel})--
+#if(${entityColumnConstant})
+ #foreach($field in ${table.fields})
+
+ public static final String ${field.name.toUpperCase()} = "${field.name}";
+ #end
+#end
+#if(${activeRecord})
+
+ @Override
+ public Serializable pkVal() {
+ #if(${keyPropertyName})
+ return this.${keyPropertyName};
+ #else
+ return null;
+ #end
+}
+#end
+#if(!${entityLombokModel})
+
+ @Override
+ public String toString() {
+ return "${entity}{" +
+ #foreach($field in ${table.fields})
+ #if($!{foreach.index}==0)
+ "${field.propertyName} = " + ${field.propertyName} +
+ #else
+ ", ${field.propertyName} = " + ${field.propertyName} +
+ #end
+ #end
+ "}";
+}
+#end
+}