diff --git a/ruoyi-ui/src/api/tool/gen.js b/ruoyi-ui/src/api/tool/gen.js new file mode 100644 index 000000000..5cebbc25c --- /dev/null +++ b/ruoyi-ui/src/api/tool/gen.js @@ -0,0 +1,66 @@ +import request from '@/utils/request' + +// 查询 +export function listTable(query) { + return request({ + url: '/tool/gen/list', + method: 'post', + params: query + }) +} +// 查询db数据库列表 +export function listdbTable(query) { + return request({ + url: '/tool/gen/db/list', + method: 'post', + params: query + }) +} +// 导出table +export function exportTable(data) { + return request({ + url: '/tool/gen/list/'+data, + method: 'get', + }) +} +// 查询更改表信息 +export function editTableInfo(data) { + return request({ + url: '/tool/gen/edit', + method: 'get', + params:data + }) +} + +// 更改表请求 +export function editGenInfo(data) { + return request({ + url: '/tool/gen/edit', + method: 'post', + data:data + }) +} +// 导入表 +export function importTable(data) { + return request({ + url: '/tool/gen/importTable', + method: 'post', + params:data + }) +} +// 预览 +export function previewTable(data) { + return request({ + url: '/tool/gen/preview/'+data, + method: 'get' + }) +} +// 移除tableid +export function removeTable(data) { + return request({ + url: '/tool/gen/remove', + method: 'post', + params:data + }) +} + diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js index 526d755c9..11ca9fe87 100644 --- a/ruoyi-ui/src/router/index.js +++ b/ruoyi-ui/src/router/index.js @@ -1,101 +1,115 @@ -import Vue from 'vue' -import Router from 'vue-router' - -Vue.use(Router) - -/* Layout */ -import Layout from '@/layout' - -/** - * Note: 路由配置项 - * - * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 - * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 - * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 - * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 - * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 - * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 - * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 - * meta : { - roles: ['admin','editor'] // 设置该路由进入的权限,支持多个权限叠加 - title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 - icon: 'svg-name' // 设置该路由的图标,对应路径src/icons/svg - breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 - } - */ - -// 公共路由 -export const constantRoutes = [ - { - path: '/redirect', - component: Layout, - hidden: true, - children: [ - { - path: '/redirect/:path*', - component: () => import('@/views/redirect') - } - ] - }, - { - path: '/login', - component: () => import('@/views/login'), - hidden: true - }, - { - path: '/404', - component: () => import('@/views/error/404'), - hidden: true - }, - { - path: '/401', - component: () => import('@/views/error/401'), - hidden: true - }, - { - path: '', - component: Layout, - redirect: 'index', - children: [ - { - path: 'index', - component: () => import('@/views/index'), - name: '首页', - meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true } - } - ] - }, - { - path: '/user', - component: Layout, - hidden: true, - redirect: 'noredirect', - children: [ - { - path: 'profile', - component: () => import('@/views/system/user/profile/index'), - name: '个人中心', - meta: { title: '个人中心', icon: 'user' } - } - ] - }, - { - path: '/dict', - component: Layout, - hidden: true, - children: [ - { - path: 'type/data/:dictId(\\d+)', - component: () => import('@/views/system/dict/data'), - name: '字典数据', - meta: { title: '字典数据', icon: '' } - } - ] - } -] - -export default new Router({ - mode: 'history', // 去掉url中的# - scrollBehavior: () => ({ y: 0 }), - routes: constantRoutes -}) +import Vue from 'vue' +import Router from 'vue-router' + +Vue.use(Router) + +/* Layout */ +import Layout from '@/layout' + +/** + * Note: 路由配置项 + * + * hidden: true // 当设置 true 的时候该路由不会再侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 + * alwaysShow: true // 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 + * // 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 + * // 若你想不管路由下面的 children 声明的个数都显示你的根路由 + * // 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 + * redirect: noRedirect // 当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 + * name:'router-name' // 设定路由的名字,一定要填写不然使用<keep-alive>时会出现各种问题 + * meta : { + roles: ['admin','editor'] // 设置该路由进入的权限,支持多个权限叠加 + title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 + icon: 'svg-name' // 设置该路由的图标,对应路径src/icons/svg + breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示 + } + */ + +// 公共路由 +export const constantRoutes = [ + { + path: '/redirect', + component: Layout, + hidden: true, + children: [ + { + path: '/redirect/:path*', + component: () => import('@/views/redirect') + } + ] + }, + { + path: '/login', + component: () => import('@/views/login'), + hidden: true + }, + { + path: '/404', + component: () => import('@/views/error/404'), + hidden: true + }, + { + path: '/401', + component: () => import('@/views/error/401'), + hidden: true + }, + { + path: '', + component: Layout, + redirect: 'index', + children: [ + { + path: 'index', + component: () => import('@/views/index'), + name: '首页', + meta: { title: '首页', icon: 'dashboard', noCache: true, affix: true } + } + ] + }, + { + path: '/user', + component: Layout, + hidden: true, + redirect: 'noredirect', + children: [ + { + path: 'profile', + component: () => import('@/views/system/user/profile/index'), + name: '个人中心', + meta: { title: '个人中心', icon: 'user' } + } + ] + }, + { + path: '/dict', + component: Layout, + hidden: true, + children: [ + { + path: 'type/data/:dictId(\\d+)', + component: () => import('@/views/system/dict/data'), + name: '字典数据', + meta: { title: '字典数据', icon: '' } + } + ] + }, + + { + path: '/gen', + component: Layout, + hidden: true, + children: [ + { + path: 'edit', + component: () => import('@/views/tool/gen/edit'), + name: 'genEdit', + meta: { title: '修改生成配置' } + } + ] + } +] + +export default new Router({ + mode: 'history', // 去掉url中的# + scrollBehavior: () => ({ y: 0 }), + routes: constantRoutes +}) diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js index db97dcc58..fbc6095aa 100644 --- a/ruoyi-ui/src/utils/ruoyi.js +++ b/ruoyi-ui/src/utils/ruoyi.js @@ -1,95 +1,96 @@ -/** - * 通用js方法封装处理 - * Copyright (c) 2019 ruoyi - */ - -const baseURL = process.env.VUE_APP_BASE_API - -// 日期格式化 -export function parseTime(time, pattern) { - if (arguments.length === 0) { - return null - } - const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' - let date - if (typeof time === 'object') { - date = time - } else { - if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { - time = parseInt(time) - } - if ((typeof time === 'number') && (time.toString().length === 10)) { - time = time * 1000 - } - date = new Date(time) - } - const formatObj = { - y: date.getFullYear(), - m: date.getMonth() + 1, - d: date.getDate(), - h: date.getHours(), - i: date.getMinutes(), - s: date.getSeconds(), - a: date.getDay() - } - const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { - let value = formatObj[key] - // Note: getDay() returns 0 on Sunday - if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } - if (result.length > 0 && value < 10) { - value = '0' + value - } - return value || 0 - }) - return time_str -} - -// 表单重置 -export function resetForm(refName) { - if (this.$refs[refName] !== undefined) { - this.$refs[refName].resetFields(); - } -} - -// 添加日期范围 -export function addDateRange(params, dateRange) { - var search = params; - if (null != dateRange) { - search.params = { - beginTime: this.dateRange[0], - endTime: this.dateRange[1] - }; - } - return search; -} - -// 回显数据字典 -export function selectDictLabel(datas, value) { - var actions = []; - Object.keys(datas).map((key) => { - if (datas[key].dictValue == ('' + value)) { - actions.push(datas[key].dictLabel); - return false; - } - }) - return actions.join(''); -} - -// 通用下载方法 -export function download(fileName) { - window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true; -} - -// 字符串格式化(%s ) -export function sprintf(str) { - var args = arguments, flag = true, i = 1; - str = str.replace(/%s/g, function () { - var arg = args[i++]; - if (typeof arg === 'undefined') { - flag = false; - return ''; - } - return arg; - }); - return flag ? str : ''; -} \ No newline at end of file +/** + * 通用js方法封装处理 + * Copyright (c) 2019 ruoyi + */ + +const baseURL = process.env.VUE_APP_BASE_API + +// 日期格式化 +export function parseTime(time, pattern) { + if (arguments.length === 0) { + return null + } + const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}' + let date + if (typeof time === 'object') { + date = time + } else { + if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) { + time = parseInt(time) + } + if ((typeof time === 'number') && (time.toString().length === 10)) { + time = time * 1000 + } + date = new Date(time) + } + const formatObj = { + y: date.getFullYear(), + m: date.getMonth() + 1, + d: date.getDate(), + h: date.getHours(), + i: date.getMinutes(), + s: date.getSeconds(), + a: date.getDay() + } + const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => { + let value = formatObj[key] + // Note: getDay() returns 0 on Sunday + if (key === 'a') { return ['日', '一', '二', '三', '四', '五', '六'][value ] } + if (result.length > 0 && value < 10) { + value = '0' + value + } + return value || 0 + }) + return time_str +} + +// 表单重置 +export function resetForm(refName) { + if (this.$refs[refName] !== undefined) { + this.$refs[refName].resetFields(); + } +} + +// 添加日期范围 +export function addDateRange(params, dateRange) { + var search = params; + search.params=[] + if (null != dateRange) { + search.params = { + beginTime: this.dateRange[0], + endTime: this.dateRange[1] + }; + } + return search; +} + +// 回显数据字典 +export function selectDictLabel(datas, value) { + var actions = []; + Object.keys(datas).map((key) => { + if (datas[key].dictValue == ('' + value)) { + actions.push(datas[key].dictLabel); + return false; + } + }) + return actions.join(''); +} + +// 通用下载方法 +export function download(fileName) { + window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true; +} + +// 字符串格式化(%s ) +export function sprintf(str) { + var args = arguments, flag = true, i = 1; + str = str.replace(/%s/g, function () { + var arg = args[i++]; + if (typeof arg === 'undefined') { + flag = false; + return ''; + } + return arg; + }); + return flag ? str : ''; +} diff --git a/ruoyi-ui/src/utils/zipdownload.js b/ruoyi-ui/src/utils/zipdownload.js new file mode 100644 index 000000000..c89e1d82a --- /dev/null +++ b/ruoyi-ui/src/utils/zipdownload.js @@ -0,0 +1,40 @@ +import axios from 'axios' +import { getToken } from '@/utils/auth' + +const mimeMap = { + xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', + zip: 'application/zip' +} + +const baseUrl = process.env.VUE_APP_BASE_API +export function downLoadZip(str, filename) { + var url = baseUrl + str + axios({ + method: 'get', + url: url, + responseType: 'blob', + headers: {'Authorization':'Bearer ' + getToken()} + }).then(res => { + resolveBlob(res, mimeMap.zip) + }) +} +/** + * 解析blob响应内容并下载 + * @param {*} res blob响应内容 + * @param {String} mimeType MIME类型 + */ +export function resolveBlob (res, mimeType) { + const aLink = document.createElement('a') + var blob = new Blob([res.data], { type: mimeType }) + // //从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名; + var patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*') + var contentDisposition = decodeURI(res.headers['content-disposition']) + var result = patt.exec(contentDisposition) + var fileName = result[1] + fileName=fileName.replace(/\"/g,'') + aLink.href = URL.createObjectURL(blob) + aLink.setAttribute('download', fileName) // 设置下载文件名称 + document.body.appendChild(aLink) + aLink.click() + document.body.appendChild(aLink) +} diff --git a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue new file mode 100644 index 000000000..b7236e391 --- /dev/null +++ b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue @@ -0,0 +1,72 @@ +<template> + <el-form :model="info" ref="basicInfoForm" :rules="rules"> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 6, offset: 6}" :md="12" :sm="24"> + <el-form-item label="表名称" prop="tableName"> + <el-input placeholder="请输入仓库名称" v-model="info.tableName"/> + </el-form-item> + </el-col> + <el-col :lg="{span: 6, offset: 1}" :md="12" :sm="24"> + <el-form-item label="表描述" prop="tableComment"> + <el-input placeholder="请输入" v-model="info.tableComment"/> + </el-form-item> + </el-col> + </el-row> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 6, offset: 6}" :md="12" :sm="24"> + <el-form-item label="实体类名称" prop="className"> + <el-input placeholder="请输入" v-model="info.className"/> + </el-form-item> + </el-col> + <el-col :lg="{span: 6, offset: 1}" :md="12" :sm="24"> + <el-form-item label="作者" prop="functionAuthor"> + <el-input placeholder="请输入" v-model="info.functionAuthor"/> + </el-form-item> + </el-col> + </el-row> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 13, offset: 6}" :md="12" :sm="24"> + <el-form-item label="备注" prop="remark"> + <el-input type="textarea" :rows="3" v-model="info.remark"></el-input> + </el-form-item> + </el-col> + </el-row> + </el-form> +</template> +<script> +export default { + name: 'BasicInfoForm', + props: { + info: { + type: Object, + default: null + } + }, + data () { + return { + visible:false, + mdl: {}, + rules: { + tableName: [ + { required: true, message: '请输入表名称', trigger: 'blur' } + ], + tableComment: [ + { required: true, message: '请输入表描述', trigger: 'blur' } + ], + className: [ + { required: true, message: '请输入实体类名称', trigger: 'blur' } + ], + functionAuthor: [ + { required: true, message: '请输入作者', trigger: 'blur' } + ] + } + } + }, + created(){ + + }, + methods:{ + + } +} +</script> diff --git a/ruoyi-ui/src/views/tool/gen/dailog/importDailog.vue b/ruoyi-ui/src/views/tool/gen/dailog/importDailog.vue new file mode 100644 index 000000000..6d8882ee1 --- /dev/null +++ b/ruoyi-ui/src/views/tool/gen/dailog/importDailog.vue @@ -0,0 +1,141 @@ +<template> + <!-- 导入表 --> + <el-dialog title="导入表" :visible.sync="visible" width="800px"> + <el-form :model="queryParams" ref="importQueryForm" :inline="true" label-width="68px"> + <el-form-item label="表名称" prop="tableName"> + <el-input + v-model="queryParams.tableName" + placeholder="请输入表名称" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="表描述" prop="tableComment"> + <el-input + v-model="queryParams.tableComment" + placeholder="请输入表描述" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-button type="text" style="margin-left: 20px" @click="handleImportSearch">搜索</el-button> + <el-button type="text" style="margin-left: 20px" @click="handleImportReset">重置</el-button> + </el-form> + <el-row> + <el-table + :data="dbTableList" + @selection-change="handleSelectionChange" + style="width: 100%;"> + <el-table-column + type="selection" + width="55"></el-table-column> + <el-table-column + prop="tableName" + label="表名称" + > + </el-table-column> + <el-table-column + prop="tableComment" + label="表描述" + > + </el-table-column> + <el-table-column + prop="createTime" + label="创建时间" + > + </el-table-column> + <el-table-column + prop="updateTime" + label="更新时间" + > + </el-table-column> + </el-table> + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="handleDbList" + /> + </el-row> + <div slot="footer" class="dialog-footer"> + <el-button type="primary" @click="handleImportTable">确 定</el-button> + <el-button @click="handleImportCancel">取 消</el-button> + </div> + </el-dialog> +</template> + +<script> +import { listdbTable,importTable } from '@/api/tool/gen' +export default { + data() { + return { + visible: false, + center: true, + // 选中数组 + ids: [], + tables: [], + // 非单个禁用 + single: true, + // 非多个禁用 + multiple: true, + queryParams: + { + tableName:'', + tableComment:'', + pageNum: 1, + pageSize: 10 + }, + dbTableList:[], + total:0 + }; + }, + created() { + this.handleImportSearch() + }, + methods: { + show(){ + this.visible=true + }, + // 多选框选中数据 + handleSelectionChange(selection) { + this.ids = selection.map(item => item.tableId) + this.tables = selection.map(item => item.tableName) + this.single = selection.length!=1 + this.multiple = !selection.length + }, + handleImportSearch() + { + this.queryParams.pageNum=1 + this.handleDbList() + }, + handleDbList() + { + listdbTable(this.queryParams).then(res => { + if(res.code===200){ + this.dbTableList = res.rows + this.total=res.total + } + }) + }, + handleImportReset(){ + this.resetForm("importQueryForm"); + }, + handleImportTable()//导入table + { + importTable({tables:this.tables.join(",")}).then(res => { + this.msgSuccess(res.msg); + if (res.code === 200) { + this.visible=false + this.$emit('ok'); + } + }) + }, + handleImportCancel(){ + this.visible=false + }, + } +}; +</script> diff --git a/ruoyi-ui/src/views/tool/gen/edit.vue b/ruoyi-ui/src/views/tool/gen/edit.vue new file mode 100644 index 000000000..2710dd54b --- /dev/null +++ b/ruoyi-ui/src/views/tool/gen/edit.vue @@ -0,0 +1,165 @@ +<template> + <el-card class="box-card"> + <el-tabs v-model="activeName" type="card" @tab-click="handleClick"> + <el-tab-pane label="基本信息" name="basic"> + <basic-info-form ref="basicInfo" :info="info"/> + </el-tab-pane> + <el-tab-pane label="字段信息" name="cloum"> + <el-table + :data="cloumns" + style="width: 100% ;margin-top: 10px" + > + <el-table-column label="序号" type="index" width="50"/> + <el-table-column label="字段列名" align="center" prop="columnName" /> + <el-table-column label="字段描述" align="center" prop="columnComment" /> + <el-table-column label="物理类型" align="center" prop="columnType" /> + <el-table-column label="查询方式" align="center" > + <template slot-scope="scope" > + <el-select v-model="scope.row.javaType" @change="e => handleChange(e, scope.row.columnId, 'javaType')"> + <el-option value="Long">Long</el-option> + <el-option value="String">String</el-option> + <el-option value="Ingeter">Ingeter</el-option> + <el-option value="Double">Double</el-option> + <el-option value="BigDecimal">BigDecimal</el-option> + <el-option value="Date">Date</el-option> + </el-select> + </template> + </el-table-column> + <el-table-column label="Java属性" align="center" prop="javaField" /> + <el-table-column label="插入" align="center"> + <template slot-scope="scope" width="50"> + <el-checkbox :checked="scope.row.isInsert==='1'" @change="e => handleChange(e, scope.row.columnId, 'isInsert')"></el-checkbox> + </template> + </el-table-column> + <el-table-column label="编辑" align="center"> + <template slot-scope="scope" width="50"> + <el-checkbox :checked="scope.row.isEdit==='1'" @change="e => handleChange(e, scope.row.columnId, 'isEdit')"></el-checkbox> + </template> + </el-table-column> + <el-table-column label="列表" align="center"> + <template slot-scope="scope" width="50"> + <el-checkbox :checked="scope.row.isList==='1'" @change="e => handleChange(e, scope.row.columnId, 'isList')"></el-checkbox> + </template> + </el-table-column> + <el-table-column label="查询" align="center"> + <template slot-scope="scope" width="50"> + <el-checkbox :checked="scope.row.isQuery==='1'" @change="e => handleChange(e, scope.row.columnId, 'isQuery')"></el-checkbox> + </template> + </el-table-column> + <el-table-column label="查询方式" align="center" > + <template slot-scope="scope" > + <el-select v-model="scope.row.queryType" @change="e => handleChange(e, scope.row.columnId, 'queryType')"> + <el-option value="EQ">=</el-option> + <el-option value="NE">!=</el-option> + <el-option value="GT">></el-option> + <el-option value="GTE">>=</el-option> + <el-option value="LT">></el-option> + <el-option value="LTE">>=</el-option> + <el-option value="LIKE">LIKE</el-option> + <el-option value="BETWEEN">BETWEEN</el-option> + </el-select> + </template> + </el-table-column> + <el-table-column label="必填" align="center"> + <template slot-scope="scope" width="50"> + <el-checkbox :checked="scope.row.isRequired==='1'" @change="e => handleChange(e, scope.row.columnId, 'isRequired')"></el-checkbox> + </template> + </el-table-column> + <el-table-column label="显示类型" align="center" > + <template slot-scope="scope" > + <el-select v-model="scope.row.htmlType" @change="e => handleChange(e, scope.row.columnId, 'htmlType')"> + <el-option value="input">文本框</el-option> + <el-option value="textarea">文本域</el-option> + <el-option value="select">下拉框</el-option> + <el-option value="radio">单选框</el-option> + <el-option value="checkbox">复选框</el-option> + <el-option value="datetime">日期控件</el-option> + </el-select> + </template> + </el-table-column> + </el-table> + </el-tab-pane> + <el-tab-pane label="生成信息" name="genInfo"> + <gen-info-form ref="genInfo" :info="info"/> + </el-tab-pane> + </el-tabs> + <el-form label-width="100px"> + <el-form-item style="text-align: center;margin-left:-100px;margin-top:10px;"> + <el-button type="primary" @click="submitForm()">提交</el-button> + <el-button @click="rollback()">返回</el-button> + </el-form-item> + </el-form> + </el-card> +</template> +<script> +import { editTableInfo,editGenInfo } from '@/api/tool/gen' +import basicInfoForm from './basicInfoForm'; +import genInfoForm from './genInfoForm'; +export default { + components:{ + basicInfoForm, + genInfoForm + }, + data() { + return { + activeName: 'cloum', + cloumns:[], + info:{}, + cloumForm:{} + }; + }, + beforeCreate(){ + const { tableId } = this.$route.query + if (tableId) { + editTableInfo({tableId:tableId}).then(res => { + this.cloumns=res.data.rows + this.info=res.data.info + }) + } + }, + methods: { + handleChange (value, key, column) { + const newData = [...this.cloumns] + const target = newData.filter(item => key === item.columnId)[0] + if (target) { + target[column] = value + this.cloumns = newData + } + }, + submitForm() { + const basicForm = this.$refs.basicInfo.$refs.basicInfoForm; + const genForm = this.$refs.genInfo.$refs.genInfoForm; + Promise.all([basicForm, genForm].map(this.getFormPromise)).then(res => { + const validateResult = res.every(item => !!item); + if (validateResult) { + const genTable = Object.assign({}, basicForm.model, genForm.model) + genTable.columns = this.cloumns + console.log('genTable:',genTable) + editGenInfo(genTable).then(res=>{ + console.log('gen edit res:',res) + this.msgSuccess(res.msg); + if(res.code===200){ + this.rollback() + } + }) + } else { + this.msgError("表单校验未通过,请重新检查提交内容"); + } + }) + }, + getFormPromise(form) { + return new Promise(resolve => { + form.validate(res => { + resolve(res); + }) + }) + }, + handleClick(tab, event) { + // console.log(tab, event); + }, + rollback () { + this.$router.push('/tool/server') + } + } +}; +</script> diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue new file mode 100644 index 000000000..2913f1f94 --- /dev/null +++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue @@ -0,0 +1,84 @@ +<template> + <el-form :model="info" ref="genInfoForm"> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 6, offset: 6}" :md="12" :sm="24"> + <el-form-item > + <span slot="label">生成模板 + </span> + <el-tooltip content="树表没有分页,数据展示为树形表格" placement="top"> + <i class="el-icon-question"></i> + </el-tooltip> + <br> + <el-select v-model="info.tplCategory" disabled=""> + <el-option value="crud">单表(增删改查)</el-option> + <el-option value="tree">树表(增删改查)</el-option> + </el-select> + </el-form-item> + </el-col> + <el-col :lg="{span: 6, offset: 1}" :md="12" :sm="24"> + <el-form-item> + <span slot="label">生成包路径 + </span> + <el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top"> + <i class="el-icon-question"></i> + </el-tooltip> + <el-input v-model="info.packageName"/> + </el-form-item> + </el-col> + </el-row> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 6, offset: 6}" :md="12" :sm="24"> + <el-form-item> + <span slot="label">生成模块名 + </span> + <el-tooltip content="可理解为子系统名,例如 system" placement="top"> + <i class="el-icon-question"></i> + </el-tooltip> + <el-input v-model="info.moduleName"/> + </el-form-item> + </el-col> + <el-col :lg="{span: 6, offset: 1}" :md="12" :sm="24"> + <el-form-item> + <span slot="label">生成业务名 + </span> + <el-tooltip content="可理解为功能英文名,例如 user" placement="top"> + <i class="el-icon-question"></i> + </el-tooltip> + <el-input v-model="info.businessName"/> + </el-form-item> + </el-col> + </el-row> + <el-row class="form-row" :gutter="24"> + <el-col :lg="{span: 6, offset: 6}" :md="12" :sm="24"> + <el-form-item> + <span slot="label">生成功能名 + </span> + <el-tooltip content="用作类描述,例如 用户" placement="top"> + <i class="el-icon-question"></i> + </el-tooltip> + <el-input v-model="info.functionName"/> + </el-form-item> + </el-col> + </el-row> + </el-form> +</template> +<script> +export default { + name: 'BasicInfoForm', + props: { + info: { + type: Object, + default: null + } + }, + data () { + return { + visible:false, + mdl: {} + } + }, + created(){ + + } +} +</script> diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue index c0c06736a..87a564c77 100644 --- a/ruoyi-ui/src/views/tool/gen/index.vue +++ b/ruoyi-ui/src/views/tool/gen/index.vue @@ -1,5 +1,244 @@ -<template> - <div class="app-container"> - 代码生成 - </div> -</template> \ No newline at end of file +<template> + <div class="app-container"> + <el-form :model="queryParams" ref="queryForm" :inline="true" label-width="68px"> + <el-form-item label="表名称" prop="tableName"> + <el-input + v-model="queryParams.tableName" + placeholder="请输入表名称" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="表描述" prop="tableComment"> + <el-input + v-model="queryParams.tableComment" + placeholder="请输入表描述" + clearable + size="small" + @keyup.enter.native="handleQuery" + /> + </el-form-item> + <el-form-item label="创建时间"> + <el-date-picker + v-model="dateRange" + size="small" + style="width: 240px" + value-format="yyyy-MM-dd" + type="daterange" + range-separator="-" + start-placeholder="开始日期" + end-placeholder="结束日期" + ></el-date-picker> + </el-form-item> + <el-form-item> + <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button> + <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button> + </el-form-item> + </el-form> + + <el-row :gutter="10" class="mb8"> + <el-col :span="1.5"> + <el-button + type="primary" + icon="el-icon-download" + size="mini" + @click="handleBatchGenTable" + v-hasPermi="['system:post:add']" + >生成</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="warning" + icon="el-icon-upload" + size="mini" + @click="handleImport" + v-hasPermi="['system:post:add']" + >导入</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="success" + icon="el-icon-edit" + size="mini" + :disabled="single" + @click="handleEditTable" + v-hasPermi="['system:post:edit']" + >修改</el-button> + </el-col> + <el-col :span="1.5"> + <el-button + type="danger" + icon="el-icon-delete" + size="mini" + :disabled="multiple" + @click="handleDelete" + v-hasPermi="['system:post:remove']" + >删除</el-button> + </el-col> + </el-row> + + <el-table + :data="tableList" + style="width: 100% ;margin-top: 10px" + @selection-change="handleSelectionChange" + > + <el-table-column + type="selection" + width="30"></el-table-column> + <el-table-column label="序号" align="center" prop="tableId" width="50px"/> + <el-table-column label="表名称" align="center" prop="tableName" /> + <el-table-column label="表描述" align="center" prop="tableComment" /> + <el-table-column label="实体" align="center" prop="className" /> + <el-table-column label="创建时间" align="center" prop="createTime" /> + <el-table-column label="更新时间" align="center" prop="updateTime" /> + <el-table-column + label="操作" + align="center" + min-width="180px" + > + <template slot-scope="scope"> + <el-button type="text" size="small" icon="el-icon-view" @click="handlepreView(scope.row)">预览</el-button> + <el-button type="text" size="small" icon="el-icon-edit" @click="handleEditTable(scope.row)">编辑</el-button> + <el-button type="text" size="small" icon="el-icon-delete" @click="handleDelete(scope.row)">删除</el-button> + <el-button type="text" size="small" icon="el-icon-download"@click="handleGenTable(scope.row.tableName)">生成代码</el-button> + </template> + </el-table-column> + </el-table> + <pagination + v-show="total>0" + :total="total" + :page.sync="queryParams.pageNum" + :limit.sync="queryParams.pageSize" + @pagination="getList" + /> + <!-- 预览界面 --> + <el-dialog :title="title" :visible.sync="preDialog.open" width="900px" lock-scroll> + <el-tabs v-model="vm.activeName" type="card"> + <el-tab-pane :label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))" v-for="(value, key) in preDialog.preData" :key="key"> + <pre>{{ value }}</pre> + </el-tab-pane> + </el-tabs> + </el-dialog> + <import-dailog ref="import" @ok="handleQuery"/> + </div> +</template> + +<script> +import { listTable,listdbTable,importTable,previewTable,removeTable } from '@/api/tool/gen' +import importDailog from './dailog/importDailog'; +import { downLoadZip } from '@/utils/zipdownload' +export default { + components: { importDailog }, + data() { + return { + // 遮罩层 + loading: true, + // 选中数组 + ids: [], + tableNames: [], + // 非单个禁用 + single: true, + // 非多个禁用 + multiple: true, + // 总条数 + total: 0, + // 岗位表格数据 + tableList: [], + // 弹出层标题 + title: "", + // 是否显示弹出层 + open: false, + // 状态数据字典 + statusOptions: [], + // 日期范围 + dateRange: '', + // 查询参数 + queryParams: { + pageNum: 1, + pageSize: 10, + tableName: undefined, + tableComment: undefined + }, + // 表单参数 + form: {}, + vm:{ + activeName:"0" + }, + preDialog:{ + open: false, + preData:{} + }, + }; + }, + created() { + this.getList() + }, + methods: { + /** 查询岗位列表 */ + getList() { + this.loading = true; + listTable(this.addDateRange(this.queryParams, this.dateRange)).then(response => { + this.tableList = response.rows; + this.total = response.total; + this.loading = false; + }); + }, + /** 搜索按钮操作 */ + handleQuery() { + console.log("handleQuery") + this.queryParams.pageNum = 1; + this.getList(); + }, + handleGenTable(tabelname){ + downLoadZip('tool/gen/genCode/'+tabelname, 'ruoyi') + }, + handleBatchGenTable(tabelname){ + downLoadZip('tool/gen/batchGenCode?tables='+this.tableNames.join(','), 'ruoyi') + }, + handleImport(){ + this.$refs.import.show() + }, + /** 重置按钮操作 */ + resetQuery() { + this.dateRange = []; + this.resetForm("queryForm"); + this.handleQuery(); + }, + handlepreView(row){ + previewTable(row.tableId).then(response => { + this.title="代码预览" + this.preDialog.preData = response.data + this.preDialog.open=true + }) + }, + // 多选框选中数据 + handleSelectionChange(selection) { + this.ids = selection.map(item => item.tableId) + this.tableNames = selection.map(item => item.tableName) + this.single = selection.length!=1 + this.multiple = !selection.length + }, + /** 修改按钮操作 */ + handleEditTable(row) { + const tableId = row.tableId || this.ids[0] + console.log(tableId) + this.$router.push({ path: '/gen/edit',query: { tableId: tableId } }); + }, + /** 删除按钮操作 */ + handleDelete(row) { + const tableIds = row.tableId || this.ids.join(','); + this.$confirm('是否确认删除表编号为"' + tableIds + '"的数据项?', "警告", { + confirmButtonText: "确定", + cancelButtonText: "取消", + type: "warning" + }).then(function() { + return removeTable({ids:tableIds}); + }).then(() => { + this.getList(); + this.msgSuccess("删除成功"); + }).catch(function() {}); + } + } +}; +</script> diff --git a/ruoyi/pom.xml b/ruoyi/pom.xml index f9f6b9ae4..f04aa1491 100644 --- a/ruoyi/pom.xml +++ b/ruoyi/pom.xml @@ -34,6 +34,7 @@ <swagger.version>2.9.2</swagger.version> <poi.version>3.17</poi.version> <oshi.version>3.9.1</oshi.version> + <velocity.version>1.7</velocity.version> </properties> <dependencies> @@ -231,6 +232,13 @@ <artifactId>poi-ooxml</artifactId> <version>${poi.version}</version> </dependency> + + <!--velocity代码生成使用模板 --> + <dependency> + <groupId>org.apache.velocity</groupId> + <artifactId>velocity</artifactId> + <version>${velocity.version}</version> + </dependency> </dependencies> diff --git a/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java new file mode 100644 index 000000000..068969be7 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/constant/GenConstants.java @@ -0,0 +1,94 @@ +package com.ruoyi.common.constant; + +/** + * 代码生成通用常量 + * + * @author ruoyi + */ +public class GenConstants +{ + /** 单表(增删改查) */ + public static final String TPL_CRUD = "crud"; + + /** 树表(增删改查) */ + public static final String TPL_TREE = "tree"; + + /** 树编码字段 */ + public static final String TREE_CODE = "treeCode"; + + /** 树父编码字段 */ + public static final String TREE_PARENT_CODE = "treeParentCode"; + + /** 树名称字段 */ + public static final String TREE_NAME = "treeName"; + + /** 数据库字符串类型 */ + public static final String[] COLUMNTYPE_STR = { "char", "varchar", "narchar", "varchar2", "tinytext", "text", + "mediumtext", "longtext" }; + + /** 数据库时间类型 */ + public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" }; + + /** 数据库数字类型 */ + public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer", + "bigint", "float", "float", "double", "decimal" }; + + /** 页面不需要编辑字段 */ + public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" }; + + /** 页面不需要显示的列表字段 */ + public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time" }; + + /** 页面不需要查询字段 */ + public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by", + "update_time", "remark" }; + + /** Entity基类字段 */ + public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" }; + + /** Tree基类字段 */ + public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors" }; + + /** 文本框 */ + public static final String HTML_INPUT = "input"; + + /** 文本域 */ + public static final String HTML_TEXTAREA = "textarea"; + + /** 下拉框 */ + public static final String HTML_SELECT = "select"; + + /** 单选框 */ + public static final String HTML_RADIO = "radio"; + + /** 复选框 */ + public static final String HTML_CHECKBOX = "checkbox"; + + /** 日期控件 */ + public static final String HTML_DATETIME = "datetime"; + + /** 字符串类型 */ + public static final String TYPE_STRING = "String"; + + /** 整型 */ + public static final String TYPE_INTEGER = "Integer"; + + /** 长整型 */ + public static final String TYPE_LONG = "Long"; + + /** 浮点型 */ + public static final String TYPE_DOUBLE = "Double"; + + /** 高精度计算类型 */ + public static final String TYPE_BIGDECIMAL = "BigDecimal"; + + /** 时间类型 */ + public static final String TYPE_DATE = "Date"; + + /** 模糊查询 */ + public static final String QUERY_LIKE = "LIKE"; + + /** 需要 */ + public static final String REQUIRE = "1"; +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/text/CharsetKit.java b/ruoyi/src/main/java/com/ruoyi/common/utils/text/CharsetKit.java new file mode 100644 index 000000000..f273cf758 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/text/CharsetKit.java @@ -0,0 +1,87 @@ +package com.ruoyi.common.utils.text; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import com.ruoyi.common.utils.StringUtils; + +/** + * 字符集工具类 + * + * @author ruoyi + * + */ +public class CharsetKit +{ + /** ISO-8859-1 */ + public static final String ISO_8859_1 = "ISO-8859-1"; + /** UTF-8 */ + public static final String UTF_8 = "UTF-8"; + /** GBK */ + public static final String GBK = "GBK"; + + /** ISO-8859-1 */ + public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1); + /** UTF-8 */ + public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8); + /** GBK */ + public static final Charset CHARSET_GBK = Charset.forName(GBK); + + /** + * 转换为Charset对象 + * + * @param charset 字符集,为空则返回默认字符集 + * @return Charset + */ + public static Charset charset(String charset) + { + return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, String srcCharset, String destCharset) + { + return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset)); + } + + /** + * 转换字符串的字符集编码 + * + * @param source 字符串 + * @param srcCharset 源字符集,默认ISO-8859-1 + * @param destCharset 目标字符集,默认UTF-8 + * @return 转换后的字符集 + */ + public static String convert(String source, Charset srcCharset, Charset destCharset) + { + if (null == srcCharset) + { + srcCharset = StandardCharsets.ISO_8859_1; + } + + if (null == destCharset) + { + srcCharset = StandardCharsets.UTF_8; + } + + if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset)) + { + return source; + } + return new String(source.getBytes(srcCharset), destCharset); + } + + /** + * @return 系统字符集编码 + */ + public static String systemCharset() + { + return Charset.defaultCharset().name(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/text/Convert.java b/ruoyi/src/main/java/com/ruoyi/common/utils/text/Convert.java new file mode 100644 index 000000000..a9e2f2188 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/text/Convert.java @@ -0,0 +1,999 @@ +package com.ruoyi.common.utils.text; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.nio.ByteBuffer; +import java.nio.charset.Charset; +import java.text.NumberFormat; +import java.util.Set; +import com.ruoyi.common.utils.StringUtils; + +/** + * 类型转换器 + * + * @author ruoyi + */ +public class Convert +{ + /** + * 转换为字符串<br> + * 如果给定的值为null,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static String toStr(Object value, String defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof String) + { + return (String) value; + } + return value.toString(); + } + + /** + * 转换为字符串<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static String toStr(Object value) + { + return toStr(value, null); + } + + /** + * 转换为字符<br> + * 如果给定的值为null,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Character toChar(Object value, Character defaultValue) + { + if (null == value) + { + return defaultValue; + } + if (value instanceof Character) + { + return (Character) value; + } + + final String valueStr = toStr(value, null); + return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0); + } + + /** + * 转换为字符<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Character toChar(Object value) + { + return toChar(value, null); + } + + /** + * 转换为byte<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Byte toByte(Object value, Byte defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Byte) + { + return (Byte) value; + } + if (value instanceof Number) + { + return ((Number) value).byteValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Byte.parseByte(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为byte<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Byte toByte(Object value) + { + return toByte(value, null); + } + + /** + * 转换为Short<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Short toShort(Object value, Short defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Short) + { + return (Short) value; + } + if (value instanceof Number) + { + return ((Number) value).shortValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Short.parseShort(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Short<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Short toShort(Object value) + { + return toShort(value, null); + } + + /** + * 转换为Number<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Number toNumber(Object value, Number defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Number) + { + return (Number) value; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return NumberFormat.getInstance().parse(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Number<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Number toNumber(Object value) + { + return toNumber(value, null); + } + + /** + * 转换为int<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Integer toInt(Object value, Integer defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Integer) + { + return (Integer) value; + } + if (value instanceof Number) + { + return ((Number) value).intValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Integer.parseInt(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为int<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Integer toInt(Object value) + { + return toInt(value, null); + } + + /** + * 转换为Integer数组<br> + * + * @param str 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String str) + { + return toIntArray(",", str); + } + + /** + * 转换为Long数组<br> + * + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String str) + { + return toLongArray(",", str); + } + + /** + * 转换为Integer数组<br> + * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static Integer[] toIntArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Integer[] {}; + } + String[] arr = str.split(split); + final Integer[] ints = new Integer[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Integer v = toInt(arr[i], 0); + ints[i] = v; + } + return ints; + } + + /** + * 转换为Long数组<br> + * + * @param split 分隔符 + * @param str 被转换的值 + * @return 结果 + */ + public static Long[] toLongArray(String split, String str) + { + if (StringUtils.isEmpty(str)) + { + return new Long[] {}; + } + String[] arr = str.split(split); + final Long[] longs = new Long[arr.length]; + for (int i = 0; i < arr.length; i++) + { + final Long v = toLong(arr[i], null); + longs[i] = v; + } + return longs; + } + + /** + * 转换为String数组<br> + * + * @param str 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String str) + { + return toStrArray(",", str); + } + + /** + * 转换为String数组<br> + * + * @param split 分隔符 + * @param split 被转换的值 + * @return 结果 + */ + public static String[] toStrArray(String split, String str) + { + return str.split(split); + } + + /** + * 转换为long<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Long toLong(Object value, Long defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Long) + { + return (Long) value; + } + if (value instanceof Number) + { + return ((Number) value).longValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).longValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为long<br> + * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Long toLong(Object value) + { + return toLong(value, null); + } + + /** + * 转换为double<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Double toDouble(Object value, Double defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Double) + { + return (Double) value; + } + if (value instanceof Number) + { + return ((Number) value).doubleValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + // 支持科学计数法 + return new BigDecimal(valueStr.trim()).doubleValue(); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为double<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Double toDouble(Object value) + { + return toDouble(value, null); + } + + /** + * 转换为Float<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Float toFloat(Object value, Float defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Float) + { + return (Float) value; + } + if (value instanceof Number) + { + return ((Number) value).floatValue(); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Float.parseFloat(valueStr.trim()); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Float<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Float toFloat(Object value) + { + return toFloat(value, null); + } + + /** + * 转换为boolean<br> + * String支持的值为:true、false、yes、ok、no,1,0 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static Boolean toBool(Object value, Boolean defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof Boolean) + { + return (Boolean) value; + } + String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + valueStr = valueStr.trim().toLowerCase(); + switch (valueStr) + { + case "true": + return true; + case "false": + return false; + case "yes": + return true; + case "ok": + return true; + case "no": + return false; + case "1": + return true; + case "0": + return false; + default: + return defaultValue; + } + } + + /** + * 转换为boolean<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static Boolean toBool(Object value) + { + return toBool(value, null); + } + + /** + * 转换为Enum对象<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * + * @param clazz Enum的Class + * @param value 值 + * @param defaultValue 默认值 + * @return Enum + */ + public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (clazz.isAssignableFrom(value.getClass())) + { + @SuppressWarnings("unchecked") + E myE = (E) value; + return myE; + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return Enum.valueOf(clazz, valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为Enum对象<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * + * @param clazz Enum的Class + * @param value 值 + * @return Enum + */ + public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value) + { + return toEnum(clazz, value, null); + } + + /** + * 转换为BigInteger<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value, BigInteger defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigInteger) + { + return (BigInteger) value; + } + if (value instanceof Long) + { + return BigInteger.valueOf((Long) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigInteger(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigInteger<br> + * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigInteger toBigInteger(Object value) + { + return toBigInteger(value, null); + } + + /** + * 转换为BigDecimal<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @param defaultValue 转换错误时的默认值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue) + { + if (value == null) + { + return defaultValue; + } + if (value instanceof BigDecimal) + { + return (BigDecimal) value; + } + if (value instanceof Long) + { + return new BigDecimal((Long) value); + } + if (value instanceof Double) + { + return new BigDecimal((Double) value); + } + if (value instanceof Integer) + { + return new BigDecimal((Integer) value); + } + final String valueStr = toStr(value, null); + if (StringUtils.isEmpty(valueStr)) + { + return defaultValue; + } + try + { + return new BigDecimal(valueStr); + } + catch (Exception e) + { + return defaultValue; + } + } + + /** + * 转换为BigDecimal<br> + * 如果给定的值为空,或者转换失败,返回默认值<br> + * 转换失败不会报错 + * + * @param value 被转换的值 + * @return 结果 + */ + public static BigDecimal toBigDecimal(Object value) + { + return toBigDecimal(value, null); + } + + /** + * 将对象转为字符串<br> + * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @return 字符串 + */ + public static String utf8Str(Object obj) + { + return str(obj, CharsetKit.CHARSET_UTF_8); + } + + /** + * 将对象转为字符串<br> + * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charsetName 字符集 + * @return 字符串 + */ + public static String str(Object obj, String charsetName) + { + return str(obj, Charset.forName(charsetName)); + } + + /** + * 将对象转为字符串<br> + * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法 + * + * @param obj 对象 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(Object obj, Charset charset) + { + if (null == obj) + { + return null; + } + + if (obj instanceof String) + { + return (String) obj; + } + else if (obj instanceof byte[] || obj instanceof Byte[]) + { + return str((Byte[]) obj, charset); + } + else if (obj instanceof ByteBuffer) + { + return str((ByteBuffer) obj, charset); + } + return obj.toString(); + } + + /** + * 将byte数组转为字符串 + * + * @param bytes byte数组 + * @param charset 字符集 + * @return 字符串 + */ + public static String str(byte[] bytes, String charset) + { + return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset)); + } + + /** + * 解码字节码 + * + * @param data 字符串 + * @param charset 字符集,如果此字段为空,则解码的结果取决于平台 + * @return 解码后的字符串 + */ + public static String str(byte[] data, Charset charset) + { + if (data == null) + { + return null; + } + + if (null == charset) + { + return new String(data); + } + return new String(data, charset); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, String charset) + { + if (data == null) + { + return null; + } + + return str(data, Charset.forName(charset)); + } + + /** + * 将编码的byteBuffer数据转换为字符串 + * + * @param data 数据 + * @param charset 字符集,如果为空使用当前系统字符集 + * @return 字符串 + */ + public static String str(ByteBuffer data, Charset charset) + { + if (null == charset) + { + charset = Charset.defaultCharset(); + } + return charset.decode(data).toString(); + } + + // ----------------------------------------------------------------------- 全角半角转换 + /** + * 半角转全角 + * + * @param input String. + * @return 全角字符串. + */ + public static String toSBC(String input) + { + return toSBC(input, null); + } + + /** + * 半角转全角 + * + * @param input String + * @param notConvertSet 不替换的字符集合 + * @return 全角字符串. + */ + public static String toSBC(String input, Set<Character> notConvertSet) + { + char c[] = input.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == ' ') + { + c[i] = '\u3000'; + } + else if (c[i] < '\177') + { + c[i] = (char) (c[i] + 65248); + + } + } + return new String(c); + } + + /** + * 全角转半角 + * + * @param input String. + * @return 半角字符串 + */ + public static String toDBC(String input) + { + return toDBC(input, null); + } + + /** + * 替换全角为半角 + * + * @param text 文本 + * @param notConvertSet 不替换的字符集合 + * @return 替换后的字符 + */ + public static String toDBC(String text, Set<Character> notConvertSet) + { + char c[] = text.toCharArray(); + for (int i = 0; i < c.length; i++) + { + if (null != notConvertSet && notConvertSet.contains(c[i])) + { + // 跳过不替换的字符 + continue; + } + + if (c[i] == '\u3000') + { + c[i] = ' '; + } + else if (c[i] > '\uFF00' && c[i] < '\uFF5F') + { + c[i] = (char) (c[i] - 65248); + } + } + String returnString = new String(c); + + return returnString; + } + + /** + * 数字金额大写转换 先写个完整的然后将如零拾替换成零 + * + * @param n 数字 + * @return 中文大写数字 + */ + public static String digitUppercase(double n) + { + String[] fraction = { "角", "分" }; + String[] digit = { "零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖" }; + String[][] unit = { { "元", "万", "亿" }, { "", "拾", "佰", "仟" } }; + + String head = n < 0 ? "负" : ""; + n = Math.abs(n); + + String s = ""; + for (int i = 0; i < fraction.length; i++) + { + s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(零.)+", ""); + } + if (s.length() < 1) + { + s = "整"; + } + int integerPart = (int) Math.floor(n); + + for (int i = 0; i < unit[0].length && integerPart > 0; i++) + { + String p = ""; + for (int j = 0; j < unit[1].length && n > 0; j++) + { + p = digit[integerPart % 10] + unit[1][j] + p; + integerPart = integerPart / 10; + } + s = p.replaceAll("(零.)*零$", "").replaceAll("^$", "零") + unit[0][i] + s; + } + return head + s.replaceAll("(零.)*零元", "元").replaceFirst("(零.)+", "").replaceAll("(零.)+", "零").replaceAll("^整$", "零元整"); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/text/StrFormatter.java b/ruoyi/src/main/java/com/ruoyi/common/utils/text/StrFormatter.java new file mode 100644 index 000000000..d376bc5b2 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/common/utils/text/StrFormatter.java @@ -0,0 +1,93 @@ +package com.ruoyi.common.utils.text; + +import com.ruoyi.common.utils.StringUtils; + +/** + * 字符串格式化 + * + * @author ruoyi + */ +public class StrFormatter +{ + public static final String EMPTY_JSON = "{}"; + public static final char C_BACKSLASH = '\\'; + public static final char C_DELIM_START = '{'; + public static final char C_DELIM_END = '}'; + + /** + * 格式化字符串<br> + * 此方法只是简单将占位符 {} 按照顺序替换为参数<br> + * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br> + * 例:<br> + * 通常使用:format("this is {} for {}", "a", "b") -> this is a for b<br> + * 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a<br> + * 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br> + * + * @param strPattern 字符串模板 + * @param argArray 参数列表 + * @return 结果 + */ + public static String format(final String strPattern, final Object... argArray) + { + if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray)) + { + return strPattern; + } + final int strPatternLength = strPattern.length(); + + // 初始化定义好的长度以获得更好的性能 + StringBuilder sbuf = new StringBuilder(strPatternLength + 50); + + int handledPosition = 0; + int delimIndex;// 占位符所在位置 + for (int argIndex = 0; argIndex < argArray.length; argIndex++) + { + delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition); + if (delimIndex == -1) + { + if (handledPosition == 0) + { + return strPattern; + } + else + { // 字符串模板剩余部分不再包含占位符,加入剩余部分后返回结果 + sbuf.append(strPattern, handledPosition, strPatternLength); + return sbuf.toString(); + } + } + else + { + if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH) + { + if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH) + { + // 转义符之前还有一个转义符,占位符依旧有效 + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + else + { + // 占位符被转义 + argIndex--; + sbuf.append(strPattern, handledPosition, delimIndex - 1); + sbuf.append(C_DELIM_START); + handledPosition = delimIndex + 1; + } + } + else + { + // 正常占位符 + sbuf.append(strPattern, handledPosition, delimIndex); + sbuf.append(Convert.utf8Str(argArray[argIndex])); + handledPosition = delimIndex + 2; + } + } + } + // append the characters following the last {} pair. + // 加入最后一个占位符后所有的字符 + sbuf.append(strPattern, handledPosition, strPattern.length()); + + return sbuf.toString(); + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/GenConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/GenConfig.java new file mode 100644 index 000000000..a74e2c38e --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/framework/config/GenConfig.java @@ -0,0 +1,66 @@ +package com.ruoyi.framework.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 读取代码生成相关配置 + * + * @author ruoyi + */ +@Component +@ConfigurationProperties(prefix = "gen") +public class GenConfig +{ + /** 作者 */ + public static String author; + + /** 生成包路径 */ + public static String packageName; + + /** 自动去除表前缀,默认是true */ + public static boolean autoRemovePre; + + /** 表前缀(类名不会包含表前缀) */ + public static String tablePrefix; + + public static String getAuthor() + { + return author; + } + + public void setAuthor(String author) + { + GenConfig.author = author; + } + + public static String getPackageName() + { + return packageName; + } + + public void setPackageName(String packageName) + { + GenConfig.packageName = packageName; + } + + public static boolean getAutoRemovePre() + { + return autoRemovePre; + } + + public void setAutoRemovePre(boolean autoRemovePre) + { + GenConfig.autoRemovePre = autoRemovePre; + } + + public static String getTablePrefix() + { + return tablePrefix; + } + + public void setTablePrefix(String tablePrefix) + { + GenConfig.tablePrefix = tablePrefix; + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java new file mode 100644 index 000000000..1b8d9699e --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/controller/GenController.java @@ -0,0 +1,197 @@ +package com.ruoyi.project.tool.gen.controller; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.stereotype.Controller; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import com.ruoyi.common.utils.text.Convert; +import com.ruoyi.framework.aspectj.lang.annotation.Log; +import com.ruoyi.framework.aspectj.lang.enums.BusinessType; +import com.ruoyi.framework.web.controller.BaseController; +import com.ruoyi.framework.web.domain.AjaxResult; +import com.ruoyi.framework.web.page.TableDataInfo; +import com.ruoyi.project.tool.gen.domain.GenTable; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; +import com.ruoyi.project.tool.gen.service.IGenTableColumnService; +import com.ruoyi.project.tool.gen.service.IGenTableService; + +/** + * 代码生成 操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/tool/gen") +public class GenController extends BaseController +{ + + @Autowired + private IGenTableService genTableService; + + @Autowired + private IGenTableColumnService genTableColumnService; + + + /** + * 修改代码生成业务 + */ + @GetMapping("/edit") + @ResponseBody + public AjaxResult edit(GenTableColumn genTableColumn) + { + GenTable table = genTableService.selectGenTableById(genTableColumn.getTableId()); + List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn); + Map<String, Object> map=new HashMap<String, Object>(); + map.put("info", table); + map.put("rows",list); + return AjaxResult.success(map); + } + + /** + * 查询代码生成列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @PostMapping("/list") + @ResponseBody + public TableDataInfo genList(GenTable genTable) + { + startPage(); + List<GenTable> list = genTableService.selectGenTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据库列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @PostMapping("/db/list") + @ResponseBody + public TableDataInfo dataList(GenTable genTable) + { + startPage(); + List<GenTable> list = genTableService.selectDbTableList(genTable); + return getDataTable(list); + } + + /** + * 查询数据表字段列表 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @PostMapping("/column/list") + @ResponseBody + public TableDataInfo columnList(GenTableColumn genTableColumn) + { + TableDataInfo dataInfo = new TableDataInfo(); + List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn); + dataInfo.setRows(list); + dataInfo.setTotal(list.size()); + return dataInfo; + } + + + /** + * 导入表结构(保存) + */ + @PreAuthorize("@ss.hasPermi('tool:gen:list')") + @Log(title = "代码生成", businessType = BusinessType.IMPORT) + @PostMapping("/importTable") + @ResponseBody + public AjaxResult importTableSave(String tables) + { + String[] tableNames = Convert.toStrArray(tables); + // 查询表信息 + List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames); + genTableService.importGenTable(tableList); + return AjaxResult.success(); + } + + + /** + * 修改保存代码生成业务 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:edit')") + @Log(title = "代码生成", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(@Validated @RequestBody GenTable genTable) + { + genTableService.validateEdit(genTable); + genTableService.updateGenTable(genTable); + return AjaxResult.success(); + } + + @PreAuthorize("@ss.hasPermi('tool:gen:remove')") + @Log(title = "代码生成", businessType = BusinessType.DELETE) + @PostMapping("/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + genTableService.deleteGenTableByIds(ids); + return AjaxResult.success(); + } + + /** + * 预览代码 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:preview')") + @GetMapping("/preview/{tableId}") + @ResponseBody + public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException + { + Map<String, String> dataMap = genTableService.previewCode(tableId); + return AjaxResult.success(dataMap); + } + + /** + * 生成代码 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:code')") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/genCode/{tableName}") + public void genCode(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException + { + byte[] data = genTableService.generatorCode(tableName); + genCode(response, data); + } + + /** + * 批量生成代码 + */ + @PreAuthorize("@ss.hasPermi('tool:gen:code')") + @Log(title = "代码生成", businessType = BusinessType.GENCODE) + @GetMapping("/batchGenCode") + @ResponseBody + public void batchGenCode(HttpServletResponse response, String tables) throws IOException + { + String[] tableNames = Convert.toStrArray(tables); + byte[] data = genTableService.generatorCode(tableNames); + genCode(response, data); + } + + /** + * 生成zip文件 + */ + private void genCode(HttpServletResponse response, byte[] data) throws IOException + { + response.reset(); + response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\""); + response.addHeader("Content-Length", "" + data.length); + response.setContentType("application/octet-stream; charset=UTF-8"); + IOUtils.write(data, response.getOutputStream()); + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java new file mode 100644 index 000000000..d608c82db --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTable.java @@ -0,0 +1,269 @@ +package com.ruoyi.project.tool.gen.domain; + +import java.util.List; +import javax.validation.Valid; +import javax.validation.constraints.NotBlank; +import com.ruoyi.common.constant.GenConstants; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.web.domain.BaseEntity; + +/** + * 业务表 gen_table + * + * @author ruoyi + */ +public class GenTable extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long tableId; + + /** 表名称 */ + @NotBlank(message = "表名称不能为空") + private String tableName; + + /** 表描述 */ + @NotBlank(message = "表描述不能为空") + private String tableComment; + + /** 实体类名称(首字母大写) */ + @NotBlank(message = "实体类名称不能为空") + private String className; + + /** 使用的模板(crud单表操作 tree树表操作) */ + private String tplCategory; + + /** 生成包路径 */ + @NotBlank(message = "生成包路径不能为空") + private String packageName; + + /** 生成模块名 */ + @NotBlank(message = "生成模块名不能为空") + private String moduleName; + + /** 生成业务名 */ + @NotBlank(message = "生成业务名不能为空") + private String businessName; + + /** 生成功能名 */ + @NotBlank(message = "生成功能名不能为空") + private String functionName; + + /** 生成作者 */ + @NotBlank(message = "作者不能为空") + private String functionAuthor; + + /** 主键信息 */ + private GenTableColumn pkColumn; + + /** 表列信息 */ + @Valid + private List<GenTableColumn> columns; + + /** 其它生成选项 */ + private String options; + + /** 树编码字段 */ + private String treeCode; + + /** 树父编码字段 */ + private String treeParentCode; + + /** 树名称字段 */ + private String treeName; + + public Long getTableId() + { + return tableId; + } + + public void setTableId(Long tableId) + { + this.tableId = tableId; + } + + public String getTableName() + { + return tableName; + } + + public void setTableName(String tableName) + { + this.tableName = tableName; + } + + public String getTableComment() + { + return tableComment; + } + + public void setTableComment(String tableComment) + { + this.tableComment = tableComment; + } + + public String getClassName() + { + return className; + } + + public void setClassName(String className) + { + this.className = className; + } + + public String getTplCategory() + { + return tplCategory; + } + + public void setTplCategory(String tplCategory) + { + this.tplCategory = tplCategory; + } + + public String getPackageName() + { + return packageName; + } + + public void setPackageName(String packageName) + { + this.packageName = packageName; + } + + public String getModuleName() + { + return moduleName; + } + + public void setModuleName(String moduleName) + { + this.moduleName = moduleName; + } + + public String getBusinessName() + { + return businessName; + } + + public void setBusinessName(String businessName) + { + this.businessName = businessName; + } + + public String getFunctionName() + { + return functionName; + } + + public void setFunctionName(String functionName) + { + this.functionName = functionName; + } + + public String getFunctionAuthor() + { + return functionAuthor; + } + + public void setFunctionAuthor(String functionAuthor) + { + this.functionAuthor = functionAuthor; + } + + public GenTableColumn getPkColumn() + { + return pkColumn; + } + + public void setPkColumn(GenTableColumn pkColumn) + { + this.pkColumn = pkColumn; + } + + public List<GenTableColumn> getColumns() + { + return columns; + } + + public void setColumns(List<GenTableColumn> columns) + { + this.columns = columns; + } + + public String getOptions() + { + return options; + } + + public void setOptions(String options) + { + this.options = options; + } + + public String getTreeCode() + { + return treeCode; + } + + public void setTreeCode(String treeCode) + { + this.treeCode = treeCode; + } + + public String getTreeParentCode() + { + return treeParentCode; + } + + public void setTreeParentCode(String treeParentCode) + { + this.treeParentCode = treeParentCode; + } + + public String getTreeName() + { + return treeName; + } + + public void setTreeName(String treeName) + { + this.treeName = treeName; + } + + public boolean isTree() + { + return isTree(this.tplCategory); + } + + public static boolean isTree(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory); + } + + public boolean isCrud() + { + return isCrud(this.tplCategory); + } + + public static boolean isCrud(String tplCategory) + { + return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory); + } + + public boolean isSuperColumn(String javaField) + { + return isSuperColumn(this.tplCategory, javaField); + } + + public static boolean isSuperColumn(String tplCategory, String javaField) + { + if (isTree(tplCategory)) + { + StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.TREE_ENTITY); + } + return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY); + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTableColumn.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTableColumn.java new file mode 100644 index 000000000..303575f55 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/domain/GenTableColumn.java @@ -0,0 +1,368 @@ +package com.ruoyi.project.tool.gen.domain; + +import javax.validation.constraints.NotBlank; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.web.domain.BaseEntity; + +/** + * 代码生成业务字段表 gen_table_column + * + * @author ruoyi + */ +public class GenTableColumn extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** 编号 */ + private Long columnId; + + /** 归属表编号 */ + private Long tableId; + + /** 列名称 */ + private String columnName; + + /** 列描述 */ + private String columnComment; + + /** 列类型 */ + private String columnType; + + /** JAVA类型 */ + private String javaType; + + /** JAVA字段名 */ + @NotBlank(message = "Java属性不能为空") + private String javaField; + + /** 是否主键(1是) */ + private String isPk; + + /** 是否自增(1是) */ + private String isIncrement; + + /** 是否必填(1是) */ + private String isRequired; + + /** 是否为插入字段(1是) */ + private String isInsert; + + /** 是否编辑字段(1是) */ + private String isEdit; + + /** 是否列表字段(1是) */ + private String isList; + + /** 是否查询字段(1是) */ + private String isQuery; + + /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */ + private String queryType; + + /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件) */ + private String htmlType; + + /** 字典类型 */ + private String dictType; + + /** 排序 */ + private Integer sort; + + public void setColumnId(Long columnId) + { + this.columnId = columnId; + } + + public Long getColumnId() + { + return columnId; + } + + public void setTableId(Long tableId) + { + this.tableId = tableId; + } + + public Long getTableId() + { + return tableId; + } + + public void setColumnName(String columnName) + { + this.columnName = columnName; + } + + public String getColumnName() + { + return columnName; + } + + public void setColumnComment(String columnComment) + { + this.columnComment = columnComment; + } + + public String getColumnComment() + { + return columnComment; + } + + public void setColumnType(String columnType) + { + this.columnType = columnType; + } + + public String getColumnType() + { + return columnType; + } + + public void setJavaType(String javaType) + { + this.javaType = javaType; + } + + public String getJavaType() + { + return javaType; + } + + public void setJavaField(String javaField) + { + this.javaField = javaField; + } + + public String getJavaField() + { + return javaField; + } + + public void setIsPk(String isPk) + { + this.isPk = isPk; + } + + public String getIsPk() + { + return isPk; + } + + public boolean isPk() + { + return isPk(this.isPk); + } + + public boolean isPk(String isPk) + { + return isPk != null && StringUtils.equals("1", isPk); + } + + public String getIsIncrement() + { + return isIncrement; + } + + public void setIsIncrement(String isIncrement) + { + this.isIncrement = isIncrement; + } + + public boolean isIncrement() + { + return isIncrement(this.isIncrement); + } + + public boolean isIncrement(String isIncrement) + { + return isIncrement != null && StringUtils.equals("1", isIncrement); + } + + public void setIsRequired(String isRequired) + { + this.isRequired = isRequired; + } + + public String getIsRequired() + { + return isRequired; + } + + public boolean isRequired() + { + return isRequired(this.isRequired); + } + + public boolean isRequired(String isRequired) + { + return isRequired != null && StringUtils.equals("1", isRequired); + } + + public void setIsInsert(String isInsert) + { + this.isInsert = isInsert; + } + + public String getIsInsert() + { + return isInsert; + } + + public boolean isInsert() + { + return isInsert(this.isInsert); + } + + public boolean isInsert(String isInsert) + { + return isInsert != null && StringUtils.equals("1", isInsert); + } + + public void setIsEdit(String isEdit) + { + this.isEdit = isEdit; + } + + public String getIsEdit() + { + return isEdit; + } + + public boolean isEdit() + { + return isInsert(this.isEdit); + } + + public boolean isEdit(String isEdit) + { + return isEdit != null && StringUtils.equals("1", isEdit); + } + + public void setIsList(String isList) + { + this.isList = isList; + } + + public String getIsList() + { + return isList; + } + + public boolean isList() + { + return isList(this.isList); + } + + public boolean isList(String isList) + { + return isList != null && StringUtils.equals("1", isList); + } + + public void setIsQuery(String isQuery) + { + this.isQuery = isQuery; + } + + public String getIsQuery() + { + return isQuery; + } + + public boolean isQuery() + { + return isQuery(this.isQuery); + } + + public boolean isQuery(String isQuery) + { + return isQuery != null && StringUtils.equals("1", isQuery); + } + + public void setQueryType(String queryType) + { + this.queryType = queryType; + } + + public String getQueryType() + { + return queryType; + } + + public String getHtmlType() + { + return htmlType; + } + + public void setHtmlType(String htmlType) + { + this.htmlType = htmlType; + } + + public void setDictType(String dictType) + { + this.dictType = dictType; + } + + public String getDictType() + { + return dictType; + } + + public void setSort(Integer sort) + { + this.sort = sort; + } + + public Integer getSort() + { + return sort; + } + + public boolean isSuperColumn() + { + return isSuperColumn(this.javaField); + } + + public static boolean isSuperColumn(String javaField) + { + return StringUtils.equalsAnyIgnoreCase(javaField, + // BaseEntity + "createBy", "createTime", "updateBy", "updateTime", "remark", + // TreeEntity + "parentName", "parentId", "orderNum", "ancestors"); + } + + public boolean isUsableColumn() + { + return isUsableColumn(javaField); + } + + public static boolean isUsableColumn(String javaField) + { + // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单 + return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum"); + } + + public String readConverterExp() + { + String remarks = StringUtils.substringBetween(this.columnComment, "(", ")"); + StringBuffer sb = new StringBuffer(); + if (StringUtils.isNotEmpty(remarks)) + { + for (String value : remarks.split(" ")) + { + if (StringUtils.isNotEmpty(value)) + { + Object startStr = value.subSequence(0, 1); + String endStr = value.substring(1); + sb.append("").append(startStr).append("=").append(endStr).append(","); + } + } + return sb.deleteCharAt(sb.length() - 1).toString(); + } + else + { + return this.columnComment; + } + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableColumnMapper.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableColumnMapper.java new file mode 100644 index 000000000..3e35cc4b1 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableColumnMapper.java @@ -0,0 +1,52 @@ +package com.ruoyi.project.tool.gen.mapper; + +import java.util.List; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; + +/** + * 业务字段 数据层 + * + * @author ruoyi + */ +public interface GenTableColumnMapper +{ + /** + * 根据表名称查询列信息 + * + * @param tableName 表名称 + * @return 列信息 + */ + public List<GenTableColumn> selectDbTableColumnsByName(String tableName); + + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 批量删除业务字段 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(Long[] ids); +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableMapper.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableMapper.java new file mode 100644 index 000000000..eae10e485 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/mapper/GenTableMapper.java @@ -0,0 +1,76 @@ +package com.ruoyi.project.tool.gen.mapper; + +import java.util.List; +import com.ruoyi.project.tool.gen.domain.GenTable; + +/** + * 业务 数据层 + * + * @author ruoyi + */ +public interface GenTableMapper +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List<GenTable> selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableListByNames(String[] tableNames); + + /** + * 查询表ID业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 查询表名称业务信息 + * + * @param tableName 表名称 + * @return 业务信息 + */ + public GenTable selectGenTableByName(String tableName); + + /** + * 新增业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int insertGenTable(GenTable genTable); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public int updateGenTable(GenTable genTable); + + /** + * 批量删除业务 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableByIds(Long[] ids); +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableColumnServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableColumnServiceImpl.java new file mode 100644 index 000000000..e9a664f20 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableColumnServiceImpl.java @@ -0,0 +1,68 @@ +package com.ruoyi.project.tool.gen.service; + +import java.util.List; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import com.ruoyi.common.utils.text.Convert; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; +import com.ruoyi.project.tool.gen.mapper.GenTableColumnMapper; + +/** + * 业务字段 服务层实现 + * + * @author ruoyi + */ +@Service +public class GenTableColumnServiceImpl implements IGenTableColumnService +{ + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + @Override + public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn) + { + return genTableColumnMapper.selectGenTableColumnListByTableId(genTableColumn); + } + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int insertGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.insertGenTableColumn(genTableColumn); + } + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + @Override + public int updateGenTableColumn(GenTableColumn genTableColumn) + { + return genTableColumnMapper.updateGenTableColumn(genTableColumn); + } + + /** + * 删除业务字段对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int deleteGenTableColumnByIds(String ids) + { + return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableServiceImpl.java new file mode 100644 index 000000000..516d12bdb --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/GenTableServiceImpl.java @@ -0,0 +1,341 @@ +package com.ruoyi.project.tool.gen.service; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.StringWriter; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.zip.ZipEntry; +import java.util.zip.ZipOutputStream; +import org.apache.commons.io.IOUtils; +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.Velocity; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.GenConstants; +import com.ruoyi.common.exception.CustomException; +import com.ruoyi.common.utils.SecurityUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.common.utils.text.Convert; +import com.ruoyi.project.tool.gen.domain.GenTable; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; +import com.ruoyi.project.tool.gen.mapper.GenTableColumnMapper; +import com.ruoyi.project.tool.gen.mapper.GenTableMapper; +import com.ruoyi.project.tool.gen.util.GenUtils; +import com.ruoyi.project.tool.gen.util.VelocityInitializer; +import com.ruoyi.project.tool.gen.util.VelocityUtils; + +/** + * 业务 服务层实现 + * + * @author ruoyi + */ +@Service +public class GenTableServiceImpl implements IGenTableService +{ + private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class); + + @Autowired + private GenTableMapper genTableMapper; + + @Autowired + private GenTableColumnMapper genTableColumnMapper; + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + @Override + public GenTable selectGenTableById(Long id) + { + GenTable genTable = genTableMapper.selectGenTableById(id); + setTableFromOptions(genTable); + return genTable; + } + + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + @Override + public List<GenTable> selectGenTableList(GenTable genTable) + { + return genTableMapper.selectGenTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableList(GenTable genTable) + { + return genTableMapper.selectDbTableList(genTable); + } + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableListByNames(String[] tableNames) + { + 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); + } + } + } + + /** + * 删除业务对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + @Transactional + public void deleteGenTableByIds(String ids) + { + genTableMapper.deleteGenTableByIds(Convert.toLongArray(ids)); + genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids)); + } + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + @Override + @Transactional + public void importGenTable(List<GenTable> tableList) + { + String operName = SecurityUtils.getUsername(); + for (GenTable table : tableList) + { + try + { + String tableName = table.getTableName(); + GenUtils.initTable(table, operName); + int row = genTableMapper.insertGenTable(table); + if (row > 0) + { + // 保存列信息 + List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName); + for (GenTableColumn column : genTableColumns) + { + GenUtils.initColumnField(column, table); + genTableColumnMapper.insertGenTableColumn(column); + } + } + } + catch (Exception e) + { + log.error("表名 " + table.getTableName() + " 导入失败:", e); + } + } + } + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + 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; + } + + /** + * 生成代码 + * + * @param tableName 表名称 + * @return 数据 + */ + @Override + public byte[] generatorCode(String tableName) + { + ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); + ZipOutputStream zip = new ZipOutputStream(outputStream); + generatorCode(tableName, zip); + IOUtils.closeQuietly(zip); + return outputStream.toByteArray(); + } + + /** + * 批量生成代码 + * + * @param tableNames 表数组 + * @return 数据 + */ + @Override + public byte[] generatorCode(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.closeEntry(); + } + catch (IOException e) + { + log.error("渲染模板失败,表名:" + table.getTableName(), e); + } + } + } + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + public void validateEdit(GenTable genTable) + { + if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) + { + String options = JSON.toJSONString(genTable.getParams()); + JSONObject paramsObj = JSONObject.parseObject(options); + if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE))) + { + throw new CustomException("树编码字段不能为空"); + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE))) + { + throw new CustomException("树父编码字段不能为空"); + } + else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME))) + { + throw new CustomException("树名称字段不能为空"); + } + } + } + + /** + * 设置主键列信息 + * + * @param genTable 业务表信息 + * @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); + genTable.setTreeCode(treeCode); + genTable.setTreeParentCode(treeParentCode); + genTable.setTreeName(treeName); + } + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableColumnService.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableColumnService.java new file mode 100644 index 000000000..444d9cc48 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableColumnService.java @@ -0,0 +1,44 @@ +package com.ruoyi.project.tool.gen.service; + +import java.util.List; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; + +/** + * 业务字段 服务层 + * + * @author ruoyi + */ +public interface IGenTableColumnService +{ + /** + * 查询业务字段列表 + * + * @param genTableColumn 业务字段信息 + * @return 业务字段集合 + */ + public List<GenTableColumn> selectGenTableColumnListByTableId(GenTableColumn genTableColumn); + + /** + * 新增业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int insertGenTableColumn(GenTableColumn genTableColumn); + + /** + * 修改业务字段 + * + * @param genTableColumn 业务字段信息 + * @return 结果 + */ + public int updateGenTableColumn(GenTableColumn genTableColumn); + + /** + * 删除业务字段信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int deleteGenTableColumnByIds(String ids); +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableService.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableService.java new file mode 100644 index 000000000..07424a84b --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/service/IGenTableService.java @@ -0,0 +1,99 @@ +package com.ruoyi.project.tool.gen.service; + +import java.util.List; +import java.util.Map; +import com.ruoyi.project.tool.gen.domain.GenTable; + +/** + * 业务 服务层 + * + * @author ruoyi + */ +public interface IGenTableService +{ + /** + * 查询业务列表 + * + * @param genTable 业务信息 + * @return 业务集合 + */ + public List<GenTable> selectGenTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param genTable 业务信息 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableList(GenTable genTable); + + /** + * 查询据库列表 + * + * @param tableNames 表名称组 + * @return 数据库表集合 + */ + public List<GenTable> selectDbTableListByNames(String[] tableNames); + + /** + * 查询业务信息 + * + * @param id 业务ID + * @return 业务信息 + */ + public GenTable selectGenTableById(Long id); + + /** + * 修改业务 + * + * @param genTable 业务信息 + * @return 结果 + */ + public void updateGenTable(GenTable genTable); + + /** + * 删除业务信息 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public void deleteGenTableByIds(String ids); + + /** + * 导入表结构 + * + * @param tableList 导入表列表 + */ + public void importGenTable(List<GenTable> tableList); + + /** + * 预览代码 + * + * @param tableId 表编号 + * @return 预览数据列表 + */ + public Map<String, String> previewCode(Long tableId); + + /** + * 生成代码 + * + * @param tableName 表名称 + * @return 数据 + */ + public byte[] generatorCode(String tableName); + + /** + * 批量生成代码 + * + * @param tableNames 表数组 + * @return 数据 + */ + public byte[] generatorCode(String[] tableNames); + + /** + * 修改保存参数校验 + * + * @param genTable 业务信息 + */ + public void validateEdit(GenTable genTable); +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/GenUtils.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/GenUtils.java new file mode 100644 index 000000000..590401322 --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/GenUtils.java @@ -0,0 +1,238 @@ +package com.ruoyi.project.tool.gen.util; + +import java.util.Arrays; +import org.apache.commons.lang3.RegExUtils; +import com.ruoyi.common.constant.GenConstants; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.config.GenConfig; +import com.ruoyi.project.tool.gen.domain.GenTable; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; + +/** + * 代码生成器 工具类 + * + * @author ruoyi + */ +public class GenUtils +{ + /** + * 初始化表信息 + */ + 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); + } + + /** + * 初始化列属性字段 + */ + 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)); + + if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType)) + { + column.setJavaType(GenConstants.TYPE_STRING); + // 字符串长度超过500设置为文本域 + Integer columnLength = getColumnLength(column.getColumnType()); + String htmlType = columnLength >= 500 ? 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); + + // 如果是浮点型 + String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ","); + if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) + { + column.setJavaType(GenConstants.TYPE_DOUBLE); + } + // 如果是整形 + else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) + { + column.setJavaType(GenConstants.TYPE_INTEGER); + } + // 长整形 + else + { + column.setJavaType(GenConstants.TYPE_LONG); + } + } + + // 插入字段(默认所有字段都需要插入) + column.setIsInsert(GenConstants.REQUIRE); + + // 编辑字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk()) + { + column.setIsEdit(GenConstants.REQUIRE); + } + // 列表字段 + if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk()) + { + column.setIsList(GenConstants.REQUIRE); + } + // 查询字段 + 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); + } + } + + /** + * 校验数组是否包含指定值 + * + * @param arr 数组 + * @param targetValue 值 + * @return 是否包含 + */ + public static boolean arraysContains(String[] arr, String targetValue) + { + return Arrays.asList(arr).contains(targetValue); + } + + /** + * 获取模块名 + * + * @param packageName 包名 + * @return 模块名 + */ + public static String getModuleName(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + int nameLength = packageName.length(); + String moduleName = StringUtils.substring(packageName, lastIndex + 1, nameLength); + return moduleName; + } + + /** + * 获取业务名 + * + * @param tableName 表名 + * @return 业务名 + */ + public static String getBusinessName(String tableName) + { + int lastIndex = tableName.lastIndexOf("_"); + int nameLength = tableName.length(); + String businessName = StringUtils.substring(tableName, lastIndex + 1, nameLength); + return businessName; + } + + /** + * 表名转换成Java类名 + * + * @param tableName 表名称 + * @return 类名 + */ + public static String convertClassName(String tableName) + { + boolean autoRemovePre = GenConfig.getAutoRemovePre(); + String tablePrefix = GenConfig.getTablePrefix(); + if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) + { + String[] searchList = StringUtils.split(tablePrefix, ","); + String[] replacementList = emptyList(searchList.length); + tableName = StringUtils.replaceEach(tableName, searchList, replacementList); + } + return StringUtils.convertToCamelCase(tableName); + } + + /** + * 关键字替换 + * + * @param name 需要被替换的名字 + * @return 替换后的名字 + */ + public static String replaceText(String text) + { + return RegExUtils.replaceAll(text, "(?:表|若依)", ""); + } + + /** + * 获取数据库类型字段 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static String getDbType(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + return StringUtils.substringBefore(columnType, "("); + } + else + { + return columnType; + } + } + + /** + * 获取字段长度 + * + * @param columnType 列类型 + * @return 截取后的列类型 + */ + public static Integer getColumnLength(String columnType) + { + if (StringUtils.indexOf(columnType, "(") > 0) + { + String length = StringUtils.substringBetween(columnType, "(", ")"); + return Integer.valueOf(length); + } + else + { + return 0; + } + } + + /** + * 获取空数组列表 + * + * @param length 长度 + * @return 数组信息 + */ + public static String[] emptyList(int length) + { + String[] values = new String[length]; + for (int i = 0; i < length; i++) + { + values[i] = StringUtils.EMPTY; + } + return values; + } +} \ No newline at end of file diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityInitializer.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityInitializer.java new file mode 100644 index 000000000..7f932fc3b --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityInitializer.java @@ -0,0 +1,35 @@ +package com.ruoyi.project.tool.gen.util; + +import java.util.Properties; +import org.apache.velocity.app.Velocity; +import com.ruoyi.common.constant.Constants; + +/** + * VelocityEngine工厂 + * + * @author RuoYi + */ +public class VelocityInitializer +{ + /** + * 初始化vm方法 + */ + public static void initVelocity() + { + Properties p = new Properties(); + try + { + // 加载classpath目录下的vm文件 + p.setProperty("file.resource.loader.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + // 定义字符集 + p.setProperty(Velocity.ENCODING_DEFAULT, Constants.UTF8); + p.setProperty(Velocity.OUTPUT_ENCODING, Constants.UTF8); + // 初始化Velocity引擎,指定配置Properties + Velocity.init(p); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java new file mode 100644 index 000000000..0375ec92a --- /dev/null +++ b/ruoyi/src/main/java/com/ruoyi/project/tool/gen/util/VelocityUtils.java @@ -0,0 +1,304 @@ +package com.ruoyi.project.tool.gen.util; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import org.apache.velocity.VelocityContext; +import com.alibaba.fastjson.JSONObject; +import com.ruoyi.common.constant.GenConstants; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.project.tool.gen.domain.GenTable; +import com.ruoyi.project.tool.gen.domain.GenTableColumn; + +public class VelocityUtils +{ + /** 项目空间路径 */ + private static final String PROJECT_PATH = "main/java"; + + /** mybatis空间路径 */ + private static final String MYBATIS_PATH = "main/resources/mybatis"; + + /** html空间路径 */ + private static final String TEMPLATES_PATH = "main/resources/templates"; + + /** + * 设置模板变量信息 + * + * @return 模板列表 + */ + public static VelocityContext prepareContext(GenTable genTable) + { + String moduleName = genTable.getModuleName(); + String businessName = genTable.getBusinessName(); + String packageName = genTable.getPackageName(); + String tplCategory = genTable.getTplCategory(); + String functionName = genTable.getFunctionName(); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("tplCategory", genTable.getTplCategory()); + velocityContext.put("tableName", genTable.getTableName()); + velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】"); + velocityContext.put("ClassName", genTable.getClassName()); + velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName())); + velocityContext.put("moduleName", genTable.getModuleName()); + velocityContext.put("businessName", genTable.getBusinessName()); + velocityContext.put("basePackage", getPackagePrefix(packageName)); + velocityContext.put("packageName", packageName); + velocityContext.put("author", genTable.getFunctionAuthor()); + velocityContext.put("datetime", DateUtils.getDate()); + velocityContext.put("pkColumn", genTable.getPkColumn()); + velocityContext.put("importList", getImportList(genTable.getColumns())); + velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName)); + velocityContext.put("columns", genTable.getColumns()); + velocityContext.put("table", genTable); + if (GenConstants.TPL_TREE.equals(tplCategory)) + { + setTreeVelocityContext(velocityContext, genTable); + } + return velocityContext; + } + + public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSONObject.parseObject(options); + String treeCode = getTreecode(paramsObj); + String treeParentCode = getTreeParentCode(paramsObj); + String treeName = getTreeName(paramsObj); + + context.put("treeCode", treeCode); + context.put("treeParentCode", treeParentCode); + context.put("treeName", treeName); + context.put("expandColumn", getExpandColumn(genTable)); + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME)); + } + } + + /** + * 获取模板信息 + * + * @return 模板列表 + */ + public static List<String> getTemplateList(String tplCategory) + { + List<String> templates = new ArrayList<String>(); + templates.add("vm/java/domain.java.vm"); + templates.add("vm/java/mapper.java.vm"); + templates.add("vm/java/service.java.vm"); + templates.add("vm/java/serviceImpl.java.vm"); + templates.add("vm/java/controller.java.vm"); + templates.add("vm/xml/mapper.xml.vm"); + if (GenConstants.TPL_CRUD.equals(tplCategory)) + { + templates.add("vm/html/list.html.vm"); + } + else if (GenConstants.TPL_TREE.equals(tplCategory)) + { + templates.add("vm/html/tree.html.vm"); + templates.add("vm/html/list-tree.html.vm"); + } + templates.add("vm/html/add.html.vm"); + templates.add("vm/html/edit.html.vm"); + templates.add("vm/sql/sql.vm"); + return templates; + } + + /** + * 获取文件名 + */ + public static String getFileName(String template, GenTable genTable) + { + // 文件名称 + String fileName = ""; + // 包路径 + String packageName = genTable.getPackageName(); + // 模块名 + String moduleName = genTable.getModuleName(); + // 大写类名 + String className = genTable.getClassName(); + // 业务名称 + String businessName = genTable.getBusinessName(); + + String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/"); + String mybatisPath = MYBATIS_PATH + "/" + moduleName; + String htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + businessName; + + if (template.contains("domain.java.vm")) + { + fileName = StringUtils.format("{}/{}/domain/{}.java", javaPath, businessName, className); + } + else if (template.contains("mapper.java.vm")) + { + fileName = StringUtils.format("{}/{}/mapper/{}Mapper.java", javaPath, businessName, className); + } + else if (template.contains("service.java.vm")) + { + fileName = StringUtils.format("{}/{}/service/I{}Service.java", javaPath, businessName, className); + } + else if (template.contains("serviceImpl.java.vm")) + { + fileName = StringUtils.format("{}/{}/service/impl/{}ServiceImpl.java", javaPath, businessName, className); + } + else if (template.contains("controller.java.vm")) + { + fileName = StringUtils.format("{}/{}/controller/{}Controller.java", javaPath, businessName, className); + } + else if (template.contains("mapper.xml.vm")) + { + fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className); + } + else if (template.contains("list.html.vm")) + { + fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); + } + else if (template.contains("list-tree.html.vm")) + { + fileName = StringUtils.format("{}/{}.html", htmlPath, businessName); + } + else if (template.contains("tree.html.vm")) + { + fileName = StringUtils.format("{}/tree.html", htmlPath); + } + else if (template.contains("add.html.vm")) + { + fileName = StringUtils.format("{}/add.html", htmlPath); + } + else if (template.contains("edit.html.vm")) + { + fileName = StringUtils.format("{}/edit.html", htmlPath); + } + else if (template.contains("sql.vm")) + { + fileName = businessName + "Menu.sql"; + } + return fileName; + } + + /** + * 获取包前缀 + * + * @param packageName 包名称 + * @return 包前缀名称 + */ + public static String getPackagePrefix(String packageName) + { + int lastIndex = packageName.lastIndexOf("."); + String basePackage = StringUtils.substring(packageName, 0, lastIndex); + return basePackage; + } + + /** + * 根据列类型获取导入包 + * + * @param column 列集合 + * @return 返回需要导入的包列表 + */ + public static HashSet<String> getImportList(List<GenTableColumn> columns) + { + HashSet<String> importList = new HashSet<String>(); + for (GenTableColumn column : columns) + { + if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) + { + importList.add("java.util.Date"); + } + else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) + { + importList.add("java.math.BigDecimal"); + } + } + return importList; + } + + /** + * 获取权限前缀 + * + * @param moduleName 模块名称 + * @param businessName 业务名称 + * @return 返回权限前缀 + */ + public static String getPermissionPrefix(String moduleName, String businessName) + { + return StringUtils.format("{}:{}", moduleName, businessName); + + } + + /** + * 获取树编码 + * + * @param options 生成其他选项 + * @return 树编码 + */ + public static String getTreecode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE)); + } + return ""; + } + + /** + * 获取树父编码 + * + * @param options 生成其他选项 + * @return 树父编码 + */ + public static String getTreeParentCode(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE)); + } + return ""; + } + + /** + * 获取树名称 + * + * @param options 生成其他选项 + * @return 树名称 + */ + public static String getTreeName(JSONObject paramsObj) + { + if (paramsObj.containsKey(GenConstants.TREE_NAME)) + { + return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME)); + } + return ""; + } + + /** + * 获取需要在哪一列上面显示展开按钮 + * + * @param genTable 业务表对象 + * @return 展开按钮列序号 + */ + public static int getExpandColumn(GenTable genTable) + { + String options = genTable.getOptions(); + JSONObject paramsObj = JSONObject.parseObject(options); + String treeName = paramsObj.getString(GenConstants.TREE_NAME); + int num = 0; + for (GenTableColumn column : genTable.getColumns()) + { + if (column.isList()) + { + num++; + String columnName = column.getColumnName(); + if (columnName.equals(treeName)) + { + break; + } + } + } + return num; + } +} \ No newline at end of file diff --git a/ruoyi/src/main/resources/application.yml b/ruoyi/src/main/resources/application.yml index a1f653dc8..2dc100db6 100644 --- a/ruoyi/src/main/resources/application.yml +++ b/ruoyi/src/main/resources/application.yml @@ -58,9 +58,9 @@ spring: # redis 配置 redis: # 地址 - host: localhost + host: 192.168.0.185 # 端口,默认为6379 - port: 6379 + port: 6380 # 连接超时时间 timeout: 10s lettuce: @@ -106,4 +106,18 @@ xss: # 排除链接(多个用逗号分隔) excludes: /system/notice/* # 匹配链接 - urlPatterns: /system/*,/monitor/*,/tool/* \ No newline at end of file + urlPatterns: /system/*,/monitor/*,/tool/* + + +# 代码生成 +gen: + # 作者 + author: ruoyi + # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool + packageName: com.ruoyi.system + # 自动去除表前缀,默认是false + autoRemovePre: false + # 表前缀(生成类名不会包含表前缀,多个用逗号分隔) + tablePrefix: sys_ + + \ No newline at end of file diff --git a/ruoyi/src/main/resources/mybatis/tool/GenTableColumnMapper.xml b/ruoyi/src/main/resources/mybatis/tool/GenTableColumnMapper.xml new file mode 100644 index 000000000..41d38d35d --- /dev/null +++ b/ruoyi/src/main/resources/mybatis/tool/GenTableColumnMapper.xml @@ -0,0 +1,120 @@ +<?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="com.ruoyi.project.tool.gen.mapper.GenTableColumnMapper"> + + <resultMap type="GenTableColumn" id="GenTableColumnResult"> + <id property="columnId" column="column_id" /> + <result property="tableId" column="table_id" /> + <result property="columnName" column="column_name" /> + <result property="columnComment" column="column_comment" /> + <result property="columnType" column="column_type" /> + <result property="javaType" column="java_type" /> + <result property="javaField" column="java_field" /> + <result property="isPk" column="is_pk" /> + <result property="isIncrement" column="is_increment" /> + <result property="isRequired" column="is_required" /> + <result property="isInsert" column="is_insert" /> + <result property="isEdit" column="is_edit" /> + <result property="isList" column="is_list" /> + <result property="isQuery" column="is_query" /> + <result property="queryType" column="query_type" /> + <result property="htmlType" column="html_type" /> + <result property="dictType" column="dict_type" /> + <result property="sort" column="sort" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectGenTableColumnVo"> + select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column + </sql> + + <select id="selectGenTableColumnListByTableId" parameterType="GenTableColumn" resultMap="GenTableColumnResult"> + <include refid="selectGenTableColumnVo"/> + where table_id = #{tableId} + order by sort + </select> + + <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult"> + select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else null 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 + </select> + + <insert id="insertGenTableColumn" parameterType="GenTableColumn" useGeneratedKeys="true" keyProperty="columnId"> + insert into gen_table_column ( + <if test="tableId != null and tableId != ''">table_id,</if> + <if test="columnName != null and columnName != ''">column_name,</if> + <if test="columnComment != null and columnComment != ''">column_comment,</if> + <if test="columnType != null and columnType != ''">column_type,</if> + <if test="javaType != null and javaType != ''">java_type,</if> + <if test="javaField != null and javaField != ''">java_field,</if> + <if test="isPk != null and isPk != ''">is_pk,</if> + <if test="isIncrement != null and isIncrement != ''">is_increment,</if> + <if test="isRequired != null and isRequired != ''">is_required,</if> + <if test="isInsert != null and isInsert != ''">is_insert,</if> + <if test="isEdit != null and isEdit != ''">is_edit,</if> + <if test="isList != null and isList != ''">is_list,</if> + <if test="isQuery != null and isQuery != ''">is_query,</if> + <if test="queryType != null and queryType != ''">query_type,</if> + <if test="htmlType != null and htmlType != ''">html_type,</if> + <if test="dictType != null and dictType != ''">dict_type,</if> + <if test="sort != null">sort,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="tableId != null and tableId != ''">#{tableId},</if> + <if test="columnName != null and columnName != ''">#{columnName},</if> + <if test="columnComment != null and columnComment != ''">#{columnComment},</if> + <if test="columnType != null and columnType != ''">#{columnType},</if> + <if test="javaType != null and javaType != ''">#{javaType},</if> + <if test="javaField != null and javaField != ''">#{javaField},</if> + <if test="isPk != null and isPk != ''">#{isPk},</if> + <if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if> + <if test="isRequired != null and isRequired != ''">#{isRequired},</if> + <if test="isInsert != null and isInsert != ''">#{isInsert},</if> + <if test="isEdit != null and isEdit != ''">#{isEdit},</if> + <if test="isList != null and isList != ''">#{isList},</if> + <if test="isQuery != null and isQuery != ''">#{isQuery},</if> + <if test="queryType != null and queryType != ''">#{queryType},</if> + <if test="htmlType != null and htmlType != ''">#{htmlType},</if> + <if test="dictType != null and dictType != ''">#{dictType},</if> + <if test="sort != null">#{sort},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateGenTableColumn" parameterType="GenTableColumn"> + update gen_table_column + <set> + column_comment = #{columnComment}, + java_type = #{javaType}, + java_field = #{javaField}, + is_insert = #{isInsert}, + is_edit = #{isEdit}, + is_list = #{isList}, + is_query = #{isQuery}, + is_required = #{isRequired}, + query_type = #{queryType}, + html_type = #{htmlType}, + dict_type = #{dictType}, + sort = #{sort}, + update_by = #{updateBy}, + update_time = sysdate() + </set> + where column_id = #{columnId} + </update> + + <delete id="deleteGenTableColumnByIds" parameterType="Long"> + delete from gen_table_column where table_id in + <foreach collection="array" item="tableId" open="(" separator="," close=")"> + #{tableId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi/src/main/resources/mybatis/tool/GenTableMapper.xml b/ruoyi/src/main/resources/mybatis/tool/GenTableMapper.xml new file mode 100644 index 000000000..3e41ba906 --- /dev/null +++ b/ruoyi/src/main/resources/mybatis/tool/GenTableMapper.xml @@ -0,0 +1,181 @@ +<?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="com.ruoyi.project.tool.gen.mapper.GenTableMapper"> + + <resultMap type="GenTable" id="GenTableResult"> + <id property="tableId" column="table_id" /> + <result property="tableName" column="table_name" /> + <result property="tableComment" column="table_comment" /> + <result property="className" column="class_name" /> + <result property="tplCategory" column="tpl_category" /> + <result property="packageName" column="package_name" /> + <result property="moduleName" column="module_name" /> + <result property="businessName" column="business_name" /> + <result property="functionName" column="function_name" /> + <result property="functionAuthor" column="function_author" /> + <result property="options" column="options" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + <result property="remark" column="remark" /> + <collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" /> + </resultMap> + + <resultMap type="GenTableColumn" id="GenTableColumnResult"> + <id property="columnId" column="column_id" /> + <result property="tableId" column="table_id" /> + <result property="columnName" column="column_name" /> + <result property="columnComment" column="column_comment" /> + <result property="columnType" column="column_type" /> + <result property="javaType" column="java_type" /> + <result property="javaField" column="java_field" /> + <result property="isPk" column="is_pk" /> + <result property="isIncrement" column="is_increment" /> + <result property="isRequired" column="is_required" /> + <result property="isInsert" column="is_insert" /> + <result property="isEdit" column="is_edit" /> + <result property="isList" column="is_list" /> + <result property="isQuery" column="is_query" /> + <result property="queryType" column="query_type" /> + <result property="htmlType" column="html_type" /> + <result property="dictType" column="dict_type" /> + <result property="sort" column="sort" /> + <result property="createBy" column="create_by" /> + <result property="createTime" column="create_time" /> + <result property="updateBy" column="update_by" /> + <result property="updateTime" column="update_time" /> + </resultMap> + + <sql id="selectGenTableVo"> + select table_id, table_name, table_comment, class_name, tpl_category, package_name, module_name, business_name, function_name, function_author, options, create_by, create_time, update_by, update_time, remark from gen_table + </sql> + + <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult"> + <include refid="selectGenTableVo"/> + <where> + <if test="tableName != null and tableName != ''"> + AND lower(table_name) like lower(concat('%', #{tableName}, '%')) + </if> + <if test="tableComment != null and tableComment != ''"> + AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </where> + </select> + + <select id="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_schema = (select database()) + AND table_name NOT LIKE 'qrtz_%' AND table_name NOT LIKE 'gen_%' + AND table_name NOT IN (select table_name from gen_table) + <if test="tableName != null and tableName != ''"> + AND lower(table_name) like lower(concat('%', #{tableName}, '%')) + </if> + <if test="tableComment != null and tableComment != ''"> + AND lower(table_comment) like lower(concat('%', #{tableComment}, '%')) + </if> + <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 --> + AND date_format(create_time,'%y%m%d') >= date_format(#{params.beginTime},'%y%m%d') + </if> + <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 --> + AND date_format(create_time,'%y%m%d') <= date_format(#{params.endTime},'%y%m%d') + </if> + </select> + + <select id="selectDbTableListByNames" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_name NOT LIKE 'qrtz_%' 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> + </select> + + <select id="selectTableByName" parameterType="String" resultMap="GenTableResult"> + select table_name, table_comment, create_time, update_time from information_schema.tables + where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database()) + and table_name = #{tableName} + </select> + + <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult"> + SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + where t.table_id = #{tableId} + </select> + + <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult"> + SELECT t.table_id, t.table_name, t.table_comment, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark, + c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort + FROM gen_table t + LEFT JOIN gen_table_column c ON t.table_id = c.table_id + where t.table_name = #{tableName} + </select> + + <insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId"> + insert into gen_table ( + <if test="tableName != null">table_name,</if> + <if test="tableComment != null and tableComment != ''">table_comment,</if> + <if test="className != null and className != ''">class_name,</if> + <if test="tplCategory != null and tplCategory != ''">tpl_category,</if> + <if test="packageName != null and packageName != ''">package_name,</if> + <if test="moduleName != null and moduleName != ''">module_name,</if> + <if test="businessName != null and businessName != ''">business_name,</if> + <if test="functionName != null and functionName != ''">function_name,</if> + <if test="functionAuthor != null and functionAuthor != ''">function_author,</if> + <if test="remark != null and remark != ''">remark,</if> + <if test="createBy != null and createBy != ''">create_by,</if> + create_time + )values( + <if test="tableName != null">#{tableName},</if> + <if test="tableComment != null and tableComment != ''">#{tableComment},</if> + <if test="className != null and className != ''">#{className},</if> + <if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if> + <if test="packageName != null and packageName != ''">#{packageName},</if> + <if test="moduleName != null and moduleName != ''">#{moduleName},</if> + <if test="businessName != null and businessName != ''">#{businessName},</if> + <if test="functionName != null and functionName != ''">#{functionName},</if> + <if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if> + <if test="remark != null and remark != ''">#{remark},</if> + <if test="createBy != null and createBy != ''">#{createBy},</if> + sysdate() + ) + </insert> + + <update id="updateGenTable" parameterType="GenTable"> + update gen_table + <set> + <if test="tableName != null">table_name = #{tableName},</if> + <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if> + <if test="className != null and className != ''">class_name = #{className},</if> + <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if> + <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if> + <if test="packageName != null and packageName != ''">package_name = #{packageName},</if> + <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if> + <if test="businessName != null and businessName != ''">business_name = #{businessName},</if> + <if test="functionName != null and functionName != ''">function_name = #{functionName},</if> + <if test="options != null and options != ''">options = #{options},</if> + <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if> + <if test="remark != null">remark = #{remark},</if> + update_time = sysdate() + </set> + where table_id = #{tableId} + </update> + + <delete id="deleteGenTableByIds" parameterType="Long"> + delete from gen_table where table_id in + <foreach collection="array" item="tableId" open="(" separator="," close=")"> + #{tableId} + </foreach> + </delete> + +</mapper> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/html/add.html.vm b/ruoyi/src/main/resources/vm/html/add.html.vm new file mode 100644 index 000000000..1817027f3 --- /dev/null +++ b/ruoyi/src/main/resources/vm/html/add.html.vm @@ -0,0 +1,159 @@ +<!DOCTYPE html> +<html lang="zh" xmlns:th="http://www.thymeleaf.org" > +<head> + <th:block th:include="include :: header('新增${functionName}')" /> +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + <th:block th:include="include :: datetimepicker-css" /> +#break +#end +#end +</head> +<body class="white-bg"> + <div class="wrapper wrapper-content animated fadeInRight ibox-content"> + <form class="form-horizontal m" id="form-${businessName}-add"> +#foreach($column in $columns) +#set($field=$column.javaField) +#if($column.insert && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($dictType=$column.dictType) +#if("" != $treeParentCode && $column.javaField == $treeParentCode) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="input-group"> +#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)}) +#set($treeId = "${className}?.${treeCode}") + <input id="treeId" name="${treeParentCode}" type="hidden" th:value="${${treeId}}"/> + <input class="form-control" type="text" onclick="select${BusinessName}Tree()" id="treeName" readonly="true" th:value="${${treeName}}"#if($column.required) required#end> + <span class="input-group-addon"><i class="fa fa-search"></i></span> + </div> + </div> + </div> +#elseif($column.htmlType == "input") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <input name="${field}" class="form-control" type="text"#if($column.required) required#end> + </div> + </div> +#elseif($column.htmlType == "select" && "" != $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <select name="${field}" class="form-control m-b" th:with="type=${@dict.getType('${dictType}')}"#if($column.required) required#end> + <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option> + </select> + </div> + </div> +#elseif($column.htmlType == "select" && $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <select name="${field}" class="form-control m-b"#if($column.required) required#end> + <option value="">所有</option> + </select> + <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 代码生成请选择字典属性</span> + </div> + </div> +#elseif($column.htmlType == "radio" && "" != $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="radio-box" th:each="dict : ${@dict.getType('${dictType}')}"> + <input type="radio" th:id="${'${field}_' + dict.dictCode}" name="${field}" th:value="${dict.dictValue}" th:checked="${dict.default}"#if($column.required) required#end> + <label th:for="${'${field}_' + dict.dictCode}" th:text="${dict.dictLabel}"></label> + </div> + </div> + </div> +#elseif($column.htmlType == "radio" && $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="radio-box"> + <input type="radio" name="${field}" value=""#if($column.required) required#end> + <label th:for="${field}" th:text="未知"></label> + </div> + <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 代码生成请选择字典属性</span> + </div> + </div> +#elseif($column.htmlType == "datetime") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="input-group date"> + <span class="input-group-addon"><i class="fa fa-calendar"></i></span> + <input name="${field}" class="form-control" placeholder="yyyy-MM-dd" type="text"#if($column.required) required#end> + </div> + </div> + </div> +#elseif($column.htmlType == "textarea") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <textarea name="${field}" class="form-control"#if($column.required) required#end></textarea> + </div> + </div> +#end +#end +#end +#end + </form> + </div> + <th:block th:include="include :: footer" /> +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + <th:block th:include="include :: datetimepicker-js" /> +#break +#end +#end + <script type="text/javascript"> + var prefix = ctx + "${moduleName}/${businessName}" + $("#form-${businessName}-add").validate({ + focusCleanup: true + }); + + function submitHandler() { + if ($.validate.form()) { + $.operate.save(prefix + "/add", $('#form-${businessName}-add').serialize()); + } + } +#foreach($column in $columns) +#if($column.insert && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + + $("input[name='$column.javaField']").datetimepicker({ + format: "yyyy-mm-dd", + minView: "month", + autoclose: true + }); +#end +#end +#if($table.tree) + + /*${functionName}-新增-选择父部门树*/ + function select${BusinessName}Tree() { + var options = { + title: '${functionName}选择', + width: "380", + url: prefix + "/select${BusinessName}Tree/" + $("#treeId").val(), + callBack: doSubmit + }; + $.modal.openOptions(options); + } + + function doSubmit(index, layero){ + var body = layer.getChildFrame('body', index); + $("#treeId").val(body.find('#treeId').val()); + $("#treeName").val(body.find('#treeName').val()); + layer.close(index); + } +#end + </script> +</body> +</html> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/html/edit.html.vm b/ruoyi/src/main/resources/vm/html/edit.html.vm new file mode 100644 index 000000000..e8edd670a --- /dev/null +++ b/ruoyi/src/main/resources/vm/html/edit.html.vm @@ -0,0 +1,159 @@ +<!DOCTYPE html> +<html lang="zh" xmlns:th="http://www.thymeleaf.org" > +<head> + <th:block th:include="include :: header('修改${functionName}')" /> +#foreach($column in $columns) +#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + <th:block th:include="include :: datetimepicker-css" /> +#break +#end +#end +</head> +<body class="white-bg"> + <div class="wrapper wrapper-content animated fadeInRight ibox-content"> + <form class="form-horizontal m" id="form-${businessName}-edit" th:object="${${className}}"> + <input name="${pkColumn.javaField}" th:field="*{${pkColumn.javaField}}" type="hidden"> +#foreach($column in $columns) +#if($column.edit && !$column.pk) +#if(($column.usableColumn) || (!$column.superColumn)) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#set($field=$column.javaField) +#set($dictType=$column.dictType) +#if("" != $treeParentCode && $column.javaField == $treeParentCode) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="input-group"> +#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)}) + <input id="treeId" name="${treeParentCode}" type="hidden" th:field="*{${treeParentCode}}" /> + <input class="form-control" type="text" onclick="select${BusinessName}Tree()" id="treeName" readonly="true" th:field="*{parentName}"#if($column.required) required#end> + <span class="input-group-addon"><i class="fa fa-search"></i></span> + </div> + </div> + </div> +#elseif($column.htmlType == "input") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <input name="${field}" th:field="*{${field}}" class="form-control" type="text"#if($column.required) required#end> + </div> + </div> +#elseif($column.htmlType == "select" && "" != $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <select name="${field}" class="form-control m-b" th:with="type=${@dict.getType('${dictType}')}"#if($column.required) required#end> + <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}" th:field="*{${field}}"></option> + </select> + </div> + </div> +#elseif($column.htmlType == "select" && $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <select name="${field}" class="form-control m-b"#if($column.required) required#end> + <option value="">所有</option> + </select> + <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 代码生成请选择字典属性</span> + </div> + </div> +#elseif($column.htmlType == "radio" && "" != $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="radio-box" th:each="dict : ${@dict.getType('${dictType}')}"> + <input type="radio" th:id="${'${field}_' + dict.dictCode}" name="${field}" th:value="${dict.dictValue}" th:field="*{${field}}"#if($column.required) required#end> + <label th:for="${'${field}_' + dict.dictCode}" th:text="${dict.dictLabel}"></label> + </div> + </div> + </div> +#elseif($column.htmlType == "radio" && $dictType) + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="radio-box"> + <input type="radio" name="${field}" value=""#if($column.required) required#end> + <label th:for="${field}" th:text="未知"></label> + </div> + <span class="help-block m-b-none"><i class="fa fa-info-circle"></i> 代码生成请选择字典属性</span> + </div> + </div> +#elseif($column.htmlType == "datetime") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <div class="input-group date"> + <span class="input-group-addon"><i class="fa fa-calendar"></i></span> + <input name="${field}" th:value="${#dates.format(${className}.${field}, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text"#if($column.required) required#end> + </div> + </div> + </div> +#elseif($column.htmlType == "textarea") + <div class="form-group"> + <label class="col-sm-3 control-label">${comment}:</label> + <div class="col-sm-8"> + <textarea name="${field}" class="form-control"#if($column.required) required#end>[[*{${field}}]]</textarea> + </div> + </div> +#end +#end +#end +#end + </form> + </div> + <th:block th:include="include :: footer" /> +#foreach($column in $columns) +#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + <th:block th:include="include :: datetimepicker-js" /> +#break +#end +#end + <script type="text/javascript"> + var prefix = ctx + "${moduleName}/${businessName}"; + $("#form-${businessName}-edit").validate({ + focusCleanup: true + }); + + function submitHandler() { + if ($.validate.form()) { + $.operate.save(prefix + "/edit", $('#form-${businessName}-edit').serialize()); + } + } +#foreach($column in $columns) +#if($column.edit && !$column.superColumn && !$column.pk && $column.htmlType == "datetime") + + $("input[name='$column.javaField']").datetimepicker({ + format: "yyyy-mm-dd", + minView: "month", + autoclose: true + }); +#end +#end +#if($table.tree) + + /*${functionName}-新增-选择父部门树*/ + function select${BusinessName}Tree() { + var options = { + title: '${functionName}选择', + width: "380", + url: prefix + "/select${BusinessName}Tree/" + $("#treeId").val(), + callBack: doSubmit + }; + $.modal.openOptions(options); + } + + function doSubmit(index, layero){ + var body = layer.getChildFrame('body', index); + $("#treeId").val(body.find('#treeId').val()); + $("#treeName").val(body.find('#treeName').val()); + layer.close(index); + } +#end + </script> +</body> +</html> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/html/list-tree.html.vm b/ruoyi/src/main/resources/vm/html/list-tree.html.vm new file mode 100644 index 000000000..2e05fe611 --- /dev/null +++ b/ruoyi/src/main/resources/vm/html/list-tree.html.vm @@ -0,0 +1,150 @@ +<!DOCTYPE html> +<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> +<head> + <th:block th:include="include :: header('${functionName}列表')" /> +</head> +<body class="gray-bg"> + <div class="container-div"> + <div class="row"> + <div class="col-sm-12 search-collapse"> + <form id="formId"> + <div class="select-list"> + <ul> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <li> + <p>${comment}:</p> + <input type="text" name="${column.javaField}"/> + </li> +#elseif($column.htmlType == "select" || $column.htmlType == "radio" && "" != $dictType) + <li> + <p>${comment}:</p> + <select name="${column.javaField}" th:with="type=${@dict.getType('${dictType}')}"> + <option value="">所有</option> + <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option> + </select> + </li> +#elseif($column.htmlType == "select" || $column.htmlType == "radio" && $dictType) + <li> + <p>${comment}:</p> + <select name="${column.javaField}"> + <option value="">所有</option> + </select> + </li> +#elseif($column.htmlType == "datetime") + <li class="select-time"> + <p>${comment}:</p> + <input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[begin${AttrName}]"/> + <span>-</span> + <input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[end${AttrName}]"/> + </li> +#end +#end +#end + <li> + <a class="btn btn-primary btn-rounded btn-sm" onclick="$.treeTable.search()"><i class="fa fa-search"></i> 搜索</a> + <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a> + </li> + </ul> + </div> + </form> + </div> + + <div class="btn-group-sm" id="toolbar" role="group"> + <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="${permissionPrefix}:add"> + <i class="fa fa-plus"></i> 新增 + </a> + <a class="btn btn-primary" onclick="$.operate.edit()" shiro:hasPermission="${permissionPrefix}:edit"> + <i class="fa fa-edit"></i> 修改 + </a> + <a class="btn btn-info" id="expandAllBtn"> + <i class="fa fa-exchange"></i> 展开/折叠 + </a> + </div> + <div class="col-sm-12 select-table table-striped"> + <table id="bootstrap-tree-table"></table> + </div> + </div> + </div> + <th:block th:include="include :: footer" /> + <script th:inline="javascript"> + var addFlag = [[${@permission.hasPermi('${permissionPrefix}:add')}]]; + var editFlag = [[${@permission.hasPermi('${permissionPrefix}:edit')}]]; + var removeFlag = [[${@permission.hasPermi('${permissionPrefix}:remove')}]]; +#foreach($column in $columns) +#if(${column.dictType} != '') + var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]]; +#end +#end + var prefix = ctx + "${moduleName}/${businessName}"; + + $(function() { + var options = { + code: "${treeCode}", + parentCode: "${treeParentCode}", + expandColumn: "${expandColumn}", + uniqueId: "${pkColumn.javaField}", + url: prefix + "/list", + createUrl: prefix + "/add/{id}", + updateUrl: prefix + "/edit/{id}", + removeUrl: prefix + "/remove/{id}", + exportUrl: prefix + "/export", + modalName: "${functionName}", + columns: [{ + field: 'selectItem', + radio: true + }, +#foreach($column in $columns) +#set($dictType=$column.dictType) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) +#elseif($column.list && "" != $dictType) + { + field : '${javaField}', + title : '${comment}', + align: 'left', + formatter: function(value, row, index) { + return $.table.selectDictLabel(${javaField}Datas, value); + } + }, +#elseif($column.list && "" != $javaField) + { + field : '${javaField}', + title : '${comment}', + align: 'left' + }, +#end +#end + { + title: '操作', + align: 'center', + align: 'left', + formatter: function(value, row, index) { + var actions = []; + actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.${pkColumn.javaField} + '\')"><i class="fa fa-edit"></i>编辑</a> '); + actions.push('<a class="btn btn-info btn-xs ' + addFlag + '" href="javascript:void(0)" onclick="$.operate.add(\'' + row.${pkColumn.javaField} + '\')"><i class="fa fa-plus"></i>新增</a> '); + actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.${pkColumn.javaField} + '\')"><i class="fa fa-remove"></i>删除</a>'); + return actions.join(''); + } + }] + }; + $.treeTable.init(options); + }); + </script> +</body> +</html> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/html/list.html.vm b/ruoyi/src/main/resources/vm/html/list.html.vm new file mode 100644 index 000000000..35fd8bcf6 --- /dev/null +++ b/ruoyi/src/main/resources/vm/html/list.html.vm @@ -0,0 +1,148 @@ +<!DOCTYPE html> +<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"> +<head> + <th:block th:include="include :: header('${functionName}列表')" /> +</head> +<body class="gray-bg"> + <div class="container-div"> + <div class="row"> + <div class="col-sm-12 search-collapse"> + <form id="formId"> + <div class="select-list"> + <ul> +#foreach($column in $columns) +#if($column.query) +#set($dictType=$column.dictType) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.htmlType == "input") + <li> + <p>${comment}:</p> + <input type="text" name="${column.javaField}"/> + </li> +#elseif($column.htmlType == "select" || $column.htmlType == "radio" && "" != $dictType) + <li> + <p>${comment}:</p> + <select name="${column.javaField}" th:with="type=${@dict.getType('${dictType}')}"> + <option value="">所有</option> + <option th:each="dict : ${type}" th:text="${dict.dictLabel}" th:value="${dict.dictValue}"></option> + </select> + </li> +#elseif($column.htmlType == "select" || $column.htmlType == "radio" && $dictType) + <li> + <p>${comment}:</p> + <select name="${column.javaField}"> + <option value="">所有</option> + </select> + </li> +#elseif($column.htmlType == "datetime") + <li class="select-time"> + <p>${comment}:</p> + <input type="text" class="time-input" id="startTime" placeholder="开始时间" name="params[begin${AttrName}]"/> + <span>-</span> + <input type="text" class="time-input" id="endTime" placeholder="结束时间" name="params[end${AttrName}]"/> + </li> +#end +#end +#end + <li> + <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i> 搜索</a> + <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i> 重置</a> + </li> + </ul> + </div> + </form> + </div> + + <div class="btn-group-sm" id="toolbar" role="group"> + <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="${permissionPrefix}:add"> + <i class="fa fa-plus"></i> 添加 + </a> + <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="${permissionPrefix}:edit"> + <i class="fa fa-edit"></i> 修改 + </a> + <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="${permissionPrefix}:remove"> + <i class="fa fa-remove"></i> 删除 + </a> + <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="${permissionPrefix}:export"> + <i class="fa fa-download"></i> 导出 + </a> + </div> + <div class="col-sm-12 select-table table-striped"> + <table id="bootstrap-table"></table> + </div> + </div> + </div> + <th:block th:include="include :: footer" /> + <script th:inline="javascript"> + var editFlag = [[${@permission.hasPermi('${permissionPrefix}:edit')}]]; + var removeFlag = [[${@permission.hasPermi('${permissionPrefix}:remove')}]]; +#foreach($column in $columns) +#if(${column.dictType} != '') + var ${column.javaField}Datas = [[${@dict.getType('${column.dictType}')}]]; +#end +#end + var prefix = ctx + "${moduleName}/${businessName}"; + + $(function() { + var options = { + url: prefix + "/list", + createUrl: prefix + "/add", + updateUrl: prefix + "/edit/{id}", + removeUrl: prefix + "/remove", + exportUrl: prefix + "/export", + modalName: "${functionName}", + columns: [{ + checkbox: true + }, +#foreach($column in $columns) +#set($dictType=$column.dictType) +#set($javaField=$column.javaField) +#set($parentheseIndex=$column.columnComment.indexOf("(")) +#if($parentheseIndex != -1) +#set($comment=$column.columnComment.substring(0, $parentheseIndex)) +#else +#set($comment=$column.columnComment) +#end +#if($column.pk) + { + field : '${javaField}', + title : '${comment}', + visible: false + }, +#elseif($column.list && "" != $dictType) + { + field : '${javaField}', + title : '${comment}', + formatter: function(value, row, index) { + return $.table.selectDictLabel(${javaField}Datas, value); + } + }, +#elseif($column.list && "" != $javaField) + { + field : '${javaField}', + title : '${comment}' + }, +#end +#end + { + title: '操作', + align: 'center', + formatter: function(value, row, index) { + var actions = []; + actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.${pkColumn.javaField} + '\')"><i class="fa fa-edit"></i>编辑</a> '); + actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.${pkColumn.javaField} + '\')"><i class="fa fa-remove"></i>删除</a>'); + return actions.join(''); + } + }] + }; + $.table.init(options); + }); + </script> +</body> +</html> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/html/tree.html.vm b/ruoyi/src/main/resources/vm/html/tree.html.vm new file mode 100644 index 000000000..91e8fab37 --- /dev/null +++ b/ruoyi/src/main/resources/vm/html/tree.html.vm @@ -0,0 +1,51 @@ +<!DOCTYPE html> +<html lang="zh" xmlns:th="http://www.thymeleaf.org" > +<head> + <th:block th:include="include :: header('${functionName}树选择')" /> + <th:block th:include="include :: ztree-css" /> +</head> +<style> + body{height:auto;font-family: "Microsoft YaHei";} + button{font-family: "SimSun","Helvetica Neue",Helvetica,Arial;} +</style> +<body class="hold-transition box box-main"> +#set($treeId = "${className}?." + $treeCode) +#set($treeName = "${className}?." + $treeName) + <input id="treeId" name="treeId" type="hidden" th:value="${${treeId}}"/> + <input id="treeName" name="treeName" type="hidden" th:value="${${treeName}}"/> + <div class="wrapper"><div class="treeShowHideButton" onclick="$.tree.toggleSearch();"> + <label id="btnShow" title="显示搜索" style="display:none;">︾</label> + <label id="btnHide" title="隐藏搜索">︽</label> + </div> + <div class="treeSearchInput" id="search"> + <label for="keyword">关键字:</label><input type="text" class="empty" id="keyword" maxlength="50"> + <button class="btn" id="btn" onclick="$.tree.searchNode()"> 搜索 </button> + </div> + <div class="treeExpandCollapse"> + <a href="#" onclick="$.tree.expand()">展开</a> / + <a href="#" onclick="$.tree.collapse()">折叠</a> + </div> + <div id="tree" class="ztree treeselect"></div> + </div> + <th:block th:include="include :: footer" /> + <th:block th:include="include :: ztree-js" /> + <script th:inline="javascript"> + $(function() { + var url = ctx + "${moduleName}/${businessName}/treeData"; + var options = { + url: url, + expandLevel: 2, + onClick : zOnClick + }; + $.tree.init(options); + }); + + function zOnClick(event, treeId, treeNode) { + var treeId = treeNode.id; + var treeName = treeNode.name; + $("#treeId").val(treeId); + $("#treeName").val(treeName); + } + </script> +</body> +</html> \ No newline at end of file diff --git a/ruoyi/src/main/resources/vm/java/controller.java.vm b/ruoyi/src/main/resources/vm/java/controller.java.vm new file mode 100644 index 000000000..fb9f9e80e --- /dev/null +++ b/ruoyi/src/main/resources/vm/java/controller.java.vm @@ -0,0 +1,200 @@ +package ${packageName}.${businessName}.controller; + +import java.util.List; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import com.ruoyi.framework.aspectj.lang.annotation.Log; +import com.ruoyi.framework.aspectj.lang.enums.BusinessType; +import ${packageName}.${businessName}.domain.${ClassName}; +import ${packageName}.${businessName}.service.I${ClassName}Service; +import com.ruoyi.framework.web.controller.BaseController; +import com.ruoyi.framework.web.domain.AjaxResult; +import com.ruoyi.common.utils.poi.ExcelUtil; +#if($table.crud) +import com.ruoyi.framework.web.page.TableDataInfo; +#elseif($table.tree) +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.framework.web.domain.Ztree; +#end + +/** + * ${functionName}Controller + * + * @author ${author} + * @date ${datetime} + */ +@Controller +@RequestMapping("/${moduleName}/${businessName}") +public class ${ClassName}Controller extends BaseController +{ + private String prefix = "${moduleName}/${businessName}"; + + @Autowired + private I${ClassName}Service ${className}Service; + + @RequiresPermissions("${permissionPrefix}:view") + @GetMapping() + public String ${businessName}() + { + return prefix + "/${businessName}"; + } + +#if($table.tree) + /** + * 查询${functionName}树列表 + */ + @RequiresPermissions("${permissionPrefix}:list") + @PostMapping("/list") + @ResponseBody + public List<${ClassName}> list(${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return list; + } +#elseif($table.crud) + /** + * 查询${functionName}列表 + */ + @RequiresPermissions("${permissionPrefix}:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(${ClassName} ${className}) + { + startPage(); + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + return getDataTable(list); + } +#end + + /** + * 导出${functionName}列表 + */ + @RequiresPermissions("${permissionPrefix}:export") + @PostMapping("/export") + @ResponseBody + public AjaxResult export(${ClassName} ${className}) + { + List<${ClassName}> list = ${className}Service.select${ClassName}List(${className}); + ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class); + return util.exportExcel(list, "${businessName}"); + } + +#if($table.crud) + /** + * 新增${functionName} + */ + @GetMapping("/add") + public String add() + { + return prefix + "/add"; + } +#elseif($table.tree) + /** + * 新增${functionName} + */ + @GetMapping(value = { "/add/{${pkColumn.javaField}}", "/add/" }) + public String add(@PathVariable(value = "${pkColumn.javaField}", required = false) Long ${pkColumn.javaField}, ModelMap mmap) + { + if (StringUtils.isNotNull(${pkColumn.javaField})) + { + mmap.put("${className}", ${className}Service.select${ClassName}ById(${pkColumn.javaField})); + } + return prefix + "/add"; + } +#end + + /** + * 新增保存${functionName} + */ + @RequiresPermissions("${permissionPrefix}:add") + @Log(title = "${functionName}", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(${ClassName} ${className}) + { + return toAjax(${className}Service.insert${ClassName}(${className})); + } + + /** + * 修改${functionName} + */ + @GetMapping("/edit/{${pkColumn.javaField}}") + public String edit(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}, ModelMap mmap) + { + ${ClassName} ${className} = ${className}Service.select${ClassName}ById(${pkColumn.javaField}); + mmap.put("${className}", ${className}); + return prefix + "/edit"; + } + + /** + * 修改保存${functionName} + */ + @RequiresPermissions("${permissionPrefix}:edit") + @Log(title = "${functionName}", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(${ClassName} ${className}) + { + return toAjax(${className}Service.update${ClassName}(${className})); + } + +#if($table.crud) + /** + * 删除${functionName} + */ + @RequiresPermissions("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @PostMapping( "/remove") + @ResponseBody + public AjaxResult remove(String ids) + { + return toAjax(${className}Service.delete${ClassName}ByIds(ids)); + } +#elseif($table.tree) + /** + * 删除 + */ + @RequiresPermissions("${permissionPrefix}:remove") + @Log(title = "${functionName}", businessType = BusinessType.DELETE) + @GetMapping("/remove/{${pkColumn.javaField}}") + @ResponseBody + public AjaxResult remove(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField}) + { + return toAjax(${className}Service.delete${ClassName}ById(${pkColumn.javaField})); + } +#end +#if($table.tree) + + /** + * 选择${functionName}树 + */ +#set($BusinessName=$businessName.substring(0,1).toUpperCase() + ${businessName.substring(1)}) + @GetMapping(value = { "/select${BusinessName}Tree/{${pkColumn.javaField}}", "/select${BusinessName}Tree/" }) + public String select${BusinessName}Tree(@PathVariable(value = "${pkColumn.javaField}", required = false) Long ${pkColumn.javaField}, ModelMap mmap) + { + if (StringUtils.isNotNull(${pkColumn.javaField})) + { + mmap.put("${className}", ${className}Service.select${ClassName}ById(${pkColumn.javaField})); + } + return prefix + "/tree"; + } + + /** + * 加载${functionName}树列表 + */ + @GetMapping("/treeData") + @ResponseBody + public List<Ztree> treeData() + { + List<Ztree> ztrees = ${className}Service.select${ClassName}Tree(); + return ztrees; + } +#end +} diff --git a/ruoyi/src/main/resources/vm/java/domain.java.vm b/ruoyi/src/main/resources/vm/java/domain.java.vm new file mode 100644 index 000000000..96d5e7d97 --- /dev/null +++ b/ruoyi/src/main/resources/vm/java/domain.java.vm @@ -0,0 +1,76 @@ +package ${packageName}.${businessName}.domain; + +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; +import com.ruoyi.framework.aspectj.lang.annotation.Excel; +#if($table.crud) +import com.ruoyi.framework.web.domain.BaseEntity; +#elseif($table.tree) +import com.ruoyi.framework.web.domain.TreeEntity; +#end +#foreach ($import in $importList) +import ${import}; +#end + +/** + * ${functionName}对象 ${tableName} + * + * @author ${author} + * @date ${datetime} + */ +#if($table.crud) +#set($Entity="BaseEntity") +#elseif($table.tree) +#set($Entity="TreeEntity") +#end +public class ${ClassName} extends ${Entity} +{ + private static final long serialVersionUID = 1L; + +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) + /** $column.columnComment */ +#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') + @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd") +#else + @Excel(name = "${comment}") +#end +#end + private $column.javaType $column.javaField; + +#end +#end +#foreach ($column in $columns) +#if(!$table.isSuperColumn($column.javaField)) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + public void set${AttrName}($column.javaType $column.javaField) + { + this.$column.javaField = $column.javaField; + } + + public $column.javaType get${AttrName}() + { + return $column.javaField; + } +#end +#end + + @Override + public String toString() { + return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) +#foreach ($column in $columns) +#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)}) + .append("${column.javaField}", get${AttrName}()) +#end + .toString(); + } +} diff --git a/ruoyi/src/main/resources/vm/java/mapper.java.vm b/ruoyi/src/main/resources/vm/java/mapper.java.vm new file mode 100644 index 000000000..58879415f --- /dev/null +++ b/ruoyi/src/main/resources/vm/java/mapper.java.vm @@ -0,0 +1,61 @@ +package ${packageName}.${businessName}.mapper; + +import ${packageName}.${businessName}.domain.${ClassName}; +import java.util.List; + +/** + * ${functionName}Mapper接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface ${ClassName}Mapper +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return ${functionName} + */ + public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 删除${functionName} + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return 结果 + */ + public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 批量删除${functionName} + * + * @param ${pkColumn.javaField}s 需要删除的数据ID + * @return 结果 + */ + public int delete${ClassName}ByIds(String[] ${pkColumn.javaField}s); +} diff --git a/ruoyi/src/main/resources/vm/java/service.java.vm b/ruoyi/src/main/resources/vm/java/service.java.vm new file mode 100644 index 000000000..54c7fc071 --- /dev/null +++ b/ruoyi/src/main/resources/vm/java/service.java.vm @@ -0,0 +1,73 @@ +package ${packageName}.${businessName}.service; + +import ${packageName}.${businessName}.domain.${ClassName}; +import java.util.List; +#if($table.tree) +import com.ruoyi.framework.web.domain.Ztree; +#end + +/** + * ${functionName}Service接口 + * + * @author ${author} + * @date ${datetime} + */ +public interface I${ClassName}Service +{ + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return ${functionName} + */ + public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName}集合 + */ + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}); + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int insert${ClassName}(${ClassName} ${className}); + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + public int update${ClassName}(${ClassName} ${className}); + + /** + * 批量删除${functionName} + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + public int delete${ClassName}ByIds(String ids); + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return 结果 + */ + public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}); +#if($table.tree) + + /** + * 查询${functionName}树列表 + * + * @return 所有${functionName}信息 + */ + public List<Ztree> select${ClassName}Tree(); +#end +} diff --git a/ruoyi/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi/src/main/resources/vm/java/serviceImpl.java.vm new file mode 100644 index 000000000..405da6921 --- /dev/null +++ b/ruoyi/src/main/resources/vm/java/serviceImpl.java.vm @@ -0,0 +1,141 @@ +package ${packageName}.${businessName}.service.impl; + +import java.util.List; +#if($table.tree) +import java.util.ArrayList; +import com.ruoyi.framework.web.domain.Ztree; +#end +#foreach ($column in $columns) +#if($column.javaField == 'createTime' || $column.javaField == 'updateTime') +import com.ruoyi.common.utils.DateUtils; +#break +#end +#end +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import ${packageName}.${businessName}.mapper.${ClassName}Mapper; +import ${packageName}.${businessName}.domain.${ClassName}; +import ${packageName}.${businessName}.service.I${ClassName}Service; +import com.ruoyi.common.utils.text.Convert; + +/** + * ${functionName}Service业务层处理 + * + * @author ${author} + * @date ${datetime} + */ +@Service +public class ${ClassName}ServiceImpl implements I${ClassName}Service +{ + @Autowired + private ${ClassName}Mapper ${className}Mapper; + + /** + * 查询${functionName} + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return ${functionName} + */ + @Override + public ${ClassName} select${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}) + { + return ${className}Mapper.select${ClassName}ById(${pkColumn.javaField}); + } + + /** + * 查询${functionName}列表 + * + * @param ${className} ${functionName} + * @return ${functionName} + */ + @Override + public List<${ClassName}> select${ClassName}List(${ClassName} ${className}) + { + return ${className}Mapper.select${ClassName}List(${className}); + } + + /** + * 新增${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + @Override + public int insert${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'createTime') + ${className}.setCreateTime(DateUtils.getNowDate()); +#end +#end + return ${className}Mapper.insert${ClassName}(${className}); + } + + /** + * 修改${functionName} + * + * @param ${className} ${functionName} + * @return 结果 + */ + @Override + public int update${ClassName}(${ClassName} ${className}) + { +#foreach ($column in $columns) +#if($column.javaField == 'createTime') + ${className}.setUpdateTime(DateUtils.getNowDate()); +#end +#end + return ${className}Mapper.update${ClassName}(${className}); + } + + /** + * 删除${functionName}对象 + * + * @param ids 需要删除的数据ID + * @return 结果 + */ + @Override + public int delete${ClassName}ByIds(String ids) + { + return ${className}Mapper.delete${ClassName}ByIds(Convert.toStrArray(ids)); + } + + /** + * 删除${functionName}信息 + * + * @param ${pkColumn.javaField} ${functionName}ID + * @return 结果 + */ + @Override + public int delete${ClassName}ById(${pkColumn.javaType} ${pkColumn.javaField}) + { + return ${className}Mapper.delete${ClassName}ById(${pkColumn.javaField}); + } +#if($table.tree) + + /** + * 查询${functionName}树列表 + * + * @return 所有${functionName}信息 + */ + @Override + public List<Ztree> select${ClassName}Tree() + { + List<${ClassName}> ${className}List = ${className}Mapper.select${ClassName}List(new ${ClassName}()); + List<Ztree> ztrees = new ArrayList<Ztree>(); + for (${ClassName} ${className} : ${className}List) + { + Ztree ztree = new Ztree(); +#set($TreeCode=$treeCode.substring(0,1).toUpperCase() + ${treeCode.substring(1)}) +#set($TreeParentCode=$treeParentCode.substring(0,1).toUpperCase() + ${treeParentCode.substring(1)}) +#set($TreeName=$treeName.substring(0,1).toUpperCase() + ${treeName.substring(1)}) + ztree.setId(${className}.get${TreeCode}()); + ztree.setpId(${className}.get${TreeParentCode}()); + ztree.setName(${className}.get${TreeName}()); + ztree.setTitle(${className}.get${TreeName}()); + ztrees.add(ztree); + } + return ztrees; + } +#end +} diff --git a/ruoyi/src/main/resources/vm/sql/sql.vm b/ruoyi/src/main/resources/vm/sql/sql.vm new file mode 100644 index 000000000..404108086 --- /dev/null +++ b/ruoyi/src/main/resources/vm/sql/sql.vm @@ -0,0 +1,22 @@ +-- 菜单 SQL +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}', '3', '1', '/${moduleName}/${businessName}', 'C', '0', '${permissionPrefix}:view', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', '${functionName}菜单'); + +-- 按钮父菜单ID +SELECT @parentId := LAST_INSERT_ID(); + +-- 按钮 SQL +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}查询', @parentId, '1', '#', 'F', '0', '${permissionPrefix}:list', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); + +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}新增', @parentId, '2', '#', 'F', '0', '${permissionPrefix}:add', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); + +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}修改', @parentId, '3', '#', 'F', '0', '${permissionPrefix}:edit', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); + +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}删除', @parentId, '4', '#', 'F', '0', '${permissionPrefix}:remove', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); + +insert into sys_menu (menu_name, parent_id, order_num, url,menu_type, visible, perms, icon, create_by, create_time, update_by, update_time, remark) +values('${functionName}导出', @parentId, '5', '#', 'F', '0', '${permissionPrefix}:export', '#', 'admin', '2018-03-01', 'ry', '2018-03-01', ''); diff --git a/ruoyi/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi/src/main/resources/vm/xml/mapper.xml.vm new file mode 100644 index 000000000..bbfeb539e --- /dev/null +++ b/ruoyi/src/main/resources/vm/xml/mapper.xml.vm @@ -0,0 +1,108 @@ +<?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}.${businessName}.mapper.${ClassName}Mapper"> + + <resultMap type="${ClassName}" id="${ClassName}Result"> +#foreach ($column in $columns) + <result property="${column.javaField}" column="${column.columnName}" /> +#end +#if($table.tree) + <result property="parentName" column="parent_name" /> +#end + </resultMap> + + <sql id="select${ClassName}Vo"> + select#foreach($column in $columns) $column.columnName#if($velocityCount != $columns.size()),#end#end from ${tableName} + </sql> + + <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result"> + <include refid="select${ClassName}Vo"/> + <where> +#foreach($column in $columns) +#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)}) +#if($column.query) +#if($column.queryType == "EQ") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if> +#elseif($queryType == "NE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if> +#elseif($queryType == "GT") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName > #{$javaField}</if> +#elseif($queryType == "GTE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName >= #{$javaField}</if> +#elseif($queryType == "LT") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName < #{$javaField}</if> +#elseif($queryType == "LTE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName <= #{$javaField}</if> +#elseif($queryType == "LIKE") + <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if> +#elseif($queryType == "BETWEEN") + <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if> +#end +#end +#end + </where> +#if($table.tree) + order by ${tree_parent_code} +#end + </select> + + <select id="select${ClassName}ById" parameterType="${pkColumn.javaType}" resultMap="${ClassName}Result"> +#if($table.crud) + <include refid="select${ClassName}Vo"/> + where ${pkColumn.columnName} = #{${pkColumn.javaField}} +#elseif($table.tree) + select#foreach($column in $columns) t.$column.columnName,#end p.${tree_name} as parent_name + from ${tableName} t + left join ${tableName} p on p.${pkColumn.columnName} = t.${tree_parent_code} + where t.${pkColumn.columnName} = #{${pkColumn.javaField}} +#end + </select> + + <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end> + insert into ${tableName} + <trim prefix="(" suffix=")" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + <if test="$column.javaField != null #if($column.javaType == 'String' ) and $column.javaField != ''#end">$column.columnName,</if> +#end +#end + </trim> + <trim prefix="values (" suffix=")" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment) + <if test="$column.javaField != null #if($column.javaType == 'String' ) and $column.javaField != ''#end">#{$column.javaField},</if> +#end +#end + </trim> + </insert> + + <update id="update${ClassName}" parameterType="${ClassName}"> + update ${tableName} + <trim prefix="SET" suffixOverrides=","> +#foreach($column in $columns) +#if($column.columnName != $pkColumn.columnName) + <if test="$column.javaField != null #if($column.javaType == 'String' ) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if> +#end +#end + </trim> + where ${pkColumn.columnName} = #{${pkColumn.javaField}} + </update> + + <delete id="delete${ClassName}ById" parameterType="${pkColumn.javaType}"> + delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}} + </delete> + + <delete id="delete${ClassName}ByIds" parameterType="String"> + delete from ${tableName} where ${pkColumn.columnName} in + <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")"> + #{${pkColumn.javaField}} + </foreach> + </delete> + +</mapper> \ No newline at end of file