若依系统二次开发

1. 后台定制

  1. 后台模块命名定制
    • 若依框架修改器
    • 把若依项目压缩为一个zip的压缩文件
      • 注意⚠️:不要使用mac finder进行压缩,使用zip命令压缩,压缩文件里面不会有多余的文件,不会影响修改器运行。
      • 压缩命令:zip -r ruoyi.zip ruoyi
      • 修改器执行示意图:

      alt text
  2. 项目配置
    • 日志文件存储位置配置
      • 在项目目录创建 logs 文件夹
      • rstone-admin 模块 ruoyi-admin/src/main/resources/logback.xml 文件修改
      <!-- 日志存放路径 -->
      <property name="log.path" value="./logs" />
      
    • 数据库配置
      • 数据库配置文件:ruoyi-admin/src/main/resources/application-druid.yml
      # 数据源配置
      spring:
          datasource:
              type: com.alibaba.druid.pool.DruidDataSource
              driverClassName: com.mysql.cj.jdbc.Driver
              druid:
                  # 主库数据源
                  master:
                      url: jdbc:mysql://localhost:3306/ruoyi_vue_3.8.9?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                      username: root
                      password: root123
      
    • 配置redis
      • 配置redis文件:ruoyi-admin/src/main/resources/application.yml
          redis:
          # 地址
          host: localhost
          # 端口,默认为6379
          port: 6379
          # 数据库索引
          database: 0
          # 密码
          password: root,123
      
    • 上传文件目录配置
      • 在项目目录创建 upload 文件夹
      • ruoyi-admin/src/main/resources/application.yml 文件修改
      # 项目相关配置
      ruoyi:
      # 名称
      name: RuoYi
      # 版本
      version: 3.8.9
      # 版权年份
      copyrightYear: 2024
      # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
      profile: ./uploadPath
      
  3. 启动项目
    • 运行rstone-admin下的ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
    • 访问地址:http://localhost:8080/ruoyi-admin/index.html
      • 显示:欢迎使用RuoYi后台管理框架,当前版本:v3.8.9,请通过前端地址访问。
      • 测试成功
  4. 打包
    • 选择idea中的maven菜单,对整个父项目进行打包,打包成功后ruoyi-admin/target/rstone-admin-3.8.9.jar,就是打包成功的文件。
    • 运行测试:
    java -jar ./rstone-admin/target/rstone-admin.jar
    
  5. 配置文件使用环境变量
    • 需求:
      • 适应不同的环境,比如开发环境、测试环境、生产环境,只需要在不同的环境下设置不同的环境变量即可。
      • 生产环境把变量保存在配置文件中不是很安全。
    • application.yml文件使用环境变量举例:
            redis:
            # 地址
            host: ${REDISHOST}
            # 端口,默认为6379
            port: ${REDISPORT}
            # 数据库索引
            database: 0
            # 密码
            password: ${REDISPASSWORD}
    
    • 在IDEA开发环境中设置环境变量:
      • 运行菜单,选择Edit Configurations,在Environment Variables中添加环境变量。

2. 前端定制

  1. 浏览器标签页icon、标题
    • icon位置:/public/favicon.ico
    • 标题位置:/index.html <title>定义标题</title>
  2. 系统页面的logo文件和标题
    • logo文件位置:/src/assets/logo/logo.png
    • 标题: 环境文件 .env.* 中定义的 VUE_APP_TITLE
  3. 修改发布后的后台api基地址
    • 位置: /.env.production 中的 VITE_APP_BASE_API = '/dev-api' 修改为 '/api'
  4. 去掉页面源码和文档图表链接
    • 位置: /src/layout/components/Navbar.vue alt text
  5. 更改主题风格和主题颜色
    • 主题风格文件位置: /src/settings.js
    • 主题风格: 修改 sideTheme: 'theme-dark' 为 sideTheme: 'theme-light'
    • 主题颜色文件位置: src/store/modules/settings.js
    • 主题颜色: 修改 theme: storageSetting.theme || '#409EFF', 为 theme: storageSetting.theme || '#cc6699'
  6. 登录页面中标题、背景图
    • 标题: /src/views/login/index.vue
    • 背景图: /src/assets/images/login-background.jpg
  7. 增加自定义图标

