柏竹 柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档

柏竹

奋斗柏竹
首页
后端
前端
  • 应用推荐
关于
友链
  • 分类
  • 标签
  • 归档
  • Java基础

  • JavaWeb

  • 拓展技术

  • 框架技术

  • 数据库

  • 数据结构

  • Spring

  • SpringMVC

  • SpringBoot

  • SpringClound

  • Ruoyi-Vue-Plus

    • ruoyi-vue-plus-基础功能
    • ruoyi-vue-plus-权限控制
    • ruoyi-vue-plus-表格操作
    • ruoyi-vue-plus-缓存功能
    • ruoyi-vue-plus-日志功能
    • ruoyi-vue-plus-线程相关
    • ruoyi-vue-plus-OSS功能
    • ruoyi-vue-plus-代码生成功能
      • 快速应用
        • 基本信息
        • 字段信息
        • 生成信息
      • 配置文件
      • 核心业务
        • 导入列表
        • 导入生成表
        • 详细生成表
        • 修改生成表
        • 生成预览
        • 生成代码
        • 下载zip
        • 自定义路径生成
        • 同步生成表
      • 上下文参数&模板
        • 上下文参数
        • Java模板
        • XML模块
        • SQL模板
    • ruoyi-vue-plus-多数据源
    • ruoyi-vue-plus-任务调度
    • ruoyi-vue-plus-监控功能
    • ruoyi-vue-plus-国际化
    • ruoyi-vue-plus-XSS功能
    • ruoyi-vue-plus-防重幂&限流 功能
    • ruoyi-vue-plus-推送功能
    • ruoyi-vue-plus-序列化功能
    • ruoyi-vue-plus-数据加密
    • ruoyi-vue-plus-单元测试
    • ruoyi-vue-plus-前端插件
    • ruoyi-vue-plus-前端工具篇
    • ruoyi-vue-plus-部署篇
    • ruoyi-vue-plus-前端篇
    • ruoyi-vue-plus-后端工具篇
    • ruoyi-vue-plus-框架篇
    • ruoyi-vue-plus-问题解决
  • 后端
  • Ruoyi-Vue-Plus
柏竹
2023-12-09
目录

ruoyi-vue-plus-代码生成功能

框架代码生成功能可快速构建项目的基础文件 , 如 : Controller , Service , Mapper 等基础架构文件 . 该框架是在页面进行配置生成信息 , 以实现快速开发 , 能够提高前期开发效率

ruoyi-vue-plus应用文档 : https://plus-doc.dromara.org (opens new window)

# 快速应用

应用大致步骤

  1. 导入表
  2. 设置配置表生成信息
  3. 下载生成代码
  4. 导入sql
  5. copy 前后端
  6. 启用...

注意

  • 每个表必须包含有 : create_by , create_time , update_by , update_time 字段
  • 树表 必须包含有 指向指定字段(一般用id) , 用于指向父级数据

# 基本信息

无关键信息填写

# 字段信息

填写信息说明

  • 物理类型 => SQL应用的类型

  • Java类型 => 对象属性类型

  • Java属性 => 对象属性名称

    选定字段是否采用 插入/编辑/列表/查询 => 新增是否显示/编辑是否显示/列表是否显示/查询字段显示

  • 查询方式 : 选中查询后 , 指定SQL查询方式

  • 显示类型 : 在 编辑/新增 时 , 更加的方便使用

  • 必填 : 勾选后 , 插入的时候必须填写

# 生成信息

单表

关注 包路径/模块名

树表

关注 包路径/模块名/树id字段/树父id字段/树名

大量数据不适合使用 , 数据分级主要通过前端分级展示

# 配置文件

generator.yml 配置文件*

# 代码生成
gen: 
  # 作者
  author: bozhu
  # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
  packageName: com.ruoyi.system
  # 自动去除表前缀,默认是false
  autoRemovePre: false
  # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
  tablePrefix: sys_

根据实际情况修改配置

# 核心业务

# 导入列表

根据 information_schem 数据库表信息查询

获取库表基础信息 GenController#dataLis()

@SaCheckPermission("tool:gen:list")
@GetMapping("/db/list")
public TableDataInfo<GenTable> dataList(GenTable genTable, PageQuery pageQuery) {
    return genTableService.selectPageDbTableList(genTable, pageQuery);
}

业务层 (略过 , 无必要逻辑代码)

SQL执行语句 GenTableMapper.selectPageDbTableList() (该方法适配不同数据源应用 , 只需关注MySQL应用方式即可)

