初版提交

This commit is contained in:
huangge1199 2025-03-13 15:56:06 +08:00
parent 7e95722915
commit 1d3ca38052
14 changed files with 941 additions and 0 deletions

158
pom.xml Normal file
View File

@ -0,0 +1,158 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.huangge1199</groupId>
<artifactId>bi</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>bi</name>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.15</version>
<relativePath />
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
<fastjson.version>2.0.53</fastjson.version>
<druid.version>1.2.23</druid.version>
<swagger.version>3.0.0</swagger.version>
<oracle.version>19.3.0.0</oracle.version>
</properties>
<dependencies>
<!-- SpringBoot 核心包 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- SpringBoot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示依赖不会传递 -->
</dependency>
<!-- oracle驱动-->
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>${oracle.version}</version>
</dependency>
<!-- 阿里数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>${druid.version}</version>
</dependency>
<!-- JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- 阿里JSON解析器 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>${fastjson.version}</version>
</dependency>
<!-- Swagger3依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>${swagger.version}</version>
<exclusions>
<exclusion>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- 防止进入swagger页面报类型转换错误排除3.0.0中的引用手动增加1.6.2版本 -->
<dependency>
<groupId>io.swagger</groupId>
<artifactId>swagger-models</artifactId>
<version>1.6.2</version>
</dependency>
<!-- knife4jswagger-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<!--在引用时请在maven中央仓库搜索3.X最新版本号-->
<version>3.0.3</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<!--阿里云镜像仓库-->
<repository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>public</id>
<name>aliyun nexus</name>
<url>https://maven.aliyun.com/repository/public</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>

View File

@ -0,0 +1,11 @@
package com.huangge1199;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}

View File

@ -0,0 +1,116 @@
package com.huangge1199.base;
import com.huangge1199.contant.HttpStatus;
import java.io.Serializable;
/**
* 响应信息主体
*
* @author ruoyi
*/
public class R<T> implements Serializable
{
private static final long serialVersionUID = 1L;
/** 成功 */
public static final int SUCCESS = HttpStatus.SUCCESS;
/** 失败 */
public static final int FAIL = HttpStatus.ERROR;
private int code;
private String msg;
private T data;
public static <T> R<T> ok()
{
return restResult(null, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data)
{
return restResult(data, SUCCESS, "操作成功");
}
public static <T> R<T> ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
}
public static <T> R<T> fail()
{
return restResult(null, FAIL, "操作失败");
}
public static <T> R<T> fail(String msg)
{
return restResult(null, FAIL, msg);
}
public static <T> R<T> fail(T data)
{
return restResult(data, FAIL, "操作失败");
}
public static <T> R<T> fail(T data, String msg)
{
return restResult(data, FAIL, msg);
}
public static <T> R<T> fail(int code, String msg)
{
return restResult(null, code, msg);
}
private static <T> R<T> restResult(T data, int code, String msg)
{
R<T> apiResult = new R<>();
apiResult.setCode(code);
apiResult.setData(data);
apiResult.setMsg(msg);
return apiResult;
}
public int getCode()
{
return code;
}
public void setCode(int code)
{
this.code = code;
}
public String getMsg()
{
return msg;
}
public void setMsg(String msg)
{
this.msg = msg;
}
public T getData()
{
return data;
}
public void setData(T data)
{
this.data = data;
}
public static <T> Boolean isError(R<T> ret)
{
return !isSuccess(ret);
}
public static <T> Boolean isSuccess(R<T> ret)
{
return R.SUCCESS == ret.getCode();
}
}

View File

@ -0,0 +1,42 @@
package com.huangge1199.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import javax.sql.DataSource;
/**
* DataSourceConfig
*
* @author huangge1199
* @since 2025/3/12 14:56:10
*/
@Configuration
public class DataSourceConfig {
@Primary // 指定主数据源
@Bean(name = "masterDataSource")
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:oracle:thin:@192.168.188.2:1521/xe");
dataSource.setUsername("ruoyi");
dataSource.setPassword("ruoyi");
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
return dataSource;
}
// 仅当 enabled = true 时才启用从库数据源
@Bean(name = "slaveDataSource")
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
public DataSource slaveDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl("jdbc:oracle:thin:@192.168.188.2:1521/xe"); // 修改为实际的从库地址
dataSource.setUsername("slave_user");
dataSource.setPassword("slave_password");
dataSource.setDriverClassName("oracle.jdbc.driver.OracleDriver");
return dataSource;
}
}

