Explorar o código

代码预览的功能,完成

YunaiV %!s(int64=4) %!d(string=hai) anos
pai
achega
8cfb82659b

+ 1 - 33
ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java

@@ -38,17 +38,6 @@ import com.ruoyi.generator.service.IGenTableService;
 @RequestMapping("/tool/gen")
 public class GenController extends BaseController {
 
-    /**
-     * 查询数据库列表
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping("/db/list")
-    public TableDataInfo dataList(GenTable genTable) {
-        startPage();
-        List<GenTable> list = genTableService.selectDbTableList(genTable);
-        return getDataTable(list);
-    }
-
     /**
      * 查询数据表字段列表
      */
@@ -87,16 +76,6 @@ public class GenController extends BaseController {
         return AjaxResult.success();
     }
 
-    /**
-     * 预览代码
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
-    @GetMapping("/preview/{tableId}")
-    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException {
-        Map<String, String> dataMap = genTableService.previewCode(tableId);
-        return AjaxResult.success(dataMap);
-    }
-
     /**
      * 生成代码(下载方式)
      */
@@ -130,18 +109,6 @@ public class GenController extends BaseController {
         return AjaxResult.success();
     }
 
-    /**
-     * 批量生成代码
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
-    @GetMapping("/batchGenCode")
-    public void batchGenCode(HttpServletResponse response, String tables) throws IOException {
-        String[] tableNames = Convert.toStrArray(tables);
-        byte[] data = genTableService.downloadCode(tableNames);
-        genCode(response, data);
-    }
-
     /**
      * 生成zip文件
      */
@@ -154,4 +121,5 @@ public class GenController extends BaseController {
         response.setContentType("application/octet-stream; charset=UTF-8");
         IOUtils.write(data, response.getOutputStream());
     }
+
 }

+ 0 - 200
ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java