点击展开
<select id="selectPageDbTableList" resultMap="GenTableResult">
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
        select table_name, table_comment, create_time, update_time
        from information_schema.tables
        where table_schema = (select database())
        AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT IN (select table_name from gen_table)
        <if test="genTable.tableName != null and genTable.tableName != ''">
            AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
        </if>
        <if test="genTable.tableComment != null and genTable.tableComment != ''">
            AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
        </if>
        order by create_time desc
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
        select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
        from user_tables dt, user_tab_comments dtc, user_objects uo
        where dt.table_name = dtc.table_name
        and dt.table_name = uo.object_name
        and uo.object_type = 'TABLE'
        AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
        AND lower(dt.table_name) NOT IN (select table_name from gen_table)
        <if test="genTable.tableName != null and genTable.tableName != ''">
            AND lower(dt.table_name) like lower(concat(concat('%', #{genTable.tableName}), '%'))
        </if>
        <if test="genTable.tableComment != null and genTable.tableComment != ''">
            AND lower(dtc.comments) like lower(concat(concat('%', #{genTable.tableComment}), '%'))
        </if>
        order by create_time desc
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
        select table_name, table_comment, create_time, update_time
        from (
            SELECT c.relname AS table_name,
                    obj_description(c.oid) AS table_comment,
                    CURRENT_TIMESTAMP AS create_time,
                    CURRENT_TIMESTAMP AS update_time
            FROM pg_class c
                LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
            WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
                AND c.relname != 'spatial_%'::text
                AND n.nspname = 'public'::name
                AND n.nspname <![CDATA[ <> ]]> ''::name
        ) list_table
        where table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
        AND table_name NOT IN (select table_name from gen_table)
        <if test="genTable.tableName != null and genTable.tableName != ''">
            AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
        </if>
        <if test="genTable.tableComment != null and genTable.tableComment != ''">
            AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
        </if>
        order by create_time desc
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
        SELECT cast(D.NAME as nvarchar) as table_name,
               cast(F.VALUE as nvarchar) as table_comment,
               crdate as create_time,
               refdate as update_time
        FROM SYSOBJECTS D
            INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
                AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
                AND D.NAME NOT LIKE 'xxl_job_%' AND D.NAME NOT LIKE 'gen_%'
                AND D.NAME NOT IN (select table_name from gen_table)
        <if test="genTable.tableName != null and genTable.tableName != ''">
            AND lower(D.NAME) like lower(concat(N'%', N'${genTable.tableName}', N'%'))
        </if>
        <if test="genTable.tableComment != null and genTable.tableComment != ''">
            AND lower(CAST(F.VALUE AS nvarchar)) like lower(concat(N'%', N'${genTable.tableComment}', N'%'))
        </if>
        order by crdate desc
    </if>
</select>

实际执行的SQL

以下SQL是查询当前数据源的所有库表信息 , 因此需要加多层约束过滤

SELECT
	table_name,
	table_comment,
	create_time,
	update_time 
FROM
	information_schema.TABLES 
WHERE
	# 仅保留当前库的表
	table_schema = (SELECT DATABASE()) 
	# 排除不必要的表名(模糊匹配)
	AND table_name NOT LIKE 'xxl_job_%' 
	AND table_name NOT LIKE 'gen_%' 
	# 排除已经导入的表
	AND table_name NOT IN ( SELECT table_name FROM gen_table ) 
ORDER BY
	create_time DESC 
	LIMIT 10

DataBaseHelper数据源判断

点击展开
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DataBaseHelper {

    private static final DynamicRoutingDataSource DS = SpringUtils.getBean(DynamicRoutingDataSource.class);

    /**
     * 获取当前数据库类型
     */
    public static DataBaseType getDataBaseType() {
        DataSource dataSource = DS.determineDataSource();
        try (Connection conn = dataSource.getConnection()) {
            DatabaseMetaData metaData = conn.getMetaData();
            String databaseProductName = metaData.getDatabaseProductName();
            return DataBaseType.find(databaseProductName);
        } catch (SQLException e) {
            throw new ServiceException(e.getMessage());
        }
    }

    public static boolean isMySql() {
        return DataBaseType.MY_SQL == getDataBaseType();
    }

    public static boolean isOracle() {
        return DataBaseType.ORACLE == getDataBaseType();
    }

    public static boolean isPostgerSql() {
        return DataBaseType.POSTGRE_SQL == getDataBaseType();
    }

    public static boolean isSqlServer() {
        return DataBaseType.SQL_SERVER == getDataBaseType();
    }

    public static String findInSet(Object var1, String var2) {
        DataBaseType dataBasyType = getDataBaseType();
        String var = Convert.toStr(var1);
        if (dataBasyType == DataBaseType.SQL_SERVER) {
            // charindex(',100,' , ',0,100,101,') <> 0
            return "charindex('," + var + ",' , ','+" + var2 + "+',') <> 0";
        } else if (dataBasyType == DataBaseType.POSTGRE_SQL) {
            // (select position(',100,' in ',0,100,101,')) <> 0
            return "(select position('," + var + ",' in ','||" + var2 + "||',')) <> 0";
        } else if (dataBasyType == DataBaseType.ORACLE) {
            // instr(',0,100,101,' , ',100,') <> 0
            return "instr(','||" + var2 + "||',' , '," + var + ",') <> 0";
        }
        // find_in_set('100' , '0,100,101')
        return "find_in_set('" + var + "' , " + var2 + ") <> 0";
    }
}

# 导入生成表

当用户选中需要导入表时 , 接口会 根据 表名称 进行插入 gen_table表 和 gen_table_column表

导入表结构 GenController#importTableSave()

@SaCheckPermission("tool:gen:import")
@Log(title = "代码生成", businessType = BusinessType.IMPORT)
@PostMapping("/importTable")
public R<Void> importTableSave(String tables) {
    String[] tableNames = Convert.toStrArray(tables);
    // 查询表信息
    List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
    // 导入库表 gen_table , gen_table_column
    genTableService.importGenTable(tableList);
    return R.ok();
}

导入核心业务 GenTableServiceImpl#importGenTable()










 









 








@Transactional(rollbackFor = Exception.class)
@Override
public void importGenTable(List<GenTable> tableList) {
    String operName = LoginHelper.getUsername();
    try {
        for (GenTable table : tableList) {
            String tableName = table.getTableName();
            // 初始化 表基础信息 并保存
            GenUtils.initTable(table, operName);
            int row = baseMapper.insert(table);
            // 初始化 该表的列信息 并保存
            if (row > 0) {
                List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
                List<GenTableColumn> saveColumns = new ArrayList<>();
                for (GenTableColumn column : genTableColumns) {
                    GenUtils.initColumnField(column, table);
                    saveColumns.add(column);
                }
                if (CollUtil.isNotEmpty(saveColumns)) {
                    genTableColumnMapper.insertBatch(saveColumns);
                }
            }
        }
    } catch (Exception e) {
        throw new ServiceException("导入失败:" + e.getMessage());
    }
}

GenUtils代码生成工具类

点击展开

初始化表信息 GenUtils#initTable()

public static void initTable(GenTable genTable, String operName) {
    genTable.setClassName(convertClassName(genTable.getTableName()));
    genTable.setPackageName(GenConfig.getPackageName());
    genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
    genTable.setBusinessName(getBusinessName(genTable.getTableName()));
    genTable.setFunctionName(replaceText(genTable.getTableComment()));
    genTable.setFunctionAuthor(GenConfig.getAuthor());
    genTable.setCreateBy(operName);
}

初始化字段属性 GenUtils#initColumnField()

public static void initColumnField(GenTableColumn column, GenTable table) {
    // 括号处理
    String dataType = getDbType(column.getColumnType());
    String columnName = column.getColumnName();
    column.setTableId(table.getTableId());
    column.setCreateBy(table.getCreateBy());
    // 设置java字段名 (驼峰处理)
    column.setJavaField(StringUtils.toCamelCase(columnName));
    // 设置默认类型
    column.setJavaType(GenConstants.TYPE_STRING);
    // 设置默认查询条件
    column.setQueryType(GenConstants.QUERY_EQ);

    // 数据类型处理
    if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
        // 文本类型处理
        // 字符串长度超过500设置为文本域
        Integer columnLength = getColumnLength(column.getColumnType());
        String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
        column.setHtmlType(htmlType);
    } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
        // 时间类型处理
        column.setJavaType(GenConstants.TYPE_DATE);
        column.setHtmlType(GenConstants.HTML_DATETIME);
    } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
        // 数值类型处理
        column.setHtmlType(GenConstants.HTML_INPUT);

        // 如果是浮点型 统一用BigDecimal
        String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
        if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
            // 浮点型
            column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
        } else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
            // 整型
            column.setJavaType(GenConstants.TYPE_INTEGER);
        } else {
            // 长整型
            column.setJavaType(GenConstants.TYPE_LONG);
        }
    }

    // BO对象 默认插入勾选
    if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) {
        column.setIsInsert(GenConstants.REQUIRE);
    }
    // BO对象 默认编辑勾选
    if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
        column.setIsEdit(GenConstants.REQUIRE);
    }
    // BO对象 默认是否必填勾选
    if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
        column.setIsRequired(GenConstants.REQUIRE);
    }
    // VO对象 默认返回勾选
    if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
        column.setIsList(GenConstants.REQUIRE);
    }
    // BO对象 默认查询勾选
    if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
        column.setIsQuery(GenConstants.REQUIRE);
    }

    // 固有字段控制
    // 查询字段类型
    if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
        column.setQueryType(GenConstants.QUERY_LIKE);
    }
    // 状态字段设置单选框
    if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
        column.setHtmlType(GenConstants.HTML_RADIO);
    }
    // 类型&性别字段设置下拉框
    else if (StringUtils.endsWithIgnoreCase(columnName, "type")
        || StringUtils.endsWithIgnoreCase(columnName, "sex")) {
        column.setHtmlType(GenConstants.HTML_SELECT);
    }
    // 图片字段设置图片上传控件
    else if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
        column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
    }
    // 文件字段设置文件上传控件
    else if (StringUtils.endsWithIgnoreCase(columnName, "file")) {
        column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
    }
    // 内容字段设置富文本控件
    else if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
        column.setHtmlType(GenConstants.HTML_EDITOR);
    }
}