3. 新建业务模块

  1. 在IDEA中新建子模块「rstone-gzh」
    • 在rstone-gzh模块的 pom.xml 文件中添加核心模块依赖
    <dependencies>
        <!-- 核心模块-->
        <dependency>
            <groupId>cn.com.rstone</groupId>
            <artifactId>rstone-framework</artifactId>
        </dependency>
    </dependencies>
    
    • 去掉stone-gzh模块的pom.xml的如下内容:
    <properties>
       <!-- 其中有关java版本号的部分,应该两行都是 -->
    </properties>
    
    • 版本锁定,父工程的pom.xml 文件中添加如下内容:
    <!-- 公众号-->
    <dependency>
        <groupId>cn.com.rstone</groupId>
        <artifactId>rstone-gzh</artifactId>
        <version>${rstone.version}</version>
    </dependency>
    
    • 在rstone-admin 的pom.xml 文件中添加如下内容:
     <!-- 公众号-->
    <dependency>
        <groupId>cn.com.rstone</groupId>
        <artifactId>rstone-gzh</artifactId>
        <version>${rstone.version}</version>
    </dependency>
    

4. 代码生成

  1. 创建数据库表结构
  2. 利用后台生成代码
  3. 优化生成代码:
    1. 配置generator.yml
    # 代码生成
    gen:
    # 作者
    author: adong
    # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
    packageName: cn.com.rstone.gzh
    # 自动去除表前缀,默认是false
    autoRemovePre: true
    # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
    #gzh: 公众号, wcx: 微信小程序,ec: 电子名片,ws: 网站
    tablePrefix: sys_,tb_,gzh_,wcx_,ec_,ws_
    
    1. 实体类支持Lombok
      • rstone-common模块的pom.xml中添加lombok坐标
      <!--  lombok工具-->
      <dependency>
          <groupId>org.projectlombok</groupId>
          <artifactId>lombok</artifactId>
      </dependency>
      
      • 修改模板,在rstone-generator模块的domain.java.vm模板中添加lombok注解
      package ${packageName}.domain;
      
      ## 根据列类型获取导入包
      #foreach ($import in $importList)
      import ${import};
      #end
      ## 导入项目自定义的Excel注解,用于生成Excel文档
      import com.dkd.common.annotation.Excel;
      #if($table.crud || $table.sub)
      ## 如果表具有CRUD操作或子表,继承BaseEntity
      import com.dkd.common.core.domain.BaseEntity;
      #elseif($table.tree)
      ## 如果表是树形结构,继承TreeEntity
      import com.dkd.common.core.domain.TreeEntity;
      #end
      ## 注意lombok导包
      import lombok.AllArgsConstructor;
      import lombok.Builder;
      import lombok.Data;
      import lombok.NoArgsConstructor;
      
      /**
      * ${functionName}对象 ${tableName}
      *
      * @author ${author}
      * @date ${datetime}
      */
      #if($table.crud || $table.sub)
      #set($Entity="BaseEntity")
      #elseif($table.tree)
      #set($Entity="TreeEntity")
      #end
      @Data
      @NoArgsConstructor
      @AllArgsConstructor
      @Builder
      public class ${ClassName} extends ${Entity}
              {   ## 定义类的序列化版本ID
      private static final long serialVersionUID=1L;
      ## 根据表的列定义实体类的属性
      #foreach ($column in $columns)
          ## 如果不是父类的属性,则生成属性
          #if(!$table.isSuperColumn($column.javaField))
          /** $column.columnComment */
              ## 如果字段需要在列表中展示,使用Excel注解标记
              #if($column.list)
                  #set($parentheseIndex=$column.columnComment.indexOf("("))
                  #if($parentheseIndex != -1)
                      #set($comment=$column.columnComment.substring(0, $parentheseIndex))
                  #else
                      #set($comment=$column.columnComment)
                  #end
                  #if($parentheseIndex != -1)
                  @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
                  #elseif($column.javaType == 'Date')
                  @JsonFormat(pattern = "yyyy-MM-dd")
                  @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
                  #else
                  @Excel(name = "${comment}")
                  #end
              #end
          private $column.javaType $column.javaField;
      
          #end
      #end
      ## 如果表有子表,定义子表信息的集合
      #if($table.sub)
      /** $table.subTable.functionName信息 */
      private List<${subClassName}> ${subclassName}List;
      
      #end
      }
      
    2. Controller类支持Swagger,修改模板
      • rstone-generator模块的 controller.java.vm模板中添加Swagger注解
      package ${packageName}.controller;
      
      import java.util.List;
      import javax.servlet.http.HttpServletResponse;
      import org.springframework.security.access.prepost.PreAuthorize;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.web.bind.annotation.GetMapping;
      import org.springframework.web.bind.annotation.PostMapping;
      import org.springframework.web.bind.annotation.PutMapping;
      import org.springframework.web.bind.annotation.DeleteMapping;
      import org.springframework.web.bind.annotation.PathVariable;
      import org.springframework.web.bind.annotation.RequestBody;
      import org.springframework.web.bind.annotation.RequestMapping;
      import org.springframework.web.bind.annotation.RestController;
      import com.dkd.common.annotation.Log;
      import com.dkd.common.core.controller.BaseController;
      import com.dkd.common.core.domain.AjaxResult;
      import com.dkd.common.enums.BusinessType;
      import ${packageName}.domain.${ClassName};
      import ${packageName}.service.I${ClassName}Service;
      import com.dkd.common.utils.poi.ExcelUtil;
      #if($table.crud || $table.sub)
      import com.dkd.common.core.page.TableDataInfo;
      #elseif($table.tree)
      #end
      import io.swagger.annotations.Api;
      import io.swagger.annotations.ApiOperation;
      
      /**
      * ${functionName}Controller
      *
      * @author ${author}
      * @date ${datetime}
      */
      @Api(tags = "${functionName}Controller")
      @RestController
      @RequestMapping("/${moduleName}/${businessName}")
      public class ${ClassName}Controller extends BaseController
      {
          @Autowired
          private I${ClassName}Service ${className}Service;
      
          /**
          * 查询${functionName}列表
          */
          @ApiOperation("查询${functionName}列表")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
          @GetMapping("/list")
      #if($table.crud || $table.sub)
          public TableDataInfo list(${ClassName} ${className})
          {
              startPage();
              List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
              return getDataTable(list);
          }
      #elseif($table.tree)
          public AjaxResult list(${ClassName} ${className})
          {
              List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
              return success(list);
          }
      #end
      
          /**
          * 导出${functionName}列表
          */
          @ApiOperation("导出${functionName}列表")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
          @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
          @PostMapping("/export")
          public void export(HttpServletResponse response, ${ClassName} ${className})
          {
              List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
              ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
              util.exportExcel(response, list, "${functionName}数据");
          }
      
          /**
          * 获取${functionName}详细信息
          */
          @ApiOperation("获取${functionName}详细信息")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
          @GetMapping(value = "/{${pkColumn.javaField}}")
          public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
          {
              return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
          }
      
          /**
          * 新增${functionName}
          */
          @ApiOperation("新增${functionName}")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')")
          @Log(title = "${functionName}", businessType = BusinessType.INSERT)
          @PostMapping
          public AjaxResult add(@RequestBody ${ClassName} ${className})
          {
              return toAjax(${className}Service.insert${ClassName}(${className}));
          }
      
          /**
          * 修改${functionName}
          */
          @ApiOperation("修改${functionName}")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')")
          @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
          @PutMapping
          public AjaxResult edit(@RequestBody ${ClassName} ${className})
          {
              return toAjax(${className}Service.update${ClassName}(${className}));
          }
      
          /**
          * 删除${functionName}
          */
          @ApiOperation("删除${functionName}")
          @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')")
          @Log(title = "${functionName}", businessType = BusinessType.DELETE)
          @DeleteMapping("/{${pkColumn.javaField}s}")
          public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
          {
              return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
          }
      }
      