View File

@ -0,0 +1,50 @@
package com.huangge1199.config;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;
import java.util.ArrayList;
import java.util.List;
/**
* Swagger2的接口配置
*
* @author ruoyi
*/
@Configuration
public class SwaggerConfig
{
@Bean
public Docket api() {
return new Docket(DocumentationType.OAS_30) // OAS_30 代表 OpenAPI 3.0
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.huangge1199.controller")) // 修改为你的 Controller 包路径
.paths(PathSelectors.any())
.build();
}
/**
* 添加摘要信息
*/
private ApiInfo apiInfo()
{
// 用ApiInfoBuilder进行定制
return new ApiInfoBuilder()
.title("Spring Boot API 文档")
.description("基于 Swagger3 + Knife4j 的 API 文档")
.version("1.0.0")
.build();
}
}

View File

@ -0,0 +1,111 @@
package com.huangge1199.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
*
* @author ruoyi
*/
@Component
@ConfigurationProperties(prefix = "sys")
public class SysConfig
{
/** 项目名称 */
private String name;
/** 版本 */
private String version;
/** 版权年份 */
private String copyrightYear;
/** 上传路径 */
private static String profile;
/** 获取地址开关 */
private static boolean addressEnabled;
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
public String getCopyrightYear()
{
return copyrightYear;
}
public void setCopyrightYear(String copyrightYear)
{
this.copyrightYear = copyrightYear;
}
public static String getProfile()
{
return profile;
}
public void setProfile(String profile)
{
SysConfig.profile = profile;
}
public static boolean isAddressEnabled()
{
return addressEnabled;
}
public void setAddressEnabled(boolean addressEnabled)
{
SysConfig.addressEnabled = addressEnabled;
}
/**
* 获取导入上传路径
*/
public static String getImportPath()
{
return getProfile() + "/import";
}
/**
* 获取头像上传路径
*/
public static String getAvatarPath()
{
return getProfile() + "/avatar";
}
/**
* 获取下载路径
*/
public static String getDownloadPath()
{
return getProfile() + "/download/";
}
/**
* 获取上传路径
*/
public static String getUploadPath()
{
return getProfile() + "/upload";
}
}

View File

@ -0,0 +1,94 @@
package com.huangge1199.contant;
/**
* 返回状态码
*
* @author ruoyi
*/
public class HttpStatus
{
/**
* 操作成功
*/
public static final int SUCCESS = 200;
/**
* 对象创建成功
*/
public static final int CREATED = 201;
/**
* 请求已经被接受
*/
public static final int ACCEPTED = 202;
/**
* 操作已经执行成功但是没有返回数据
*/
public static final int NO_CONTENT = 204;
/**
* 资源已被移除
*/
public static final int MOVED_PERM = 301;
/**
* 重定向
*/
public static final int SEE_OTHER = 303;
/**
* 资源没有被修改
*/
public static final int NOT_MODIFIED = 304;
/**
* 参数列表错误缺少格式不匹配
*/
public static final int BAD_REQUEST = 400;
/**
* 未授权
*/
public static final int UNAUTHORIZED = 401;
/**
* 访问受限授权过期
*/
public static final int FORBIDDEN = 403;
/**
* 资源服务未找到
*/
public static final int NOT_FOUND = 404;
/**
* 不允许的http方法
*/
public static final int BAD_METHOD = 405;
/**
* 资源冲突或者资源被锁
*/
public static final int CONFLICT = 409;
/**
* 不支持的数据媒体类型
*/
public static final int UNSUPPORTED_TYPE = 415;
/**
* 系统内部错误
*/
public static final int ERROR = 500;
/**
* 接口未实现
*/
public static final int NOT_IMPLEMENTED = 501;
/**
* 系统警告消息
*/
public static final int WARN = 601;
}

View File