Xml 核心SQL代码

库表信息搜索后并初始化

点击展开

获取表信息 , SQL执行语句 GenTableMapper.selectDbTableListByNames() (该方法适配不同数据源应用 , 只需关注MySQL应用方式即可)

<select id="selectDbTableListByNames" resultMap="GenTableResult">
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
        select table_name, table_comment, create_time, update_time from information_schema.tables
        where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
        and table_name in
        <foreach collection="array" item="name" open="(" separator="," close=")">
             #{name}
        </foreach>
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
        select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
        from user_tables dt, user_tab_comments dtc, user_objects uo
        where dt.table_name = dtc.table_name
        and dt.table_name = uo.object_name
        and uo.object_type = 'TABLE'
        AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
        AND dt.table_name NOT IN (select table_name from gen_table)
        and lower(dt.table_name) in
        <foreach collection="array" item="name" open="(" separator="," close=")">
            #{name}
        </foreach>
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
        select table_name, table_comment, create_time, update_time
        from (
            SELECT c.relname AS table_name,
                    obj_description(c.oid) AS table_comment,
                    CURRENT_TIMESTAMP AS create_time,
                    CURRENT_TIMESTAMP AS update_time
            FROM pg_class c
                LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
            WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
                AND c.relname != 'spatial_%'::text
                AND n.nspname = 'public'::name
                AND n.nspname <![CDATA[ <> ]]> ''::name
        ) list_table
        where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
        and table_name in
        <foreach collection="array" item="name" open="(" separator="," close=")">
            #{name}
        </foreach>
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
        SELECT cast(D.NAME as nvarchar) as table_name,
               cast(F.VALUE as nvarchar) as table_comment,
               crdate as create_time,
               refdate as update_time
        FROM SYSOBJECTS D
            INNER JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID
                AND F.MINOR_ID = 0 AND D.XTYPE = 'U' AND D.NAME != 'DTPROPERTIES'
                AND D.NAME NOT LIKE 'xxl_job_%' AND D.NAME NOT LIKE 'gen_%'
                AND D.NAME in
        <foreach collection="array" item="name" open="(" separator="," close=")">
            #{name}
        </foreach>
    </if>
</select>

实际执行SQL (用法和上面一样)

SELECT
	table_name,
	table_comment,
	create_time,
	update_time 
FROM
	information_schema.TABLES 
WHERE
	table_name NOT LIKE 'xxl_job_%' 
	AND table_name NOT LIKE 'gen_%' 
	AND table_schema = (SELECT DATABASE()) 
	# 多个表名逗号分隔
	AND table_name IN ( 'tableName' )

获取表字段信息 , SQL执行语句 GenTableColumnMapper.selectDbTableColumnsByName()