@@ -44,7 +44,6 @@ import com.ruoyi.generator.util.VelocityUtils;
  */
 @Service
 public class GenTableServiceImpl implements IGenTableService {
-    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
 
     @Autowired
     private GenTableMapper genTableMapper;
@@ -65,17 +64,6 @@ public class GenTableServiceImpl implements IGenTableService {
         return genTable;
     }
 
-    /**
-     * 查询业务列表
-     *
-     * @param genTable 业务信息
-     * @return 业务集合
-     */
-    @Override
-    public List<GenTable> selectGenTableList(GenTable genTable) {
-        return genTableMapper.selectGenTableList(genTable);
-    }
-
     /**
      * 查询据库列表
      *
@@ -98,25 +86,6 @@ public class GenTableServiceImpl implements IGenTableService {
         return genTableMapper.selectDbTableListByNames(tableNames);
     }
 
-    /**
-     * 修改业务
-     *
-     * @param genTable 业务信息
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public void updateGenTable(GenTable genTable) {
-        String options = JSON.toJSONString(genTable.getParams());
-        genTable.setOptions(options);
-        int row = genTableMapper.updateGenTable(genTable);
-        if (row > 0) {
-            for (GenTableColumn cenTableColumn : genTable.getColumns()) {
-                genTableColumnMapper.updateGenTableColumn(cenTableColumn);
-            }
-        }
-    }
-
     /**
      * 删除业务对象
      *
@@ -158,36 +127,6 @@ public class GenTableServiceImpl implements IGenTableService {
         }
     }
 
-    /**
-     * 预览代码
-     *
-     * @param tableId 表编号
-     * @return 预览数据列表
-     */
-    @Override
-    public Map<String, String> previewCode(Long tableId) {
-        Map<String, String> dataMap = new LinkedHashMap<>();
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableById(tableId);
-        // 查询列信息
-        List<GenTableColumn> columns = table.getColumns();
-        setPkColumn(table, columns);
-        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;
-    }
-
     /**
      * 生成代码(下载方式)
      *
@@ -203,40 +142,6 @@ public class GenTableServiceImpl implements IGenTableService {
         return outputStream.toByteArray();
     }
 
-    /**
-     * 生成代码(自定义路径)
-     *
-     * @param tableName 表名称
-     */
-    @Override
-    public void generatorCode(String tableName) {
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableByName(tableName);
-        // 查询列信息
-        List<GenTableColumn> columns = table.getColumns();
-        setPkColumn(table, columns);
-
-        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.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
-                } catch (IOException e) {
-                    throw new CustomException("渲染模板失败,表名:" + table.getTableName());
-                }
-            }
-        }
-    }
 
     /**
      * 同步数据库
@@ -266,57 +171,6 @@ public class GenTableServiceImpl implements IGenTableService {
         }
     }
 
-    /**
-     * 批量生成代码(下载方式)
-     *
-     * @param tableNames 表数组
-     * @return 数据
-     */
-    @Override
-    public byte[] downloadCode(String[] tableNames) {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        ZipOutputStream zip = new ZipOutputStream(outputStream);
-        for (String tableName : tableNames) {
-            generatorCode(tableName, zip);
-        }
-        IOUtils.closeQuietly(zip);
-        return outputStream.toByteArray();
-    }
-
-    /**
-     * 查询表信息并生成代码
-     */
-    private void generatorCode(String tableName, ZipOutputStream zip) {
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableByName(tableName);
-        // 查询列信息
-        List<GenTableColumn> columns = table.getColumns();
-        setPkColumn(table, columns);
-
-        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)));
-                IOUtils.write(sw.toString(), zip, Constants.UTF8);
-                IOUtils.closeQuietly(sw);
-                zip.flush();
-                zip.closeEntry();
-            } catch (IOException e) {
-                log.error("渲染模板失败,表名:" + table.getTableName(), e);
-            }
-        }
-    }
-
     /**
      * 修改保存参数校验
      *
@@ -337,58 +191,4 @@ public class GenTableServiceImpl implements IGenTableService {
         }
     }
 
-    /**
-     * 设置主键列信息
-     *
-     * @param table   业务表信息
-     * @param columns 业务字段列表
-     */
-    public void setPkColumn(GenTable table, List<GenTableColumn> columns) {
-        for (GenTableColumn column : columns) {
-            if (column.isPk()) {
-                table.setPkColumn(column);
-                break;
-            }
-        }
-        if (StringUtils.isNull(table.getPkColumn())) {
-            table.setPkColumn(columns.get(0));
-        }
-    }
-
-    /**
-     * 设置代码生成其他选项值
-     *
-     * @param genTable 设置后的生成对象
-     */
-    public void setTableFromOptions(GenTable genTable) {
-        JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions());
-        if (StringUtils.isNotNull(paramsObj)) {
-            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
-            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
-            String treeName = paramsObj.getString(GenConstants.TREE_NAME);
-            String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);
-            String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
-
-            genTable.setTreeCode(treeCode);
-            genTable.setTreeParentCode(treeParentCode);
-            genTable.setTreeName(treeName);
-            genTable.setParentMenuId(parentMenuId);
-            genTable.setParentMenuName(parentMenuName);
-        }
-    }
-
-    /**
-     * 获取代码生成地址
-     *
-     * @param table    业务表信息
-     * @param template 模板文件路径
-     * @return 生成地址
-     */
-    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);
-    }
 }

+ 0 - 9
ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java