@ -0,0 +1,66 @@
package com.huangge1199.controller;
import com.huangge1199.base.R;
import com.huangge1199.domain.UserTabComments;
import com.huangge1199.service.IDatabaseService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* DatabaseController
*
* @author huangge1199
* @since 2025/3/12 10:16:42
*/
@Api("数据库可视化")
@RestController
@RequestMapping("/database")
public class DatabaseController{
@Resource
private IDatabaseService databaseService;
@ApiOperation("获取数据库所有表名称")
@GetMapping("/listAllTable")
public
R<List<UserTabComments>> listAllTable()
{
List<UserTabComments> tableList = databaseService.listAllTable();
return R.ok(tableList);
}
@ApiOperation("根据表名获取表中所有字段")
@GetMapping("/listColByTable")
public
R<List<UserTabComments>> listColByTable(String tableName)
{
List<UserTabComments> tableList = databaseService.listColByTable(tableName);
return R.ok(tableList);
}
@ApiOperation("根据SQL进行查询")
@GetMapping("/executeQuery")
public
R<List<Map<String,String>>> getQuery(String sql)
{
List<Map<String,String>> resultList = databaseService.executeQuery(sql);
return R.ok(resultList);
}
@ApiOperation("根据表达式计算结果")
@PostMapping("/evaluate")
public R<Double> evaluate(@RequestBody String expression)
{
double result = 0;
try {
result = databaseService.evaluate(expression);
} catch (Exception e) {
return R.fail(e.getMessage());
}
return R.ok(result);
}
}

View File

@ -0,0 +1,28 @@
package com.huangge1199.dao;
import com.huangge1199.domain.UserTabComments;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* DatabaseDao
*
* @author huangge1199
* @since 2025/3/12 10:40:31
*/
public interface UserTabCommentsDao extends JpaRepository<UserTabComments,Long> {
@Query(value = "SELECT TABLE_NAME, COMMENTS FROM USER_TAB_COMMENTS WHERE TABLE_NAME NOT LIKE 'BIN$%'" ,nativeQuery = true)
List<UserTabComments> listAllTable();
@Query(value = "SELECT col.column_name AS \"TABLE_NAME\",\n" +
" comm.comments AS \"COMMENTS\"\n" +
"FROM all_tab_columns col\n" +
" LEFT JOIN all_col_comments comm\n" +
" ON col.table_name = comm.table_name\n" +
" AND col.column_name = comm.column_name\n" +
"WHERE col.table_name = ?1",nativeQuery = true)
List<UserTabComments> listColByTable(String tableName);
}

View File

@ -0,0 +1,27 @@
package com.huangge1199.domain;
import lombok.Data;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* UserTable
*
* @author huangge1199
* @since 2025/3/12 11:05:20
*/
@Data
@Entity
@Table(name = "USER_TAB_COMMENTS")
public class UserTabComments {
@Id
@Column(name = "TABLE_NAME")
private String name;
@Column(name = "COMMENTS")
private String comments;
}

View File

@ -0,0 +1,22 @@
package com.huangge1199.service;
import com.huangge1199.domain.UserTabComments;
import java.util.List;
import java.util.Map;
/**
* IDatabaseService
*
* @author huangge1199
* @since 2025/3/12 10:19:54
*/
public interface IDatabaseService {
List<UserTabComments> listAllTable();
List<UserTabComments> listColByTable(String tableName);
List<Map<String,String>> executeQuery(String sql);
double evaluate(String expression) throws Exception;
}

View File