<select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isMySql()">
        select column_name,
               (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required,
               (case when column_key = 'PRI' then '1' else '0' end) as is_pk,
               ordinal_position as sort,
               column_comment,
               (case when extra = 'auto_increment' then '1' else '0' end) as is_increment,
               column_type
        from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
        order by ordinal_position
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isOracle()">
        select lower(temp.column_name) as column_name,
                (case when (temp.nullable = 'N'  and  temp.constraint_type != 'P') then '1' else '0' end) as is_required,
                (case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
                temp.column_id as sort,
                temp.comments as column_comment,
                (case when temp.constraint_type = 'P' then '1' else '0' end) as is_increment,
                lower(temp.data_type) as column_type
        from (
            select col.column_id, col.column_name,col.nullable, col.data_type, colc.comments, uc.constraint_type, row_number()
                over (partition by col.column_name order by uc.constraint_type desc) as row_flg
            from user_tab_columns col
            left join user_col_comments colc on colc.table_name = col.table_name and colc.column_name = col.column_name
            left join user_cons_columns ucc on ucc.table_name = col.table_name and ucc.column_name = col.column_name
            left join user_constraints uc on uc.constraint_name = ucc.constraint_name
            where col.table_name = upper(#{tableName})
        ) temp
        WHERE temp.row_flg = 1
        ORDER BY temp.column_id
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isPostgerSql()">
        SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type
        FROM (
            SELECT c.relname AS table_name,
                   a.attname AS column_name,
                   d.description AS column_comment,
                   CASE WHEN a.attnotnull AND con.conname IS NULL THEN 1 ELSE 0
                   END AS is_required,
                   CASE WHEN con.conname IS NOT NULL THEN 1 ELSE 0
                   END AS is_pk,
                   a.attnum AS sort,
                   CASE WHEN "position"(pg_get_expr(ad.adbin, ad.adrelid),
                       ((c.relname::text || '_'::text) || a.attname::text) || '_seq'::text) > 0 THEN 1 ELSE 0
                   END AS is_increment,
                   btrim(
                       CASE WHEN t.typelem <![CDATA[ <> ]]> 0::oid AND t.typlen = '-1'::integer THEN 'ARRAY'::text ELSE
                            CASE WHEN t.typtype = 'd'::"char" THEN format_type(t.typbasetype, NULL::integer)
                            ELSE format_type(a.atttypid, NULL::integer) END
                       END, '"'::text
                   ) AS column_type
            FROM pg_attribute a
                JOIN (pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid) ON a.attrelid = c.oid
                LEFT JOIN pg_description d ON d.objoid = c.oid AND a.attnum = d.objsubid
                LEFT JOIN pg_constraint con ON con.conrelid = c.oid AND (a.attnum = ANY (con.conkey))
                LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
                LEFT JOIN pg_type t ON a.atttypid = t.oid
            WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
                AND a.attnum > 0
                AND n.nspname = 'public'::name
            ORDER BY c.relname, a.attnum
        ) temp
        WHERE table_name = (#{tableName})
            AND column_type <![CDATA[ <> ]]> '-'
    </if>
    <if test="@com.ruoyi.common.helper.DataBaseHelper@isSqlServer()">
        SELECT
            cast(A.NAME as nvarchar) as column_name,
            cast(B.NAME as nvarchar) + (case when B.NAME = 'numeric' then '(' + cast(A.prec as nvarchar) + ',' + cast(A.scale as nvarchar) + ')' else '' end) as column_type,
            cast(G.[VALUE] as nvarchar) as column_comment,
            (SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE Z WHERE TABLE_NAME = D.NAME and A.NAME = Z.column_name  ) as is_pk,
            colorder as sort
        FROM SYSCOLUMNS A
            LEFT JOIN SYSTYPES B ON A.XTYPE = B.XUSERTYPE
            INNER JOIN SYSOBJECTS D ON A.ID = D.ID AND D.XTYPE='U' AND D.NAME != 'DTPROPERTIES'
            LEFT JOIN SYS.EXTENDED_PROPERTIES G ON A.ID = G.MAJOR_ID AND A.COLID = G.MINOR_ID
            LEFT JOIN SYS.EXTENDED_PROPERTIES F ON D.ID = F.MAJOR_ID AND F.MINOR_ID = 0
        WHERE D.NAME = #{tableName}
        ORDER BY A.COLORDER
    </if>
</select>

实际执行SQL

SELECT
	column_name,
	# 判断列是否必要的 (为空并且不是主键)
	( CASE WHEN ( is_nullable = 'no' && column_key != 'PRI' ) THEN '1' ELSE '0' END ) AS is_required,
	# 判断是否为主键
	( CASE WHEN column_key = 'PRI' THEN '1' ELSE '0' END ) AS is_pk,
	ordinal_position AS sort,
	column_comment,
	# 判断是否自增
	( CASE WHEN extra = 'auto_increment' THEN '1' ELSE '0' END ) AS is_increment,
	column_type 
FROM
	information_schema.COLUMNS 
WHERE
	table_schema = (SELECT DATABASE()) 
	AND table_name = ( 'paper_test' ) 
ORDER BY
	ordinal_position

# 详细生成表

修改时需要单表的相关详细数据

获取库表基础信息 GenController#getInfo()

@SaCheckPermission("tool:gen:query")
@GetMapping(value = "/{tableId}")
public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
    GenTable table = genTableService.selectGenTableById(tableId);
    List<GenTable> tables = genTableService.selectGenTableAll();
    // 左查询 gen_column
    List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
    Map<String, Object> map = new HashMap<String, Object>();
    // 当前表详细
    map.put("info", table);
    // 当前表字段信息
    map.put("rows", list);
    // 所有表信息 , 关联表设置别用 (目前尚未开放可以无视)
    map.put("tables", tables);
    return R.ok(map);
}

# 修改生成表

修改表信息接口 GenController#editSave()

@SaCheckPermission("tool:gen:edit")
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
@PutMapping
public R<Void> editSave(@Validated @RequestBody GenTable genTable) {
    // 校验数据
    genTableService.validateEdit(genTable);
    genTableService.updateGenTable(genTable);
    return R.ok();
}

修改实现 GenTableServiceImpl#updateGenTable()







 



 




@Transactional(rollbackFor = Exception.class)
@Override
public void updateGenTable(GenTable genTable) {
    String options = JsonUtils.toJsonString(genTable.getParams());
    genTable.setOptions(options);
    // 保存修改表信息
    int row = baseMapper.updateById(genTable);
    // 保存修改列信息
    if (row > 0) {
        for (GenTableColumn cenTableColumn : genTable.getColumns()) {
            genTableColumnMapper.updateById(cenTableColumn);
        }
    }
}

# 生成预览

预览接口 GenController#preview()

@SaCheckPermission("tool:gen:preview")
@GetMapping("/preview/{tableId}")
public R<Map<String, String>> preview(@PathVariable("tableId") Long tableId) throws IOException {
    Map<String, String> dataMap = genTableService.previewCode(tableId);
    return R.ok(dataMap);
}

导出具体实现 GenTableServiceImpl#previewCode()

具体填充的数据 , 点击跳转

@Override
public Map<String, String> previewCode(Long tableId) {
    Map<String, String> dataMap = new LinkedHashMap<>();
    // 查询表信息
    GenTable table = baseMapper.selectGenTableById(tableId);
    List<Long> menuIds = new ArrayList<>();
    // 计算雪花id为生成SQL语句准备的
    for (int i = 0; i < 6; i++) {
        menuIds.add(identifierGenerator.nextId(null).longValue());
    }
    table.setMenuIds(menuIds);
    // 设置主子表信息 (在库获取设置)
    setSubTable(table);
    // 设置主键列信息
    setPkColumn(table);
    // 初始化 .vm解析
    VelocityInitializer.initVelocity();
    // 构建模板上下文(填充数据)
    VelocityContext context = VelocityUtils.prepareContext(table);

    // 获取模板列表
    List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
    for (String template : templates) {
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(context, sw);
        dataMap.put(template, sw.toString());
    }
    return dataMap;
}

# 生成代码

生成方式有两种

  • 下载zip (推荐)
  • 自定义路径生成

# 下载zip

zip下载接口 GenController#download()

@SaCheckPermission("tool:gen:code")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/download/{tableName}")
public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException {
    // 压缩包流
    byte[] data = genTableService.downloadCode(tableName);
    genCode(response, data);
}

// ... 

private void genCode(HttpServletResponse response, byte[] data) throws IOException {
    response.reset();
    response.addHeader("Access-Control-Allow-Origin", "*");
    response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
    response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
    response.addHeader("Content-Length", "" + data.length);
    response.setContentType("application/octet-stream; charset=UTF-8");
    IoUtil.write(response.getOutputStream(), false, data);
}

业务下载接口 GenTableServiceImpl#downloadCode()

@Override
public byte[] downloadCode(String[] tableNames) {
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    ZipOutputStream zip = new ZipOutputStream(outputStream);
    for (String tableName : tableNames) {
        generatorCode(tableName, zip);
    }
    IoUtil.close(zip);
    return outputStream.toByteArray();
}

// ...

// 和生成预览使用方式一样 , 该方法是将代码写入压缩流
private void generatorCode(String tableName, ZipOutputStream zip) {
    // 查询表信息
    GenTable table = baseMapper.selectGenTableByName(tableName);
    List<Long> menuIds = new ArrayList<>();
    for (int i = 0; i < 6; i++) {
        menuIds.add(identifierGenerator.nextId(null).longValue());
    }
    table.setMenuIds(menuIds);
    // 设置主子表信息
    setSubTable(table);
    // 设置主键列信息
    setPkColumn(table);
	// 初始化 .vm解析
    VelocityInitializer.initVelocity();
	// 构建模板上下文(填充数据)
    VelocityContext context = VelocityUtils.prepareContext(table);

    // 获取模板列表
    List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
    for (String template : templates) {
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(context, sw);
        try {
            // 添加到zip
            zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
            IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
            IoUtil.close(sw);
            zip.flush();
            zip.closeEntry();
        } catch (IOException e) {
            log.error("渲染模板失败,表名:" + table.getTableName(), e);
        }
    }
}

# 自定义路径生成

自定义路径 GenController#genCode()

@SaCheckPermission("tool:gen:code")
@Log(title = "代码生成", businessType = BusinessType.GENCODE)
@GetMapping("/genCode/{tableName}")
public R<Void> genCode(@PathVariable("tableName") String tableName) {
    genTableService.generatorCode(tableName);
    return R.ok();
}

业务下载接口 GenTableServiceImpl#downloadCode()

@Override
public void generatorCode(String tableName) {
    // 查询表信息
    GenTable table = baseMapper.selectGenTableByName(tableName);
    // 设置主子表信息
    setSubTable(table);
    // 设置主键列信息
    setPkColumn(table);
    // 初始化 .vm解析
    VelocityInitializer.initVelocity();
    // 构建模板上下文(填充数据)
    VelocityContext context = VelocityUtils.prepareContext(table);

    // 获取模板列表
    List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
    for (String template : templates) {
        // 排除前端相关代码
        if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm")) {
            // 渲染模板
            StringWriter sw = new StringWriter();
            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
            tpl.merge(context, sw);
            try {
                // 获取自定义目录
                String path = getGenPath(table, template);
                // 写入自定义目录的文件中
                FileUtils.writeUtf8String(sw.toString(), path);
            } catch (Exception e) {
                throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
            }
        }
    }
}

// ...

public static String getGenPath(GenTable table, String template) {
    String genPath = table.getGenPath();
    if (StringUtils.equals(genPath, "/")) {
        return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
    }
    return genPath + File.separator + VelocityUtils.getFileName(template, table);
}

# 同步生成表

同步接口 GenController#synchDb()

@SaCheckPermission("tool:gen:edit")
@Log(title = "代码生成", businessType = BusinessType.UPDATE)
@GetMapping("/synchDb/{tableName}")
public R<Void> synchDb(@PathVariable("tableName") String tableName) {
    genTableService.synchDb(tableName);
    return R.ok();
}

业务实现 GenTableServiceImpl#synchDb()

public void synchDb(String tableName) {
    GenTable table = baseMapper.selectGenTableByName(tableName);
    List<GenTableColumn> tableColumns = table.getColumns();
    // Map转化 , key 为 column_name
    Map<String, GenTableColumn> tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);

    // 查库判断存在
    List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
    if (CollUtil.isEmpty(dbTableColumns)) {
        throw new ServiceException("同步数据失败,原表结构不存在");
    }
    // 拿到表中的所有字段名
    List<String> dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName);

    List<GenTableColumn> saveColumns = new ArrayList<>();
    dbTableColumns.forEach(column -> {
        // 初始化字段
        GenUtils.initColumnField(column, table);
        // Map匹配存在字段 (保留原表信息操作)
        if (tableColumnMap.containsKey(column.getColumnName())) {
            GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
            column.setColumnId(prevColumn.getColumnId());
            if (column.isList()) {
                // 如果是列表,继续保留查询方式/字典类型选项
                column.setDictType(prevColumn.getDictType());
                column.setQueryType(prevColumn.getQueryType());
            }
            // 如果列是必填且非忽略及父属性,并且在新增/修改中,且是非主键列,则保留之前的必填/显示类型选项
            if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
                && (column.isInsert() || column.isEdit())
                && ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
                // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
                column.setIsRequired(prevColumn.getIsRequired());
                column.setHtmlType(prevColumn.getHtmlType());
            }
        }
        saveColumns.add(column);
    });
    if (CollUtil.isNotEmpty(saveColumns)) {
        // 批量更新
        genTableColumnMapper.insertOrUpdateBatch(saveColumns);
    }
    // 删除多余的字段 (将新表不包含的字段进行删除)
    List<GenTableColumn> delColumns = StreamUtils.filter(tableColumns, column ->
        !dbTableColumnNames.contains(column.getColumnName()));
    if (CollUtil.isNotEmpty(delColumns)) {
        List<Long> ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
        genTableColumnMapper.deleteBatchIds(ids);
    }
}

