diff --git a/pom.xml b/pom.xml
index 74eb7086..c75807af 100644
--- a/pom.xml
+++ b/pom.xml
@@ -20,7 +20,7 @@
2020.0.4
2021.1
2.0.3
- 2.6.0
+ 2.6.3
2.2.0
3.0.0
1.6.2
@@ -53,6 +53,7 @@
2.2.0.RELEASE
7.12.1
3.12.0
+ 1.0.5
@@ -122,6 +123,20 @@
${redisson.version}
+
+
+ cn.smallbun.screw
+ screw-core
+ ${screw.version}
+
+
+
+ org.freemarker
+ freemarker
+
+
+
+
com.xjs
xjs-business-common
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
index c7bec5da..e82da4dc 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
@@ -1,15 +1,10 @@
package com.ruoyi.common.core.utils;
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.Enumeration;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
+import cn.hutool.core.io.IoUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.text.Convert;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
@@ -18,15 +13,22 @@ import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
-import com.alibaba.fastjson.JSONObject;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.core.text.Convert;
import reactor.core.publisher.Mono;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Enumeration;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
/**
* 客户端工具类
- *
+ *
* @author ruoyi
*/
public class ServletUtils
@@ -158,7 +160,7 @@ public class ServletUtils
/**
* 将字符串渲染到客户端
- *
+ *
* @param response 渲染对象
* @param string 待渲染的字符串
* @return null
@@ -181,7 +183,7 @@ public class ServletUtils
/**
* 是否是Ajax异步请求
- *
+ *
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request)
@@ -214,7 +216,7 @@ public class ServletUtils
/**
* 内容编码
- *
+ *
* @param str 内容
* @return 编码后的内容
*/
@@ -232,7 +234,7 @@ public class ServletUtils
/**
* 内容解码
- *
+ *
* @param str 内容
* @return 解码后的内容
*/
@@ -305,4 +307,20 @@ public class ServletUtils
DataBuffer dataBuffer = response.bufferFactory().wrap(JSONObject.toJSONString(result).getBytes());
return response.writeWith(Mono.just(dataBuffer));
}
+
+ /**
+ * 返回附件
+ *
+ * @param response 响应
+ * @param filename 文件名
+ * @param content 附件内容
+ * @throws IOException
+ */
+ public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
+ // 设置 header 和 contentType
+ response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename, "UTF-8"));
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+ // 输出附件
+ IoUtil.write(response.getOutputStream(), false, content);
+ }
}
diff --git a/ruoyi-ui/src/api/business/monitor/db/dbDoc.js b/ruoyi-ui/src/api/business/monitor/db/dbDoc.js
new file mode 100644
index 00000000..dfa0251c
--- /dev/null
+++ b/ruoyi-ui/src/api/business/monitor/db/dbDoc.js
@@ -0,0 +1,35 @@
+import request from '@/utils/request'
+
+export function exportHtml(key) {
+ return request({
+ url: '/monitor/db-doc/export-html',
+ method: 'get',
+ responseType: 'blob',
+ params:key
+ })
+}
+
+export function exportWord(key) {
+ return request({
+ url: '/monitor/db-doc/export-word',
+ method: 'get',
+ responseType: 'blob',
+ params:key
+ })
+}
+
+export function exportMarkdown(key) {
+ return request({
+ url: '/monitor/db-doc/export-markdown',
+ method: 'get',
+ responseType: 'blob',
+ params:key
+ })
+}
+
+export function getDataSource() {
+ return request({
+ url: '/monitor/db-doc/getDataSource',
+ method: 'get',
+ })
+}
diff --git a/ruoyi-ui/src/components/iFrame/index.vue b/ruoyi-ui/src/components/iFrame/index.vue
index 426857fb..f0485520 100644
--- a/ruoyi-ui/src/components/iFrame/index.vue
+++ b/ruoyi-ui/src/components/iFrame/index.vue
@@ -18,7 +18,7 @@ export default {
},
data() {
return {
- height: document.documentElement.clientHeight - 94.5 + "px;",
+ height: document.documentElement.clientHeight - 94.5 + "px",
loading: true,
url: this.src
};
@@ -29,7 +29,7 @@ export default {
}, 300);
const that = this;
window.onresize = function temp() {
- that.height = document.documentElement.clientHeight - 94.5 + "px;";
+ that.height = document.documentElement.clientHeight - 94.5 + "px";
};
}
};
diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index cfb7c246..31a28037 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -1,38 +1,77 @@
-import axios from 'axios'
-import { Message } from 'element-ui'
-import { saveAs } from 'file-saver'
-import { getToken } from '@/utils/auth'
-import errorCode from '@/utils/errorCode'
-import { blobValidate } from "@/utils/ruoyi";
-
-const baseURL = process.env.VUE_APP_BASE_API
-
-export default {
- zip(url, name) {
- var url = baseURL + url
- axios({
- method: 'get',
- url: url,
- responseType: 'blob',
- headers: { 'Authorization': 'Bearer ' + getToken() }
- }).then(async (res) => {
- const isLogin = await blobValidate(res.data);
- if (isLogin) {
- const blob = new Blob([res.data], { type: 'application/zip' })
- this.saveAs(blob, name)
- } else {
- this.printErrMsg(res.data);
- }
- })
- },
- saveAs(text, name, opts) {
- saveAs(text, name, opts);
- },
- async printErrMsg(data) {
- const resText = await data.text();
- const rspObj = JSON.parse(resText);
- const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
- Message.error(errMsg);
- }
-}
-
+import axios from 'axios'
+import { Message } from 'element-ui'
+import { saveAs } from 'file-saver'
+import { getToken } from '@/utils/auth'
+import errorCode from '@/utils/errorCode'
+import { blobValidate } from "@/utils/ruoyi";
+
+const baseURL = process.env.VUE_APP_BASE_API
+
+export default {
+ zip(url, name) {
+ var url = baseURL + url
+ axios({
+ method: 'get',
+ url: url,
+ responseType: 'blob',
+ headers: { 'Authorization': 'Bearer ' + getToken() }
+ }).then(async (res) => {
+ const isLogin = await blobValidate(res.data);
+ if (isLogin) {
+ const blob = new Blob([res.data], { type: 'application/zip' })
+ this.saveAs(blob, name)
+ } else {
+ this.printErrMsg(res.data);
+ }
+ })
+ },
+ saveAs(text, name, opts) {
+ saveAs(text, name, opts);
+ },
+ async printErrMsg(data) {
+ const resText = await data.text();
+ const rspObj = JSON.parse(resText);
+ const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+ Message.error(errMsg);
+ },
+
+ // 下载 Excel 方法
+ excel(data, fileName) {
+ this.download0(data, fileName, 'application/vnd.ms-excel');
+ },
+
+ // 下载 Word 方法
+ word(data, fileName) {
+ this.download0(data, fileName, 'application/msword');
+ },
+
+ // 下载 Zip 方法
+ /*zip(data, fileName) {
+ this.download0(data, fileName, 'application/zip');
+ },*/
+
+ // 下载 Html 方法
+ html(data, fileName) {
+ this.download0(data, fileName, 'text/html');
+ },
+
+ // 下载 Markdown 方法
+ markdown(data, fileName) {
+ this.download0(data, fileName, 'text/markdown');
+ },
+
+ download0(data, fileName, mineType) {
+ // 创建 blob
+ let blob = new Blob([data], {type: mineType});
+ // 创建 href 超链接,点击进行下载
+ window.URL = window.URL || window.webkitURL;
+ let href = URL.createObjectURL(blob);
+ let downA = document.createElement("a");
+ downA.href = href;
+ downA.download = fileName;
+ downA.click();
+ // 销毁超连接
+ window.URL.revokeObjectURL(href);
+ },
+}
+
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
index 8c3c3390..966a81d2 100644
--- a/ruoyi-ui/src/store/modules/permission.js
+++ b/ruoyi-ui/src/store/modules/permission.js
@@ -1,138 +1,140 @@
-import auth from '@/plugins/auth'
-import router, { constantRoutes, dynamicRoutes } from '@/router'
-import { getRouters } from '@/api/menu'
-import Layout from '@/layout/index'
-import ParentView from '@/components/ParentView'
-import InnerLink from '@/layout/components/InnerLink'
-
-const permission = {
- state: {
- routes: [],
- addRoutes: [],
- defaultRoutes: [],
- topbarRouters: [],
- sidebarRouters: []
- },
- mutations: {
- SET_ROUTES: (state, routes) => {
- state.addRoutes = routes
- state.routes = constantRoutes.concat(routes)
- },
- SET_DEFAULT_ROUTES: (state, routes) => {
- state.defaultRoutes = constantRoutes.concat(routes)
- },
- SET_TOPBAR_ROUTES: (state, routes) => {
- // 顶部导航菜单默认添加统计报表栏指向首页
- const index = [{
- path: 'index',
- meta: { title: '统计报表', icon: 'dashboard' }
- }]
- state.topbarRouters = routes.concat(index);
- },
- SET_SIDEBAR_ROUTERS: (state, routes) => {
- state.sidebarRouters = routes
- },
- },
- actions: {
- // 生成路由
- GenerateRoutes({ commit }) {
- return new Promise(resolve => {
- // 向后端请求路由数据
- getRouters().then(res => {
- const sdata = JSON.parse(JSON.stringify(res.data))
- const rdata = JSON.parse(JSON.stringify(res.data))
- const sidebarRoutes = filterAsyncRouter(sdata)
- const rewriteRoutes = filterAsyncRouter(rdata, false, true)
- const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
- rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
- router.addRoutes(asyncRoutes);
- commit('SET_ROUTES', rewriteRoutes)
- commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
- commit('SET_DEFAULT_ROUTES', sidebarRoutes)
- commit('SET_TOPBAR_ROUTES', sidebarRoutes)
- resolve(rewriteRoutes)
- })
- })
- }
- }
-}
-
-// 遍历后台传来的路由字符串,转换为组件对象
-function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
- return asyncRouterMap.filter(route => {
- if (type && route.children) {
- route.children = filterChildren(route.children)
- }
- if (route.component) {
- // Layout ParentView 组件特殊处理
- if (route.component === 'Layout') {
- route.component = Layout
- } else if (route.component === 'ParentView') {
- route.component = ParentView
- } else if (route.component === 'InnerLink') {
- route.component = InnerLink
- } else {
- route.component = loadView(route.component)
- }
- }
- if (route.children != null && route.children && route.children.length) {
- route.children = filterAsyncRouter(route.children, route, type)
- } else {
- delete route['children']
- delete route['redirect']
- }
- return true
- })
-}
-
-function filterChildren(childrenMap, lastRouter = false) {
- var children = []
- childrenMap.forEach((el, index) => {
- if (el.children && el.children.length) {
- if (el.component === 'ParentView' && !lastRouter) {
- el.children.forEach(c => {
- c.path = el.path + '/' + c.path
- if (c.children && c.children.length) {
- children = children.concat(filterChildren(c.children, c))
- return
- }
- children.push(c)
- })
- return
- }
- }
- if (lastRouter) {
- el.path = lastRouter.path + '/' + el.path
- }
- children = children.concat(el)
- })
- return children
-}
-
-// 动态路由遍历,验证是否具备权限
-export function filterDynamicRoutes(routes) {
- const res = []
- routes.forEach(route => {
- if (route.permissions) {
- if (auth.hasPermiOr(route.permissions)) {
- res.push(route)
- }
- } else if (route.roles) {
- if (auth.hasRoleOr(route.roles)) {
- res.push(route)
- }
- }
- })
- return res
-}
-
-export const loadView = (view) => {
- if (process.env.NODE_ENV === 'development') {
- return (resolve) => require([`@/views/${view}`], resolve)
- } else {
- // 使用 import 实现生产环境的路由懒加载
- return () => import(`@/views/${view}`)
- }
-}
-
-export default permission
+import auth from '@/plugins/auth'
+import router, {constantRoutes, dynamicRoutes} from '@/router'
+import {getRouters} from '@/api/menu'
+import Layout from '@/layout/index'
+import ParentView from '@/components/ParentView'
+import InnerLink from '@/layout/components/InnerLink'
+
+const permission = {
+ state: {
+ routes: [],
+ addRoutes: [],
+ defaultRoutes: [],
+ topbarRouters: [],
+ sidebarRouters: []
+ },
+ mutations: {
+ SET_ROUTES: (state, routes) => {
+ state.addRoutes = routes
+ state.routes = constantRoutes.concat(routes)
+ },
+ SET_DEFAULT_ROUTES: (state, routes) => {
+ state.defaultRoutes = constantRoutes.concat(routes)
+ },
+ SET_TOPBAR_ROUTES: (state, routes) => {
+ // 顶部导航菜单默认添加统计报表栏指向首页
+ const index = [
+ /*{
+ path: 'index',
+ meta: {title: '统计报表', icon: 'dashboard'}
+ }*/
+ ]
+ state.topbarRouters = routes.concat(index);
+ },
+ SET_SIDEBAR_ROUTERS: (state, routes) => {
+ state.sidebarRouters = routes
+ },
+ },
+ actions: {
+ // 生成路由
+ GenerateRoutes({commit}) {
+ return new Promise(resolve => {
+ // 向后端请求路由数据
+ getRouters().then(res => {
+ const sdata = JSON.parse(JSON.stringify(res.data))
+ const rdata = JSON.parse(JSON.stringify(res.data))
+ const sidebarRoutes = filterAsyncRouter(sdata)
+ const rewriteRoutes = filterAsyncRouter(rdata, false, true)
+ const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
+ rewriteRoutes.push({path: '*', redirect: '/404', hidden: true})
+ router.addRoutes(asyncRoutes);
+ commit('SET_ROUTES', rewriteRoutes)
+ commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
+ commit('SET_DEFAULT_ROUTES', sidebarRoutes)
+ commit('SET_TOPBAR_ROUTES', sidebarRoutes)
+ resolve(rewriteRoutes)
+ })
+ })
+ }
+ }
+}
+
+// 遍历后台传来的路由字符串,转换为组件对象
+function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
+ return asyncRouterMap.filter(route => {
+ if (type && route.children) {
+ route.children = filterChildren(route.children)
+ }
+ if (route.component) {
+ // Layout ParentView 组件特殊处理
+ if (route.component === 'Layout') {
+ route.component = Layout
+ } else if (route.component === 'ParentView') {
+ route.component = ParentView
+ } else if (route.component === 'InnerLink') {
+ route.component = InnerLink
+ } else {
+ route.component = loadView(route.component)
+ }
+ }
+ if (route.children != null && route.children && route.children.length) {
+ route.children = filterAsyncRouter(route.children, route, type)
+ } else {
+ delete route['children']
+ delete route['redirect']
+ }
+ return true
+ })
+}
+
+function filterChildren(childrenMap, lastRouter = false) {
+ var children = []
+ childrenMap.forEach((el, index) => {
+ if (el.children && el.children.length) {
+ if (el.component === 'ParentView' && !lastRouter) {
+ el.children.forEach(c => {
+ c.path = el.path + '/' + c.path
+ if (c.children && c.children.length) {
+ children = children.concat(filterChildren(c.children, c))
+ return
+ }
+ children.push(c)
+ })
+ return
+ }
+ }
+ if (lastRouter) {
+ el.path = lastRouter.path + '/' + el.path
+ }
+ children = children.concat(el)
+ })
+ return children
+}
+
+// 动态路由遍历,验证是否具备权限
+export function filterDynamicRoutes(routes) {
+ const res = []
+ routes.forEach(route => {
+ if (route.permissions) {
+ if (auth.hasPermiOr(route.permissions)) {
+ res.push(route)
+ }
+ } else if (route.roles) {
+ if (auth.hasRoleOr(route.roles)) {
+ res.push(route)
+ }
+ }
+ })
+ return res
+}
+
+export const loadView = (view) => {
+ if (process.env.NODE_ENV === 'development') {
+ return (resolve) => require([`@/views/${view}`], resolve)
+ } else {
+ // 使用 import 实现生产环境的路由懒加载
+ return () => import(`@/views/${view}`)
+ }
+}
+
+export default permission
diff --git a/ruoyi-ui/src/views/business/monitor/db/index.vue b/ruoyi-ui/src/views/business/monitor/db/index.vue
new file mode 100644
index 00000000..03242df8
--- /dev/null
+++ b/ruoyi-ui/src/views/business/monitor/db/index.vue
@@ -0,0 +1,128 @@
+
+
+
+
+ 导出 HTML
+ 导出 Word
+ 导出 Markdown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xjs-business/xjs-business-monitor/pom.xml b/xjs-business/xjs-business-monitor/pom.xml
index 146bfabf..31e8de64 100644
--- a/xjs-business/xjs-business-monitor/pom.xml
+++ b/xjs-business/xjs-business-monitor/pom.xml
@@ -24,6 +24,17 @@
oshi-core
+
+
+ cn.smallbun.screw
+ screw-core
+
+
+
+ org.apache.velocity
+ velocity-engine-core
+
+
com.xjs
xjs-business-common
@@ -31,4 +42,4 @@
-
\ No newline at end of file
+
diff --git a/xjs-business/xjs-business-monitor/src/main/java/com/xjs/XjsMonitorApp.java b/xjs-business/xjs-business-monitor/src/main/java/com/xjs/XjsMonitorApp.java
index 83e24173..06e12e3b 100644
--- a/xjs-business/xjs-business-monitor/src/main/java/com/xjs/XjsMonitorApp.java
+++ b/xjs-business/xjs-business-monitor/src/main/java/com/xjs/XjsMonitorApp.java
@@ -1,6 +1,5 @@
package com.xjs;
-import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceAutoConfiguration;
import com.ruoyi.common.security.annotation.EnableRyFeignClients;
import com.ruoyi.common.security.config.ApplicationConfig;
import com.ruoyi.common.security.feign.FeignAutoConfiguration;
@@ -16,11 +15,11 @@ import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author xiejs
- * @desc 业务监控服务启动器
+ * @desc 业务监控服务启动器
* @create 2022-01-02
*/
//排除两个关于数据源的自动配置类、及seata配置类
-@SpringBootApplication(exclude = {DynamicDataSourceAutoConfiguration.class,
+@SpringBootApplication(exclude = {
DataSourceAutoConfiguration.class,
SeataAutoConfiguration.class})
// 表示通过aop框架暴露该代理对象,AopContext能够访问
@@ -28,9 +27,9 @@ import org.springframework.scheduling.annotation.EnableAsync;
// 开启线程异步执行
@EnableAsync
// 自动加载类
-@Import({ ApplicationConfig.class, FeignAutoConfiguration.class })
+@Import({ApplicationConfig.class, FeignAutoConfiguration.class})
//自定义bean扫描,添加xjs路径下的bean
-@ComponentScan(basePackages = {"com.ruoyi","com.xjs"})
+@ComponentScan(basePackages = {"com.ruoyi", "com.xjs"})
@EnableCustomSwagger2
@EnableRyFeignClients
public class XjsMonitorApp {
diff --git a/xjs-business/xjs-business-monitor/src/main/java/com/xjs/dbmonitor/DbDocController.java b/xjs-business/xjs-business-monitor/src/main/java/com/xjs/dbmonitor/DbDocController.java
new file mode 100644
index 00000000..ef1d0226
--- /dev/null
+++ b/xjs-business/xjs-business-monitor/src/main/java/com/xjs/dbmonitor/DbDocController.java
@@ -0,0 +1,182 @@
+package com.xjs.dbmonitor;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.IdUtil;
+import cn.smallbun.screw.core.Configuration;
+import cn.smallbun.screw.core.engine.EngineConfig;
+import cn.smallbun.screw.core.engine.EngineFileType;
+import cn.smallbun.screw.core.engine.EngineTemplateType;
+import cn.smallbun.screw.core.execute.DocumentationExecute;
+import cn.smallbun.screw.core.process.ProcessConfig;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DataSourceProperty;
+import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
+import com.ruoyi.common.core.utils.ServletUtils;
+import com.ruoyi.common.core.web.domain.AjaxResult;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @author xiejs
+ * @since 2022-04-16
+ */
+
+@Api(tags = "业务模块 - 数据库文档")
+@RestController
+@RequestMapping("/db-doc")
+public class DbDocController {
+ @Resource
+ private DynamicDataSourceProperties dynamicDataSourceProperties;
+
+ private static final String FILE_OUTPUT_DIR = System.getProperty("java.io.tmpdir") + File.separator
+ + "db-doc";
+ private static final String DOC_FILE_NAME = "数据库文档";
+ private static final String DOC_VERSION = "1.0.0";
+ private static final String DOC_DESCRIPTION = "谢哥数据库文档";
+
+
+ @GetMapping("getDataSource")
+ @ApiOperation("获取所有数据源")
+ public AjaxResult getDataSource() {
+ Map datasource = dynamicDataSourceProperties.getDatasource();
+ ArrayList