@ -0,0 +1,85 @@
package com.huangge1199.service.impl;
import com.huangge1199.dao.UserTabCommentsDao;
import com.huangge1199.domain.UserTabComments;
import com.huangge1199.service.IDatabaseService;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.util.*;
/**
* DatabaseServiceImpl
*
* @author huangge1199
* @since 2025/3/12 10:20:33
*/
@Service
public class DatabaseServiceImpl implements IDatabaseService {
@Resource
private UserTabCommentsDao databaseDao;
@PersistenceContext
private EntityManager entityManager;
@Override
public List<UserTabComments> listAllTable() {
return databaseDao.listAllTable();
}
@Override
public List<UserTabComments> listColByTable(String tableName) {
return databaseDao.listColByTable(tableName);
}
@Override
public List<Map<String, String>> executeQuery(String sql) {
String cols = sql.substring(sql.toLowerCase().indexOf("select") + 6, sql.toLowerCase().lastIndexOf("from"));
String[] colArr = cols.split(",");
for (int i = 0; i < colArr.length; i++) {
String col = colArr[i];
if (col.toLowerCase().contains("as")) {
if (col.contains("\"")) {
col = col.substring(col.indexOf("\"") + 1, col.lastIndexOf("\""));
} else if (col.contains("'")) {
col = col.substring(col.indexOf("'") + 1, col.lastIndexOf("'"));
}
}
colArr[i] = col;
}
Query query = entityManager.createNativeQuery(sql);
List<Object[]> resultList = query.getResultList();
List<Map<String, String>> result = new ArrayList<>();
for (Object[] row : resultList) {
Map<String, String> map = new HashMap<>(colArr.length);
for (int i = 0; i < colArr.length; i++) {
map.put(colArr[i], row[i].toString());
}
result.add(map);
}
return result;
}
@Override
public double evaluate(String expression) throws Exception {
expression = expression.replaceAll(" ","");
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
double result = 0;
try {
result = Double.parseDouble(engine.eval(expression).toString());
System.out.println("计算结果: " + result);
} catch (ScriptException e) {
System.out.println(e.getMessage());
throw new Exception("表达式错误");
}
return result;
}
}

View File

@ -0,0 +1,61 @@
# 数据源配置
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
driverClassName: oracle.jdbc.driver.OracleDriver
druid:
# 主库数据源
master:
url: jdbc:oracle:thin:@192.168.188.2:1521/ruoyi
username: ruoyi
password: ruoyi
# 从库数据源
slave:
# 从数据源开关/默认关闭
enabled: false
url:
username:
password:
# 初始连接数
initialSize: 5
# 最小连接池数量
minIdle: 10
# 最大连接池数量
maxActive: 20
# 配置获取连接等待超时的时间
maxWait: 60000
# 配置连接超时时间
connectTimeout: 30000
# 配置网络超时时间
socketTimeout: 60000
# 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis: 60000
# 配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis: 300000
# 配置一个连接在池中最大生存的时间,单位是毫秒
maxEvictableIdleTimeMillis: 900000
# 配置检测连接是否有效
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
webStatFilter:
enabled: true
statViewServlet:
enabled: true
# 设置白名单,不填则允许所有访问
allow:
url-pattern: /druid/*
# 控制台管理用户名和密码
login-username: ruoyi
login-password: 123456
filter:
stat:
enabled: true
# 慢SQL记录
log-slow-sql: true
slow-sql-millis: 1000
merge-sql: false
wall:
config:
multi-statement-allow: true

View File

@ -0,0 +1,70 @@
# 开发环境配置
server:
# 服务器的HTTP端口默认为8080
port: 8081
servlet:
# 应用的访问路径
context-path: /
tomcat:
# tomcat的URI编码
uri-encoding: UTF-8
# 连接数满后的排队数默认为100
accept-count: 1000
threads:
# tomcat最大线程数默认为200
max: 800
# Tomcat启动初始化的线程数默认值10
min-spare: 100
# Spring配置
spring:
# 资源信息
messages:
# 国际化资源文件路径
basename: i18n/messages
profiles:
active: druid
jpa:
database-platform: org.hibernate.dialect.Oracle12cDialect
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
format_sql: true
use_sql_comments: true
mvc:
pathmatch:
matching-strategy: ant_path_matcher
springdoc:
api-docs:
enabled: true
swagger-ui:
enabled: true
path: /swagger-ui.html # 访问路径
operationsSorter: method # 按方法排序
tagsSorter: alpha # 按字母排序
disable-swagger-default-url: true # 关闭默认的 Petstore API
doc-expansion: none # 关闭默认展开
knife4j:
enable: true # 开启 Knife4j 增强功能
setting:
language: zh_cn # 设置语言为中文(可选)
# 项目相关配置
sys:
# 名称
name: huangge1199
# 版本
version: 1.0.0
# 版权年份
copyrightYear: 2025
# 文件路径 示例( Windows配置D:/huangge1199/uploadPathLinux配置 /home/huangge1199/uploadPath
profile: D:/huangge1199/uploadPath
# 获取ip地址开关
addressEnabled: false
# 验证码类型 math 数字计算 char 字符验证
captchaType: math