# 上下文参数&模板

模板仅在代码当中注释补充展示

# 上下文参数

通用上下文参数

上下文参数 说明
author 作者名
BusinessName 生成业务名 , 驼峰处理
businessName 生成业务名 , 无驼峰
basePackage 包前缀
ClassName 类名 , 驼峰处理
className 类名 , 无驼峰
columns 表所有列字段
dicts 字典组 (包含有下拉框 , 单选框 , 复选框和字典名)
datetime 生成时间
functionName 模块描述 , 功能名
importList 外部引列列表
moduleName 模块名
packageName 包路径
permissionPrefix 权限前缀标识 (模块名:业务名)
pkColumn 主键字段对象
tplCategory 模板类型 (单表 , 树表 , sub主子表)
table 表对象
tableName 表名

# Java模板

实体对象 vm/java/domain.java.vm

点击展开










































 
 
 
 
 
 
 
 
 
 
 





package ${packageName}.domain;

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
import java.math.BigDecimal;

#foreach ($import in $importList)
import ${import};
#end
#if($table.crud || $table.sub)
import com.ruoyi.common.core.domain.BaseEntity;
#elseif($table.tree)
import com.ruoyi.common.core.domain.TreeEntity;
#end

/**
 * ${functionName}对象 ${tableName}
 *
 * @author ${author}
 * @date ${datetime}
 */