5.代码生成操作

  1. 启动若依项目,在浏览器使用管理员进入
  2. 菜单选择:系统工具/代码生成
  3. 在数据库中创建表,写好注释「注释默认为标题」。
    • 可以使用数据库工具创建
    • 也可以使用「代码生成」中的创建执行
  4. 点击「导入」选择创建的表。
  5. 在列表中选择导入的表,点击「编辑」,设置相关信息。
  6. 在列表中选择「生成代码」,会下载一个压缩包,解开压缩包「这里以RstoneUser实体为例」:
    • sql语句
      • RstoneUserMenu.sql 增加菜单和按钮的sql语句。
    • java
      • main/java/cn/com/rstone/official/website/admin/domain/RstoneUser.java 表对应的实体类
      • main/java/cn/com/rstone/official/website/admin/mapper/RstoneUserMapper.java mapper类
      • main/java/cn/com/rstone/official/website/admin/service/IRstoneUserService.java 服务类接口
      • main/java/cn/com/rstone/official/website/admin/service/impl/RstoneUserServiceImpl.java 服务类实现
      • main/java/cn/com/rstone/official/website/admin/controller/RstoneUserController.java controller类
      • main/resources/mapper/rstone-official-website-admin/RstoneUserMapper.xml sql语句的xml文件
    • vue
      • api/rstone-official-website-admin/RstoneUser.js 接口api
      • views/rstone-official-website-admin/RstoneUser/index.vue 页面