@@ -18,15 +18,6 @@ import com.ruoyi.generator.domain.GenTableColumn;
  * @author ruoyi
  */
 public class VelocityUtils {
-    /**
-     * 项目空间路径
-     */
-    private static final String PROJECT_PATH = "main/java";
-
-    /**
-     * mybatis空间路径
-     */
-    private static final String MYBATIS_PATH = "main/resources/mapper";
 
     /**
      * 默认上级菜单,系统工具

+ 17 - 0
ruoyi-ui/src/api/tool/codegen.js

@@ -25,3 +25,20 @@ export function updateCodegen(data) {
     data: data
   })
 }
+
+// 预览生成代码
+export function previewCodegen(tableId) {
+  return request({
+    url: '/tool/codegen/preview?tableId=' + tableId,
+    method: 'get'
+  })
+}
+
+// 下载生成代码
+export function downloadCodegen(tableId) {
+  return request({
+    url: '/tool/codegen/download?tableId=' + tableId,
+    method: 'get',
+    responseType: 'blob'
+  })
+}

+ 0 - 8
ruoyi-ui/src/api/tool/gen.js

@@ -18,14 +18,6 @@ export function importTable(data) {
   })
 }
 
-// 预览生成代码
-export function previewTable(tableId) {
-  return request({
-    url: '/tool/gen/preview/' + tableId,
-    method: 'get'
-  })
-}
-
 // 删除表数据
 export function delTable(tableId) {
   return request({

+ 12 - 1
ruoyi-ui/src/main.js

@@ -16,7 +16,17 @@ import './assets/icons' // icon
 import './permission' // permission control
 import { getDicts } from "@/api/system/dict/data";
 import { getConfigKey } from "@/api/infra/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, download, handleTree, downloadExcel } from "@/utils/ruoyi";
+import {
+  parseTime,
+  resetForm,
+  addDateRange,
+  selectDictLabel,
+  selectDictLabels,
+  download,
+  handleTree,
+  downloadExcel,
+  downloadZip
+} from "@/utils/ruoyi";
 import Pagination from "@/components/Pagination";
 // 自定义表格工具扩展
 import RightToolbar from "@/components/RightToolbar"
@@ -38,6 +48,7 @@ Vue.prototype.getDictDataLabel = getDictDataLabel
 Vue.prototype.DICT_TYPE = DICT_TYPE
 Vue.prototype.download = download
 Vue.prototype.downloadExcel = downloadExcel
+Vue.prototype.downloadZip = downloadZip
 Vue.prototype.handleTree = handleTree
 
 Vue.prototype.msgSuccess = function (msg) {

+ 15 - 0
ruoyi-ui/src/utils/ruoyi.js

@@ -116,6 +116,21 @@ export function downloadExcel(data, fileName) {
   window.URL.revokeObjectURL(href);
 }
 
+// 下载 Zip 方法
+export function downloadZip(data, fileName) {
+  // 创建 blob
+  let blob = new Blob([data], {type: 'application/zip'});
+  // 创建 href 超链接,点击进行下载
+  window.URL = window.URL || window.webkitURL;
+  let href = URL.createObjectURL(blob);
+  let downA = document.createElement("a");
+  downA.href =  href;
+  downA.download = fileName;
+  downA.click();
+  // 销毁超连接
+  window.URL.revokeObjectURL(href);
+}
+
 // 字符串格式化(%s )
 export function sprintf(str) {
 	var args = arguments, flag = true, i = 1;

+ 36 - 125
ruoyi-ui/src/views/tool/gen/index.vue

@@ -39,70 +39,18 @@
 
     <el-row :gutter="10" class="mb8">
       <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleGenTable"
-          v-hasPermi="['tool:gen:code']"
-        >生成</el-button>
+        <el-button type="primary" plain icon="el-icon-download" size="mini" @click="handleGenTable" v-hasPermi="['tool:gen:code']">生成</el-button>
       </el-col>
       <el-col :span="1.5">
-        <el-button
-          type="info"
-          plain
-          icon="el-icon-upload"
-          size="mini"
-          @click="openImportTable"
-          v-hasPermi="['tool:gen:import']"
-        >导入</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          @click="handleEditTable"
-          v-hasPermi="['tool:gen:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          @click="handleDelete"
-          v-hasPermi="['tool:gen:remove']"
-        >删除</el-button>
+        <el-button type="info" plain icon="el-icon-upload" size="mini" @click="openImportTable" v-hasPermi="['tool:gen:import']">导入</el-button>
       </el-col>
       <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
     </el-row>
 
     <el-table v-loading="loading" :data="tableList">
-      <el-table-column
-        label="表名称"
-        align="center"
-        prop="tableName"
-        :show-overflow-tooltip="true"
-        width="120"
-      />
-      <el-table-column
-        label="表描述"
-        align="center"
-        prop="tableComment"
-        :show-overflow-tooltip="true"
-        width="120"
-      />
-      <el-table-column
-        label="实体"
-        align="center"
-        prop="className"
-        :show-overflow-tooltip="true"
-        width="120"
-      />
+      <el-table-column label="表名称" align="center" prop="tableName" :show-overflow-tooltip="true" width="200"/>
+      <el-table-column label="表描述" align="center" prop="tableComment" :show-overflow-tooltip="true" width="120"/>
+      <el-table-column label="实体" align="center" prop="className" :show-overflow-tooltip="true" width="200"/>
       <el-table-column label="创建时间" align="center" prop="createTime" width="160">
         <template slot-scope="scope">
           <span>{{ parseTime(scope.row.createTime) }}</span>
@@ -115,61 +63,20 @@
       </el-table-column>
       <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
         <template slot-scope="scope">
-          <el-button
-            type="text"
-            size="small"
-            icon="el-icon-view"
-            @click="handlePreview(scope.row)"
-            v-hasPermi="['tool:gen:preview']"
-          >预览</el-button>
-          <el-button
-            type="text"
-            size="small"
-            icon="el-icon-edit"
-            @click="handleEditTable(scope.row)"
-            v-hasPermi="['tool:gen:edit']"
-          >编辑</el-button>
-          <el-button
-            type="text"
-            size="small"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['tool:gen:remove']"
-          >删除</el-button>
-          <el-button
-            type="text"
-            size="small"
-            icon="el-icon-refresh"
-            @click="handleSynchDb(scope.row)"
-            v-hasPermi="['tool:gen:edit']"
-          >同步</el-button>
-          <el-button
-            type="text"
-            size="small"
-            icon="el-icon-download"
-            @click="handleGenTable(scope.row)"
-            v-hasPermi="['tool:gen:code']"
-          >生成代码</el-button>
+          <el-button type="text" size="small" icon="el-icon-view" @click="handlePreview(scope.row)" v-hasPermi="['tool:gen:preview']">预览</el-button>
+          <el-button type="text" size="small" icon="el-icon-edit" @click="handleEditTable(scope.row)" v-hasPermi="['tool:gen:edit']">编辑</el-button>
+          <el-button type="text" size="small" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['tool:gen:remove']">删除</el-button>
+          <el-button type="text" size="small" icon="el-icon-refresh" @click="handleSynchDb(scope.row)" v-hasPermi="['tool:gen:edit']">同步</el-button>
+          <el-button type="text" size="small" icon="el-icon-download" @click="handleGenTable(scope.row)" v-hasPermi="['tool:gen:code']">生成代码</el-button>
         </template>
       </el-table-column>
     </el-table>
-    <pagination
-      v-show="total>0"
-      :total="total"
-      :page.sync="queryParams.pageNo"
-      :limit.sync="queryParams.pageSize"
-      @pagination="getList"
-    />
+    <pagination v-show="total>0" :total="total" :page.sync="queryParams.pageNo" :limit.sync="queryParams.pageSize" @pagination="getList"/>
     <!-- 预览界面 -->
     <el-dialog :title="preview.title" :visible.sync="preview.open" width="80%" top="5vh" append-to-body>
-      <el-tabs v-model="preview.activeName">
-        <el-tab-pane
-          v-for="(value, key) in preview.data"
-          :label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
-          :name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
-          :key="key"
-        >
-        <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
+      <el-tabs tab-position="left" v-model="preview.activeName">
+        <el-tab-pane v-for="item in preview.data" :label="item.filePath.substring(item.filePath.lastIndexOf('/') + 1)" :name="item.filePath" :key="item.filePath">
+          <pre><code class="hljs" v-html="highlightedCode(item)"></code></pre>
         </el-tab-pane>
       </el-tabs>
     </el-dialog>
@@ -179,7 +86,7 @@
 
 <script>
 import { previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
-import { getCodeGenTablePage } from "@/api/tool/codegen";
+import { getCodeGenTablePage, previewCodegen, } from "@/api/tool/codegen";
 
 import importTable from "./importTable";
 import { downLoadZip } from "@/utils/zipdownload";
@@ -260,18 +167,20 @@ export default {
     },
     /** 生成代码操作 */
     handleGenTable(row) {
-      const tableNames = row.tableName || this.tableNames;
-      if (tableNames === "") {
-        this.msgError("请选择要生成的数据");
-        return;
-      }
-      if(row.genType === "1") {
-        genCode(row.tableName).then(response => {
-          this.msgSuccess("成功生成到自定义路径:" + row.genPath);
-        });
-      } else {
-        downLoadZip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
-      }
+      // const tableNames = row.tableName || this.tableNames;
+      // if (tableNames === "") {
+      //   this.msgError("请选择要生成的数据");
+      //   return;
+      // }
+      // if(row.genType === "1") {
+      //   genCode(row.tableName).then(response => {
+      //     this.msgSuccess("成功生成到自定义路径:" + row.genPath);
+      //   });
+      // } else {
+      //   downLoadZip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi");
+      // }
+
+
     },
     /** 同步数据库操作 */
     handleSynchDb(row) {
@@ -298,16 +207,18 @@ export default {
     },
     /** 预览按钮 */
     handlePreview(row) {
-      previewTable(row.tableId).then(response => {
+      previewCodegen(row.id).then(response => {
         this.preview.data = response.data;
+        this.preview.activeName = response.data[0].filePath;
         this.preview.open = true;
       });
     },
     /** 高亮显示 */
-    highlightedCode(code, key) {
-      const vmName = key.substring(key.lastIndexOf("/") + 1, key.indexOf(".vm"));
-      var language = vmName.substring(vmName.indexOf(".") + 1, vmName.length);
-      const result = hljs.highlight(language, code || "", true);
+    highlightedCode(item) {
+      // const vmName = key.substring(key.lastIndexOf("/") + 1, key.indexOf(".vm"));
+      // var language = vmName.substring(vmName.indexOf(".") + 1, vmName.length);
+      var language = item.filePath.substring(item.filePath.lastIndexOf(".") + 1);
+      const result = hljs.highlight(language, item.code || "", true);
       return result.value || '&nbsp;';
     },
     /** 修改按钮操作 */

+ 75 - 3
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/ToolCodegenController.java

@@ -1,8 +1,10 @@
 package cn.iocoder.dashboard.modules.tool.controller.codegen;
 
+import cn.hutool.core.io.IoUtil;
 import cn.iocoder.dashboard.common.pojo.CommonResult;
 import cn.iocoder.dashboard.common.pojo.PageResult;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenDetailRespVO;
+import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenPreviewRespVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenUpdateReqVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.table.ToolCodegenTablePageReqVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.table.ToolCodegenTableRespVO;
@@ -11,13 +13,20 @@ import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenColum
 import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
 import cn.iocoder.dashboard.modules.tool.service.codegen.ToolCodegenService;
 import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
 import javax.validation.Valid;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
 import java.util.List;
+import java.util.Map;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
 
 import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
 
@@ -55,9 +64,6 @@ public class ToolCodegenController {
         return success(codegenService.createCodegen(tableName));
     }
 
-    /**
-     * 修改保存代码生成业务
-     */
     @ApiOperation("更新数据库的表和字段定义")
     @PutMapping("/update")
 //    @PreAuthorize("@ss.hasPermi('tool:gen:edit')") TODO 权限
@@ -66,4 +72,70 @@ public class ToolCodegenController {
         return success(true);
     }
 
+    @ApiOperation("预览生成代码")
+    @GetMapping("/preview")
+    @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
+//    @PreAuthorize("@ss.hasPermi('tool:gen:preview')") TODO 权限
+    public CommonResult<List<ToolCodegenPreviewRespVO>> previewCodegen(@RequestParam("tableId") Long tableId) {
+        Map<String, String> codes = codegenService.generationCodes(tableId);
+        return success(ToolCodegenConvert.INSTANCE.convert(codes));
+    }
+
+    @ApiOperation("下载生成代码")
+    @GetMapping("/download")
+    @ApiImplicitParam(name = "tableId", required = true, example = "表编号", dataTypeClass = Long.class)
+    public void downloadCodegen(@RequestParam("tableId") Long tableId,
+                                HttpServletResponse response) throws IOException {
+        // 生成代码
+        Map<String, String> codes = codegenService.generationCodes(tableId);
+        // 构建压缩包
+        byte[] data;
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        for (Map.Entry<String, String> entry : codes.entrySet()) {
+//                zip.putNextEntry(new ZipEntry(entry.getKey()));
+            zip.putNextEntry(new ZipEntry("123"));
+//                IoUtil.write(zip, Charset.defaultCharset(), false, entry.getValue());
+            zip.write(entry.getValue().getBytes());
+            zip.flush();
+            zip.closeEntry();
+            if (true) {
+                break;
+            }
+        }
+        data = outputStream.toByteArray();
+        IoUtil.close(zip);
+//        try (ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+//             ZipOutputStream zip = new ZipOutputStream(outputStream)) {
+//            for (Map.Entry<String, String> entry : codes.entrySet()) {
+////                zip.putNextEntry(new ZipEntry(entry.getKey()));
+//                zip.putNextEntry(new ZipEntry("123"));
+////                IoUtil.write(zip, Charset.defaultCharset(), false, entry.getValue());
+//                zip.write(entry.getValue().getBytes());
+//                zip.flush();
+//                zip.closeEntry();
+//                if (true) {
+//                    break;
+//                }
+//            }
+//            data = outputStream.toByteArray();
+//        }
+        // 返回
+//        ServletUtils.writeAttachment(response, "yudao.zip", data);
+        genCode(response, data);
+    }
+
+    /**
+     * 生成zip文件
+     */
+    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);
+    }
 }

+ 17 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/controller/codegen/vo/ToolCodegenPreviewRespVO.java

@@ -0,0 +1,17 @@
+package cn.iocoder.dashboard.modules.tool.controller.codegen.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel(value = "代码生成预览 Response VO", description ="注意,每个文件都是一个该对象")
+@Data
+public class ToolCodegenPreviewRespVO {
+
+    @ApiModelProperty(value = "文件路径", required = true, example = "java/cn/iocoder/dashboard/modules/system/controller/test/SysTestDemoController.java")
+    private String filePath;
+
+    @ApiModelProperty(value = "代码", required = true, example = "Hello World")
+    private String code;
+
+}

+ 13 - 1
src/main/java/cn/iocoder/dashboard/modules/tool/convert/codegen/ToolCodegenConvert.java

@@ -1,9 +1,10 @@
 package cn.iocoder.dashboard.modules.tool.convert.codegen;
 
 import cn.iocoder.dashboard.common.pojo.PageResult;
+import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenDetailRespVO;
+import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenPreviewRespVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenUpdateReqVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.column.ToolCodegenColumnRespVO;
-import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.ToolCodegenDetailRespVO;
 import cn.iocoder.dashboard.modules.tool.controller.codegen.vo.table.ToolCodegenTableRespVO;
 import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenColumnDO;
 import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
@@ -13,6 +14,8 @@ import org.mapstruct.Mapper;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
 
 @Mapper
 public interface ToolCodegenConvert {
@@ -52,4 +55,13 @@ public interface ToolCodegenConvert {
         return respVO;
     }
 
+    default List<ToolCodegenPreviewRespVO> convert(Map<String, String> codes) {
+        return codes.entrySet().stream().map(entry -> {
+            ToolCodegenPreviewRespVO respVO = new ToolCodegenPreviewRespVO();
+            respVO.setFilePath(entry.getKey());
+            respVO.setCode(entry.getValue());
+            return respVO;
+        }).collect(Collectors.toList());
+    }
+
 }

+ 9 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/ToolCodegenService.java

@@ -7,6 +7,7 @@ import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenColum
 import cn.iocoder.dashboard.modules.tool.dal.dataobject.codegen.ToolCodegenTableDO;
 
 import java.util.List;
+import java.util.Map;
 
 /**
  * 代码生成 Service 接口
@@ -54,4 +55,12 @@ public interface ToolCodegenService {
      */
     List<ToolCodegenColumnDO> getCodegenColumnListByTableId(Long tableId);
 
+    /**
+     * 执行指定表的代码生成
+     *
+     * @param tableId 表编号
+     * @return 生成结果。key 为文件路径,value 为对应的代码内容
+     */
+    Map<String, String> generationCodes(Long tableId);
+
 }

+ 4 - 3
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenEngine.java

@@ -21,6 +21,7 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.util.HashMap;
+import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -42,7 +43,7 @@ public class ToolCodegenEngine {
      * key:模板在 resources 的地址
      * value:生成的路径
      */
-    private static final Map<String, String> TEMPLATES = MapUtil.<String, String>builder()
+    private static final Map<String, String> TEMPLATES = MapUtil.<String, String>builder(new LinkedHashMap<>()) // 有序
             // Java
             .put("codegen/java/controller/controller.vm", "java/${basePackage}/${table.moduleName}/controller/${table.businessName}/${table.className}Controller.java")
             .put("codegen/java/controller/vo/baseVO.vm", "java/${basePackage}/${table.moduleName}/controller/${table.businessName}/vo/${table.className}BaseVO.java")
@@ -53,7 +54,7 @@ public class ToolCodegenEngine {
             .put("codegen/java/convert/convert.vm", "java/${basePackage}/${table.moduleName}/convert/${table.businessName}/${table.className}Convert.java")
             .put("codegen/java/dal/do.vm", "java/${basePackage}/${table.moduleName}/dal/dataobject/${table.businessName}/${table.className}DO.java")
             .put("codegen/java/dal/mapper.vm", "java/${basePackage}/${table.moduleName}/dal/mysql/${table.businessName}/${table.className}Mapper.java")
-            .put("codegen/java/enums/errorcode.vm", "java/${basePackage}.${table.moduleName}.enums.${simpleModuleName_upperFirst}ErrorCodeConstants.java")
+            .put("codegen/java/enums/errorcode.vm", "java/${basePackage}/${table.moduleName}/enums/${simpleModuleName_upperFirst}ErrorCodeConstants.java")
             .put("codegen/java/service/service.vm", "java/${basePackage}/${table.moduleName}/service/${table.businessName}/${table.className}Service.java")
             .put("codegen/java/service/serviceImpl.vm", "java/${basePackage}/${table.moduleName}/service/${table.businessName}/impl/${table.className}ServiceImpl.java")
             // Vue
@@ -117,7 +118,7 @@ public class ToolCodegenEngine {
         bindingMap.put("simpleClassName_strikeCase", toSymbolCase(simpleClassName, '-')); // 将 DictType 转换成 dict-type
 
         // 执行生成
-        final Map<String, String> result = Maps.newHashMapWithExpectedSize(TEMPLATES.size());
+        final Map<String, String> result = Maps.newLinkedHashMapWithExpectedSize(TEMPLATES.size()); // 有序
         TEMPLATES.forEach((vmPath, filePath) -> {
             filePath = formatFilePath(filePath, bindingMap);
             String content = templateEngine.getTemplate(vmPath).render(bindingMap);

+ 17 - 0
src/main/java/cn/iocoder/dashboard/modules/tool/service/codegen/impl/ToolCodegenServiceImpl.java

@@ -19,6 +19,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.List;
+import java.util.Map;
 
 /**
  * 代码生成 Service 实现类
@@ -102,4 +103,20 @@ public class ToolCodegenServiceImpl implements ToolCodegenService {
         return codegenColumnMapper.selectListByTableId(tableId);
     }
 
+    @Override
+    public Map<String, String> generationCodes(Long tableId) {
+        // 校验是否已经存在
+        ToolCodegenTableDO table = codegenTableMapper.selectById(tableId);
+        if (codegenTableMapper.selectById(tableId) == null) {
+            throw new RuntimeException(""); // TODO
+        }
+        List<ToolCodegenColumnDO> columns = codegenColumnMapper.selectListByTableId(tableId);
+        if (CollUtil.isEmpty(columns)) {
+            throw new RuntimeException(""); // TODO
+        }
+
+        // 执行生成
+        return codegenEngine.execute(table, columns);
+    }
+
 }

+ 4 - 4
src/main/resources/codegen/java/controller/controller.vm

@@ -42,8 +42,8 @@ public class ${table.className}Controller {
         return success(true);
     }
 
-	@ApiOperation("删除${table.classComment}")
-	@DeleteMapping("/delete")
+    @ApiOperation("删除${table.classComment}")
+    @DeleteMapping("/delete")
     @ApiImplicitParam(name = "id", value = "编号", required = true)
     public CommonResult<Boolean> delete${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
         ${classNameVar}Service.delete${simpleClassName}(id);
@@ -52,7 +52,7 @@ public class ${table.className}Controller {
 
     @GetMapping("/get")
     @ApiOperation("获得${table.classComment}")
-    @ApiImplicitParam(name = "id", value = "编号", required = true)
+    @ApiImplicitParam(name = "id", value = "编号", required = true, dataTypeClass = ${primaryColumn.javaType}.class)
     public CommonResult<${table.className}RespVO> get${simpleClassName}(@RequestParam("id") ${primaryColumn.javaType} id) {
         ${table.className}DO ${classNameVar} = ${classNameVar}Service.get${simpleClassName}(id);
         return success(${table.className}Convert.INSTANCE.convert(${classNameVar}));
@@ -60,7 +60,7 @@ public class ${table.className}Controller {
 
     @GetMapping("/list")
     @ApiOperation("获得${table.classComment}列表")
-    @ApiImplicitParam(name = "ids", value = "编号列表", required = true)
+    @ApiImplicitParam(name = "ids", value = "编号列表", required = true, dataTypeClass = List.class)
     public CommonResult<List<${table.className}RespVO>> get${simpleClassName}List(@RequestParam("ids") Collection<${primaryColumn.javaType}> ids) {
         List<${table.className}DO> list = ${classNameVar}Service.get${simpleClassName}List(ids);
         return success(${table.className}Convert.INSTANCE.convertList(list));

+ 1 - 1
src/main/resources/codegen/java/convert/convert.vm

@@ -27,6 +27,6 @@ public interface ${table.className}Convert {
 
     List<${table.className}RespVO> convertList(List<${table.className}DO> list);
 
-	PageResult<${table.className}RespVO> convertPage(PageResult<${table.className}DO> page);
+    PageResult<${table.className}RespVO> convertPage(PageResult<${table.className}DO> page);
 
 }

+ 1 - 1
src/main/resources/codegen/java/service/service.vm

@@ -57,6 +57,6 @@ public interface ${table.className}Service {
      * @param pageReqVO 分页查询
      * @return ${table.classComment}分页
      */
-	PageResult<${table.className}DO> get${simpleClassName}Page(${table.className}PageReqVO pageReqVO);
+    PageResult<${table.className}DO> get${simpleClassName}Page(${table.className}PageReqVO pageReqVO);
 
 }

+ 1 - 1
src/main/resources/codegen/java/service/serviceImpl.vm

@@ -72,7 +72,7 @@ public class ${table.className}ServiceImpl implements ${table.className}Service
         return ${classNameVar}Mapper.selectBatchIds(ids);
     }
 
-	@Override
+    @Override
     public PageResult<${table.className}DO> get${simpleClassName}Page(${table.className}PageReqVO pageReqVO) {
 		return ${classNameVar}Mapper.selectPage(pageReqVO);
     }