#if($table.crud || $table.sub)
    #set($Entity="BaseEntity")
#elseif($table.tree)
    #set($Entity="TreeEntity<${ClassName}>")
#end
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("${tableName}")
public class ${ClassName} extends ${Entity} {

    private static final long serialVersionUID=1L;

#foreach ($column in $columns)
## 方法排除基类Entity字段
#if(!$table.isSuperColumn($column.javaField))
    /**
     * $column.columnComment
     */
## 根据属性标识添加注解
#if($column.javaField=='delFlag')
    @TableLogic
#end
#if($column.javaField=='version')
    @Version
#end
#if($column.pk)
    @TableId(value = "$column.columnName")
#end
    private $column.javaType $column.javaField;
#end
#end

}

请求响应类 vm/java/vo.java.vm

点击展开































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 







package ${packageName}.domain.vo;

#foreach ($import in $importList)
import ${import};
#end
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.ruoyi.common.annotation.ExcelDictFormat;
import com.ruoyi.common.convert.ExcelDictConvert;
import lombok.Data;
import java.util.Date;

import java.io.Serializable;

/**
 * ${functionName}视图对象 ${tableName}
 *
 * @author ${author}
 * @date ${datetime}
 */
@Data
@ExcelIgnoreUnannotated
public class ${ClassName}Vo implements Serializable {

    private static final long serialVersionUID = 1L;

#foreach ($column in $columns)
#if($column.list)
    /**
     * $column.columnComment
     */
    ## 字段内容获取括号中了 , 如果没有则直接显示
    #set($parentheseIndex=$column.columnComment.indexOf("("))
    #if($parentheseIndex != -1)
        #set($comment=$column.columnComment.substring(0, $parentheseIndex))
    #else
        #set($comment=$column.columnComment)
    #end
    ## 导出表格处理
    #if(${column.dictType} && ${column.dictType} != '')
        ## 为字典类型 转化处理
    @ExcelProperty(value = "${comment}" , converter = ExcelDictConvert.class)
    @ExcelDictFormat(dictType = "${column.dictType}" )
    #elseif($parentheseIndex != -1)
        ## 为字典类型处理 (特殊转化处理)
    @ExcelProperty(value = "${comment}" , converter = ExcelDictConvert.class)
    @ExcelDictFormat(readConverterExp = "$column.readConverterExp()" )
    #else
        ## 默认 导出不处理 仅做标识
    @ExcelProperty(value = "${comment}" )
    #end
    private $column.javaType $column.javaField;

#end
#end

}

请求接收类 vm/java/bo.java.vm

点击展开




































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 





package ${packageName}.domain.bo;

import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.validation.constraints.*;

import java.util.Date;

#foreach ($import in $importList)
import ${import};
#end
#if($table.crud || $table.sub)
import com.ruoyi.common.core.domain.BaseEntity;
#elseif($table.tree)
import com.ruoyi.common.core.domain.TreeEntity;
#end

/**
 * ${functionName}业务对象 ${tableName}
 *
 * @author ${author}
 * @date ${datetime}
 */
#if($table.crud || $table.sub)
    #set($Entity="BaseEntity")
#elseif($table.tree)
    #set($Entity="TreeEntity<${ClassName}Bo>")
#end

@Data
@EqualsAndHashCode(callSuper = true)
public class ${ClassName}Bo extends ${Entity} {

    #foreach ($column in $columns)
        ## 额外判断请求参数非空处理
        #if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
            /**
             * $column.columnComment
             */
            ## 判断含有的操作组控制非空校验
            #if($column.insert && $column.edit)
                #set($Group="AddGroup.class, EditGroup.class")
            #elseif($column.insert)
                #set($Group="AddGroup.class")
            #elseif($column.edit)
                #set($Group="EditGroup.class")
            #end
            #if($column.required)
                ## 区分对象字符串处理
                #if($column.javaType == 'String')
        @NotBlank(message = "$column.columnComment不能为空" , groups = { $Group })
                #else
        @NotNull(message = "$column.columnComment不能为空" , groups = { $Group })
                #end
            #end
        private $column.javaType $column.javaField;

        #end
    #end

}

业务接口 vm/java/service.java.vm (无核心业务代码)

点击展开
package ${packageName}.service;

import ${packageName}.domain.${ClassName};
import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.bo.${ClassName}Bo;
    #if($table.crud || $table.sub)
    import com.ruoyi.common.core.page.TableDataInfo;
    import com.ruoyi.common.core.domain.PageQuery;
    #end

import java.util.Collection;
import java.util.List;

/**
 * ${functionName}Service接口
 *
 * @author ${author}
 * @date ${datetime}
 */
public interface I${ClassName}Service {

    /**
     * 查询${functionName}
     */
        ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});

    #if($table.crud || $table.sub)
        /**
         * 查询${functionName}列表
         */
        TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
    #end

    /**
     * 查询${functionName}列表
     */
    List<${ClassName}Vo> queryList(${ClassName}Bo bo);

    /**
     * 新增${functionName}
     */
    Boolean insertByBo(${ClassName}Bo bo);

    /**
     * 修改${functionName}
     */
    Boolean updateByBo(${ClassName}Bo bo);

    /**
     * 校验并批量删除${functionName}信息
     */
    Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
}

业务实现类 vm/java/serviceImpl.java.vm

点击展开

主要业务还嘚是 buildQueryWrapper()方法 , 约束查询的构建
































































 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 













































package ${packageName}.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.utils.StringUtils;
    #if($table.crud || $table.sub)
    import com.ruoyi.common.core.page.TableDataInfo;
    import com.ruoyi.common.core.domain.PageQuery;
    import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
    #end
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import ${packageName}.domain.bo.${ClassName}Bo;
import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.${ClassName};
import ${packageName}.mapper.${ClassName}Mapper;
import ${packageName}.service.I${ClassName}Service;

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

/**
 * ${functionName}Service业务层处理
 *
 * @author ${author}
 * @date ${datetime}
 */
@RequiredArgsConstructor
@Service
public class ${ClassName}ServiceImpl implements I${ClassName}Service {

    private final ${ClassName}Mapper baseMapper;

    /**
     * 查询${functionName}
     */
    @Override
    public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}) {
        return baseMapper.selectVoById(${pkColumn.javaField});
    }

    #if($table.crud || $table.sub)
        /**
         * 查询${functionName}列表
         */
        @Override
        public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) {
            LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
            Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
            return TableDataInfo.build(result);
        }
    #end

    /**
     * 查询${functionName}列表
     */
    @Override
    public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
        LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo); return baseMapper.selectVoList(lqw);
    }

    ## 构建查询条件
    private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
        #foreach($column in $columns)
            #if($column.query)
                #set($queryType=$column.queryType)
                #set($javaField=$column.javaField)
                #set($javaType=$column.javaType)
                #set($columnName=$column.columnName)
                #set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
                #set($mpMethod=$column.queryType.toLowerCase())
                #if($queryType != 'BETWEEN')
                    ## 查询判空
                    #if($javaType == 'String')
                        #set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
                    #else
                        #set($condition='bo.get'+$AttrName+'() != null')
                    #end
                    lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName());
                #else
                    ## 日期范围单独处理
                    lqw.between(params.get("begin$AttrName" ) != null && params.get("end$AttrName" ) != null,
                        ${ClassName}::get$AttrName , params.get("begin$AttrName" ), params.get("end$AttrName" ));
                #end
            #end
        #end
        return lqw;
    }

    /**
     * 新增${functionName}
     */
    @Override
    public Boolean insertByBo(${ClassName}Bo bo) {
        ${ClassName} add = BeanUtil.toBean(bo, ${ClassName}. class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        #set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)})
        if (flag) {
            bo.set$pk(add.get$pk());
        }
        return flag;
    }

    /**
     * 修改${functionName}
     */
    @Override
    public Boolean updateByBo(${ClassName}Bo bo) {
        ${ClassName} update = BeanUtil.toBean(bo, ${ClassName}. class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(${ClassName} entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除${functionName}
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }
}

vm/java/controller.java.vm (无核心业务代码)

点击展开
package ${packageName}.controller;

import java.util.List;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

import lombok.RequiredArgsConstructor;

import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.*;

import cn.dev33.satoken.annotation.SaCheckPermission;
import org.springframework.web.bind.annotation.*;
import org.springframework.validation.annotation.Validated;
import com.ruoyi.common.annotation.RepeatSubmit;
import com.ruoyi.common.annotation.Log;
import com.ruoyi.common.core.controller.BaseController;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.validate.AddGroup;
import com.ruoyi.common.core.validate.EditGroup;
import com.ruoyi.common.core.validate.QueryGroup;
import com.ruoyi.common.enums.BusinessType;
import com.ruoyi.common.utils.poi.ExcelUtil;
import ${packageName}.domain.vo.${ClassName}Vo;
import ${packageName}.domain.bo.${ClassName}Bo;
import ${packageName}.service.I${ClassName}Service;
#if($table.crud || $table.sub)
import com.ruoyi.common.core.page.TableDataInfo;
#elseif($table.tree)
#end

/**
 * ${functionName}
 *
 * @author ${author}
 * @date ${datetime}
 */
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/${moduleName}/${businessName}" )
public class ${ClassName}Controller extends BaseController {

    private final I${ClassName}Service i${ClassName}Service;

/**
 * 查询${functionName}列表
 */
@SaCheckPermission("${permissionPrefix}:list" )
@GetMapping("/list" )
    #if($table.crud || $table.sub)
    public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) {
        return i${ClassName}Service.queryPageList(bo, pageQuery);
    }
    #elseif($table.tree)
        public R<List<${ClassName}Vo>> list(${ClassName}Bo bo) {
            List<${ClassName}Vo> list = i${ClassName}Service.queryList(bo);
            return R.ok(list);
        }
    #end

    /**
     * 导出${functionName}列表
     */
    @SaCheckPermission("${permissionPrefix}:export" )
    @Log(title = "${functionName}" , businessType = BusinessType.EXPORT)
    @PostMapping("/export" )
    public void export(${ClassName}Bo bo, HttpServletResponse response) {
        List<${ClassName}Vo> list = i${ClassName}Service.queryList(bo);
        ExcelUtil.exportExcel(list, "${functionName}" , ${ClassName}Vo.class, response);
    }

    /**
     * 获取${functionName}详细信息
     *
     * @param ${pkColumn.javaField} 主键
     */
    @SaCheckPermission("${permissionPrefix}:query" )
    @GetMapping("/{${pkColumn.javaField}}" )
    public R<${ClassName}Vo> getInfo(@NotNull(message = "主键不能为空" ) @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) {
        return R.ok(i${ClassName}Service.queryById(${pkColumn.javaField}));
    }

    /**
     * 新增${functionName}
     */
    @SaCheckPermission("${permissionPrefix}:add" )
    @Log(title = "${functionName}" , businessType = BusinessType.INSERT)
    @RepeatSubmit()
    @PostMapping()
    public R<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
        return toAjax(i${ClassName}Service.insertByBo(bo));
    }

    /**
     * 修改${functionName}
     */
    @SaCheckPermission("${permissionPrefix}:edit" )
    @Log(title = "${functionName}" , businessType = BusinessType.UPDATE)
    @RepeatSubmit()
    @PutMapping()
    public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
        return toAjax(i${ClassName}Service.updateByBo(bo));
    }

    /**
     * 删除${functionName}
     *
     * @param ${pkColumn.javaField}s 主键串
     */
    @SaCheckPermission("${permissionPrefix}:remove" )
    @Log(title = "${functionName}" , businessType = BusinessType.DELETE)
    @DeleteMapping("/{${pkColumn.javaField}s}" )
    public R<Void> remove(@NotEmpty(message = "主键不能为空" ) @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
        return toAjax(i${ClassName}Service.deleteWithValidByIds(Arrays.asList(${pkColumn.javaField}s), true));
    }
}

# XML模块

vm/java/mapper.java.vm (无核心业务代码)

点击展开
package ${packageName}.mapper;

import ${packageName}.domain.${ClassName};
import ${packageName}.domain.vo.${ClassName}Vo;
import com.ruoyi.common.core.mapper.BaseMapperPlus;

/**
 * ${functionName}Mapper接口
 *
 * @author ${author}
 * @date ${datetime}
 */
public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}Mapper, ${ClassName}, ${ClassName}Vo> {

}

vm/xml/mapper.xml.vm (无核心业务代码)

点击展开
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="${packageName}.mapper.${ClassName}Mapper">

    <resultMap type="${packageName}.domain.${ClassName}" id="${ClassName}Result">
    #foreach ($column in $columns)
    	<result property="${column.javaField}" column="${column.columnName}"/>
    #end
    </resultMap>


</mapper>

# SQL模板

vm/sql/sql.vm

点击展开
-- 菜单 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');

-- 按钮 SQL
insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[1]}, '${functionName}查询', ${table.menuIds[0]}, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 'admin', sysdate(), '', null, '');

insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[2]}, '${functionName}新增', ${table.menuIds[0]}, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 'admin', sysdate(), '', null, '');

insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[3]}, '${functionName}修改', ${table.menuIds[0]}, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 'admin', sysdate(), '', null, '');

insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[4]}, '${functionName}删除', ${table.menuIds[0]}, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 'admin', sysdate(), '', null, '');

insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
values(${table.menuIds[5]}, '${functionName}导出', ${table.menuIds[0]}, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 'admin', sysdate(), '', null, '');

其他数据源无关键逻辑代码省略..

#ruoyi-vue-plus#代码生成

← ruoyi-vue-plus-OSS功能 ruoyi-vue-plus-多数据源→

最近更新
01
HTTPS自动续签
10-21
02
博客搭建-简化版(脚本)
10-20
03
ruoyi-vue-plus-部署篇
07-13
更多文章>
Theme by Vdoing | Copyright © 2019-2024 | 桂ICP备2022009417号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式