feat(browser): 添加数据库管理工具和JS对话框处理- 实现了浏览器窗口中的JavaScript alert弹窗拦截与处理
- 添加了数据库连接管理器,支持多种数据库类型(MySQL、PostgreSQL、SQLite、Oracle、H2) - 开发了数据库管理工具的前端界面,包含连接配置、查询编辑器和结果展示 - 支持本地数据库创建与示例数据初始化 - 提供了数据库表结构管理和基础SQL执行功能- 增加了暗色主题切换和响应式布局设计 - 集成了事件日志面板用于调试和状态跟踪
This commit is contained in:
@@ -6,33 +6,121 @@ import org.apache.logging.log4j.Logger;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 将输出传递给 Log4j2 的日志记录器
|
||||
* 将输出传递给 Log4j2 的日志记录器,同时保持控制台输出
|
||||
* 修复问题:控制台输出被Log4j2覆盖
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class Log4j2OutputStream extends OutputStream {
|
||||
private static final Logger logger = LogManager.getLogger();
|
||||
|
||||
// 恢复静态变量
|
||||
public static final ByteArrayOutputStream systemOutContent = new ByteArrayOutputStream();
|
||||
public static final ByteArrayOutputStream systemErrContent = new ByteArrayOutputStream();
|
||||
|
||||
private final ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
private final boolean isErrorStream;
|
||||
private final PrintStream originalStream; // 保存原始的控制台流
|
||||
|
||||
public Log4j2OutputStream(boolean isErrorStream, PrintStream originalStream) {
|
||||
this.isErrorStream = isErrorStream;
|
||||
this.originalStream = originalStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(int b) {
|
||||
systemOutContent.write(b);
|
||||
logger.info(String.valueOf((char) b));
|
||||
// 写入原始控制台
|
||||
originalStream.write(b);
|
||||
|
||||
buffer.write(b);
|
||||
// 将内容同时写入对应的静态变量
|
||||
if (isErrorStream) {
|
||||
systemErrContent.write(b);
|
||||
} else {
|
||||
systemOutContent.write(b);
|
||||
}
|
||||
|
||||
// 遇到换行符时刷新缓冲区到日志
|
||||
if (b == '\n') {
|
||||
flush();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] b, int off, int len) {
|
||||
systemOutContent.write(b, off, len);
|
||||
String message = new String(b, off, len).trim();
|
||||
logger.info(message);
|
||||
// 写入原始控制台
|
||||
originalStream.write(b, off, len);
|
||||
|
||||
buffer.write(b, off, len);
|
||||
// 将内容同时写入对应的静态变量
|
||||
if (isErrorStream) {
|
||||
systemErrContent.write(b, off, len);
|
||||
} else {
|
||||
systemOutContent.write(b, off, len);
|
||||
}
|
||||
|
||||
// 检查是否包含换行符
|
||||
for (int i = off; i < off + len; i++) {
|
||||
if (b[i] == '\n') {
|
||||
flush();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flush() {
|
||||
originalStream.flush();
|
||||
|
||||
String message = buffer.toString(StandardCharsets.UTF_8).trim();
|
||||
if (!message.isEmpty()) {
|
||||
if (isErrorStream) {
|
||||
logger.error(message);
|
||||
} else {
|
||||
logger.info(message);
|
||||
}
|
||||
}
|
||||
buffer.reset(); // 清空缓冲区
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
flush();
|
||||
originalStream.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 重定向 System.out 和 System.err 到 Log4j2
|
||||
* 重定向 System.out 和 System.err 到 Log4j2,同时保持控制台输出
|
||||
*/
|
||||
public static void redirectSystemStreams() {
|
||||
System.setOut(new PrintStream(new Log4j2OutputStream(), true));
|
||||
System.setErr(new PrintStream(new Log4j2OutputStream(), true));
|
||||
// 保存原始流
|
||||
PrintStream originalOut = System.out;
|
||||
PrintStream originalErr = System.err;
|
||||
|
||||
// System.out 使用 INFO 级别,同时输出到原始控制台
|
||||
System.setOut(new PrintStream(new Log4j2OutputStream(false, originalOut), true, StandardCharsets.UTF_8));
|
||||
// System.err 使用 ERROR 级别,同时输出到原始控制台
|
||||
System.setErr(new PrintStream(new Log4j2OutputStream(true, originalErr), true, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* 清空静态缓冲区内容
|
||||
*/
|
||||
public static void clearBuffers() {
|
||||
systemOutContent.reset();
|
||||
systemErrContent.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取输出内容
|
||||
*/
|
||||
public static String getSystemOutContent() {
|
||||
return systemOutContent.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
public static String getSystemErrContent() {
|
||||
return systemErrContent.toString(StandardCharsets.UTF_8);
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,11 @@ import org.cef.browser.CefBrowser;
|
||||
import org.cef.browser.CefFrame;
|
||||
import org.cef.browser.CefMessageRouter;
|
||||
import org.cef.callback.CefContextMenuParams;
|
||||
import org.cef.callback.CefJSDialogCallback;
|
||||
import org.cef.callback.CefMenuModel;
|
||||
import org.cef.callback.CefQueryCallback;
|
||||
import org.cef.handler.*;
|
||||
import org.cef.misc.BoolRef;
|
||||
import org.cef.network.CefRequest;
|
||||
|
||||
import javax.swing.*;
|
||||
@@ -425,6 +427,24 @@ public class BrowserWindow extends JFrame {
|
||||
}
|
||||
});
|
||||
|
||||
client.addJSDialogHandler(new CefJSDialogHandlerAdapter() {
|
||||
@Override
|
||||
public boolean onJSDialog(CefBrowser browser, String origin_url, CefJSDialogHandler.JSDialogType dialog_type, String message_text, String default_prompt_text, CefJSDialogCallback callback, BoolRef suppress_message) {
|
||||
if (dialog_type == CefJSDialogHandler.JSDialogType.JSDIALOGTYPE_ALERT) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JOptionPane.showMessageDialog(
|
||||
BrowserWindow.this,
|
||||
message_text,
|
||||
"警告",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
});
|
||||
callback.Continue(true, "");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// 3. 拦截所有新窗口(关键修复点!)
|
||||
|
||||
@@ -11,9 +11,11 @@ import org.cef.browser.CefBrowser;
|
||||
import org.cef.browser.CefFrame;
|
||||
import org.cef.browser.CefMessageRouter;
|
||||
import org.cef.callback.CefContextMenuParams;
|
||||
import org.cef.callback.CefJSDialogCallback;
|
||||
import org.cef.callback.CefMenuModel;
|
||||
import org.cef.callback.CefQueryCallback;
|
||||
import org.cef.handler.*;
|
||||
import org.cef.misc.BoolRef;
|
||||
import org.cef.network.CefRequest;
|
||||
import org.json.JSONObject;
|
||||
|
||||
@@ -432,6 +434,26 @@ public class BrowserWindowJDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
// 添加 alert 弹窗监控处理
|
||||
client.addJSDialogHandler(new CefJSDialogHandlerAdapter() {
|
||||
@Override
|
||||
public boolean onJSDialog(CefBrowser browser, String origin_url, CefJSDialogHandler.JSDialogType dialog_type, String message_text, String default_prompt_text, CefJSDialogCallback callback, BoolRef suppress_message) {
|
||||
if (dialog_type == CefJSDialogHandler.JSDialogType.JSDIALOGTYPE_ALERT) {
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
JOptionPane.showMessageDialog(
|
||||
BrowserWindowJDialog.this,
|
||||
message_text,
|
||||
"警告",
|
||||
JOptionPane.INFORMATION_MESSAGE
|
||||
);
|
||||
});
|
||||
callback.Continue(true, "");
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
// 3. 拦截所有新窗口(关键修复点!)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,397 @@
|
||||
package com.axis.innovators.box.browser.util;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* 数据库连接管理器
|
||||
* @author tzdwindows 7
|
||||
*/
|
||||
public class DatabaseConnectionManager {
|
||||
private static final java.util.Map<String, Connection> connections = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
private static final java.util.Map<String, DatabaseInfo> connectionInfo = new java.util.concurrent.ConcurrentHashMap<>();
|
||||
|
||||
public static class DatabaseInfo {
|
||||
public String driver;
|
||||
public String url;
|
||||
public String host;
|
||||
public String port;
|
||||
public String database;
|
||||
public String username;
|
||||
|
||||
public DatabaseInfo(String driver, String url, String host, String port, String database, String username) {
|
||||
this.driver = driver;
|
||||
this.url = url;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.database = database;
|
||||
this.username = username;
|
||||
}
|
||||
}
|
||||
|
||||
public static String connect(String driver, String host, String port,
|
||||
String database, String username, String password) throws SQLException {
|
||||
String connectionId = "conn_" + System.currentTimeMillis();
|
||||
|
||||
String drv = driver == null ? "" : driver.toLowerCase();
|
||||
|
||||
// 规范化 database 路径(特别是 Windows 反斜杠问题)
|
||||
if (database != null) {
|
||||
database = database.replace("\\", "/");
|
||||
} else {
|
||||
database = "";
|
||||
}
|
||||
|
||||
// 先显式加载驱动,避免因为 classloader 问题找不到驱动
|
||||
try {
|
||||
switch (drv) {
|
||||
case "mysql":
|
||||
Class.forName("com.mysql.cj.jdbc.Driver");
|
||||
break;
|
||||
case "postgresql":
|
||||
Class.forName("org.postgresql.Driver");
|
||||
break;
|
||||
case "sqlite":
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
break;
|
||||
case "oracle":
|
||||
Class.forName("oracle.jdbc.OracleDriver");
|
||||
break;
|
||||
case "h2":
|
||||
Class.forName("org.h2.Driver");
|
||||
break;
|
||||
default:
|
||||
// 不抛出,使后续 URL 构造仍可检查类型
|
||||
}
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new SQLException("JDBC 驱动未找到,请确认对应驱动已加入 classpath: " + e.getMessage(), e);
|
||||
}
|
||||
|
||||
String url = buildConnectionUrl(driver, host, port, database);
|
||||
|
||||
Connection connection;
|
||||
Properties props = new Properties();
|
||||
if (username != null && !username.isEmpty()) props.setProperty("user", username);
|
||||
if (password != null && !password.isEmpty()) props.setProperty("password", password);
|
||||
|
||||
switch (drv) {
|
||||
case "mysql":
|
||||
props.setProperty("useSSL", "false");
|
||||
props.setProperty("serverTimezone", "UTC");
|
||||
connection = DriverManager.getConnection(url, props);
|
||||
break;
|
||||
case "postgresql":
|
||||
connection = DriverManager.getConnection(url, props);
|
||||
break;
|
||||
case "sqlite":
|
||||
// sqlite 不需要 props,URL 已经是文件路径(已做过替换)
|
||||
connection = DriverManager.getConnection(url);
|
||||
break;
|
||||
case "oracle":
|
||||
connection = DriverManager.getConnection(url, props);
|
||||
break;
|
||||
case "h2":
|
||||
// H2 使用默认用户 sa / 空密码(如果需要可调整)
|
||||
connection = DriverManager.getConnection(url, "sa", "");
|
||||
break;
|
||||
default:
|
||||
throw new SQLException("不支持的数据库类型: " + driver);
|
||||
}
|
||||
|
||||
connections.put(connectionId, connection);
|
||||
connectionInfo.put(connectionId, new DatabaseInfo(driver, url, host, port, database, username));
|
||||
return connectionId;
|
||||
}
|
||||
|
||||
public static void disconnect(String connectionId) throws SQLException {
|
||||
Connection connection = connections.get(connectionId);
|
||||
if (connection != null && !connection.isClosed()) {
|
||||
connection.close();
|
||||
}
|
||||
connections.remove(connectionId);
|
||||
connectionInfo.remove(connectionId);
|
||||
}
|
||||
|
||||
public static Connection getConnection(String connectionId) {
|
||||
return connections.get(connectionId);
|
||||
}
|
||||
|
||||
public static DatabaseInfo getConnectionInfo(String connectionId) {
|
||||
return connectionInfo.get(connectionId);
|
||||
}
|
||||
|
||||
private static String buildConnectionUrl(String driver, String host, String port, String database) {
|
||||
String drv = driver == null ? "" : driver.toLowerCase();
|
||||
switch (drv) {
|
||||
case "mysql":
|
||||
return "jdbc:mysql://" + host + ":" + port + "/" + database;
|
||||
case "postgresql":
|
||||
return "jdbc:postgresql://" + host + ":" + port + "/" + database;
|
||||
case "sqlite":
|
||||
// 对于 SQLite,database 可能是绝对路径或相对文件名,先把反斜杠替成正斜杠
|
||||
if (database == null || database.isEmpty()) {
|
||||
return "jdbc:sqlite::memory:";
|
||||
}
|
||||
String normalized = database.replace("\\", "/");
|
||||
// 如果看起来像相对文件名(不含冒号也不以 / 开头),则当作相对于用户目录的路径
|
||||
if (!normalized.contains(":") && !normalized.startsWith("/")) {
|
||||
String userHome = System.getProperty("user.home").replace("\\", "/");
|
||||
normalized = userHome + "/" + normalized;
|
||||
}
|
||||
return "jdbc:sqlite:" + normalized;
|
||||
case "oracle":
|
||||
return "jdbc:oracle:thin:@" + host + ":" + port + ":" + database;
|
||||
case "h2":
|
||||
// H2 文件路径同样做反斜杠处理
|
||||
if (database == null || database.isEmpty()) {
|
||||
String userHome = System.getProperty("user.home").replace("\\", "/");
|
||||
return "jdbc:h2:file:" + userHome + "/.axis_innovators_box/databases/h2db";
|
||||
} else {
|
||||
String norm = database.replace("\\", "/");
|
||||
// 如果传入仅是名字(无斜杠或冒号),则存到用户目录下
|
||||
if (!norm.contains("/") && !norm.contains(":")) {
|
||||
String userHome = System.getProperty("user.home").replace("\\", "/");
|
||||
norm = userHome + "/.axis_innovators_box/databases/" + norm;
|
||||
}
|
||||
return "jdbc:h2:file:" + norm;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("不支持的数据库类型: " + driver);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 在服务器上创建数据库(MySQL / PostgreSQL / Oracle(示例))
|
||||
* @param driver mysql | postgresql | oracle
|
||||
* @param host 数据库主机
|
||||
* @param port 端口
|
||||
* @param dbName 要创建的数据库名(或 schema 名)
|
||||
* @param adminUser 管理员用户名(用于创建数据库)
|
||||
* @param adminPassword 管理员密码
|
||||
* @return 如果创建成功返回一个简短消息,否则抛出 SQLException
|
||||
* @throws SQLException
|
||||
*/
|
||||
public static String createDatabaseOnServer(String driver, String host, String port,
|
||||
String dbName, String adminUser, String adminPassword) throws SQLException {
|
||||
if (driver == null) throw new SQLException("driver 不能为空");
|
||||
String drv = driver.toLowerCase().trim();
|
||||
|
||||
// 简单校验 dbName(避免注入)——只允许字母数字下划线
|
||||
if (dbName == null || !dbName.matches("[A-Za-z0-9_]+")) {
|
||||
throw new SQLException("不合法的数据库名: " + dbName);
|
||||
}
|
||||
|
||||
try {
|
||||
switch (drv) {
|
||||
case "mysql":
|
||||
// 加载驱动(如果尚未加载)
|
||||
try { Class.forName("com.mysql.cj.jdbc.Driver"); } catch (ClassNotFoundException e) {
|
||||
throw new SQLException("MySQL 驱动未找到,请加入 mysql-connector-java 到 classpath", e);
|
||||
}
|
||||
// 连接到服务器的默认库(不指定数据库)以执行 CREATE DATABASE
|
||||
String mysqlUrl = "jdbc:mysql://" + host + ":" + port + "/?useSSL=false&serverTimezone=UTC";
|
||||
try (Connection conn = DriverManager.getConnection(mysqlUrl, adminUser, adminPassword);
|
||||
Statement st = conn.createStatement()) {
|
||||
String sql = "CREATE DATABASE `" + dbName + "` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci";
|
||||
st.executeUpdate(sql);
|
||||
}
|
||||
return "MySQL 数据库创建成功: " + dbName;
|
||||
|
||||
case "postgresql":
|
||||
case "postgres":
|
||||
try { Class.forName("org.postgresql.Driver"); } catch (ClassNotFoundException e) {
|
||||
throw new SQLException("Postgres 驱动未找到,请加入 postgresql 到 classpath", e);
|
||||
}
|
||||
// 连接到默认 postgres 数据库以创建新数据库
|
||||
String pgUrl = "jdbc:postgresql://" + host + ":" + port + "/postgres";
|
||||
try (Connection conn = DriverManager.getConnection(pgUrl, adminUser, adminPassword);
|
||||
Statement st = conn.createStatement()) {
|
||||
String sql = "CREATE DATABASE " + dbName + " WITH ENCODING 'UTF8'";
|
||||
st.executeUpdate(sql);
|
||||
}
|
||||
return "PostgreSQL 数据库创建成功: " + dbName;
|
||||
|
||||
case "oracle":
|
||||
// Oracle 数据库“创建数据库”通常由 DBA 完成(复杂),这里示例创建用户/模式(更常见)
|
||||
try { Class.forName("oracle.jdbc.OracleDriver"); } catch (ClassNotFoundException e) {
|
||||
throw new SQLException("Oracle 驱动未找到,请把 ojdbc.jar 加入 classpath", e);
|
||||
}
|
||||
// 需使用具有足够权限的账户(通常为 sys or system),并且 URL 需要正确(SID / ServiceName)
|
||||
// 下面示例假设通过 SID 连接: jdbc:oracle:thin:@host:port:SID
|
||||
String oracleUrl = "jdbc:oracle:thin:@" + host + ":" + port + ":" + "ORCL"; // 把 ORCL 换成实际 SID
|
||||
try (Connection conn = DriverManager.getConnection(oracleUrl, adminUser, adminPassword);
|
||||
Statement st = conn.createStatement()) {
|
||||
// 创建 user(schema)示例
|
||||
String pwd = adminPassword; // 实际应使用独立密码,不推荐用 adminPassword
|
||||
String createUser = "CREATE USER " + dbName + " IDENTIFIED BY \"" + pwd + "\"";
|
||||
String grant = "GRANT CONNECT, RESOURCE TO " + dbName;
|
||||
st.executeUpdate(createUser);
|
||||
st.executeUpdate(grant);
|
||||
} catch (SQLException ex) {
|
||||
// Oracle 操作更容易失败,给出提示
|
||||
throw new SQLException("Oracle: 无法创建用户/模式,请检查权限和 URL(通常需由 DBA 操作): " + ex.getMessage(), ex);
|
||||
}
|
||||
return "Oracle 用户/模式创建成功(注意:真正的 DB 实例通常由 DBA 管理): " + dbName;
|
||||
|
||||
default:
|
||||
throw new SQLException("不支持的数据库类型: " + driver);
|
||||
}
|
||||
} catch (SQLException se) {
|
||||
// 透传 SQLException,调用方会拿到 message 并反馈给前端
|
||||
throw se;
|
||||
} catch (Exception e) {
|
||||
throw new SQLException("创建数据库时发生异常: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
public static String createLocalDatabase(String driver, String dbName) throws SQLException {
|
||||
switch (driver.toLowerCase()) {
|
||||
case "sqlite":
|
||||
// 创建目录并构造规范化路径(确保路径使用正斜杠)
|
||||
String dbFileName = dbName.endsWith(".db") ? dbName : (dbName + ".db");
|
||||
java.nio.file.Path dbDir = java.nio.file.Paths.get(System.getProperty("user.home"), ".axis_innovators_box", "databases");
|
||||
try {
|
||||
java.nio.file.Files.createDirectories(dbDir);
|
||||
} catch (Exception e) {
|
||||
throw new SQLException("无法创建数据库目录: " + e.getMessage(), e);
|
||||
}
|
||||
String dbPath = dbDir.resolve(dbFileName).toAbsolutePath().toString().replace("\\", "/");
|
||||
|
||||
// 显式加载 sqlite 驱动(避免 No suitable driver)
|
||||
try {
|
||||
Class.forName("org.sqlite.JDBC");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new SQLException("未找到 sqlite 驱动,请确认 sqlite-jdbc 已加入 classpath", e);
|
||||
}
|
||||
|
||||
// 直接使用 connect 构建连接(connect 中会通过 buildConnectionUrl 处理 path)
|
||||
String connectionId = connect("sqlite", "", "", dbPath, "", "");
|
||||
|
||||
// 创建示例表
|
||||
createSampleTables(connectionId);
|
||||
|
||||
return connectionId;
|
||||
|
||||
case "h2":
|
||||
java.nio.file.Path h2Dir = java.nio.file.Paths.get(System.getProperty("user.home"), ".axis_innovators_box", "databases");
|
||||
try {
|
||||
java.nio.file.Files.createDirectories(h2Dir);
|
||||
} catch (Exception e) {
|
||||
throw new SQLException("无法创建数据库目录: " + e.getMessage(), e);
|
||||
}
|
||||
String h2Path = h2Dir.resolve(dbName).toAbsolutePath().toString().replace("\\", "/");
|
||||
String h2Url = "jdbc:h2:file:" + h2Path;
|
||||
|
||||
try {
|
||||
Class.forName("org.h2.Driver");
|
||||
} catch (ClassNotFoundException e) {
|
||||
throw new SQLException("未找到 H2 驱动,请确认 h2.jar 已加入 classpath", e);
|
||||
}
|
||||
|
||||
Connection h2Conn = DriverManager.getConnection(h2Url, "sa", "");
|
||||
String h2ConnectionId = "conn_" + System.currentTimeMillis();
|
||||
connections.put(h2ConnectionId, h2Conn);
|
||||
connectionInfo.put(h2ConnectionId, new DatabaseInfo("h2", h2Url, "localhost", "", dbName, "sa"));
|
||||
|
||||
createSampleTables(h2ConnectionId);
|
||||
|
||||
return h2ConnectionId;
|
||||
|
||||
default:
|
||||
throw new SQLException("不支持创建本地数据库类型: " + driver);
|
||||
}
|
||||
}
|
||||
|
||||
private static void createSampleTables(String connectionId) throws SQLException {
|
||||
Connection conn = getConnection(connectionId);
|
||||
DatabaseInfo info = getConnectionInfo(connectionId);
|
||||
|
||||
if ("sqlite".equals(info.driver) || "h2".equals(info.driver)) {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
// 创建用户表
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS users (" +
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"username VARCHAR(50) NOT NULL UNIQUE, " +
|
||||
"email VARCHAR(100) NOT NULL, " +
|
||||
"password VARCHAR(100) NOT NULL, " +
|
||||
"status VARCHAR(20) DEFAULT 'active', " +
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
|
||||
")");
|
||||
|
||||
// 创建产品表
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS products (" +
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"name VARCHAR(100) NOT NULL, " +
|
||||
"description TEXT, " +
|
||||
"price DECIMAL(10,2) NOT NULL, " +
|
||||
"stock INTEGER DEFAULT 0, " +
|
||||
"category VARCHAR(50), " +
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP" +
|
||||
")");
|
||||
|
||||
// 创建订单表
|
||||
stmt.execute("CREATE TABLE IF NOT EXISTS orders (" +
|
||||
"id INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
"user_id INTEGER, " +
|
||||
"product_id INTEGER, " +
|
||||
"quantity INTEGER NOT NULL, " +
|
||||
"total_price DECIMAL(10,2) NOT NULL, " +
|
||||
"status VARCHAR(20) DEFAULT 'pending', " +
|
||||
"created_at DATETIME DEFAULT CURRENT_TIMESTAMP, " +
|
||||
"FOREIGN KEY (user_id) REFERENCES users(id), " +
|
||||
"FOREIGN KEY (product_id) REFERENCES products(id)" +
|
||||
")");
|
||||
|
||||
// 插入示例数据
|
||||
insertSampleData(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void insertSampleData(Connection conn) throws SQLException {
|
||||
// 检查是否已有数据
|
||||
try (Statement checkStmt = conn.createStatement();
|
||||
ResultSet rs = checkStmt.executeQuery("SELECT COUNT(*) FROM users")) {
|
||||
if (rs.next() && rs.getInt(1) == 0) {
|
||||
// 插入用户数据
|
||||
try (PreparedStatement pstmt = conn.prepareStatement(
|
||||
"INSERT INTO users (username, email, password) VALUES (?, ?, ?)")) {
|
||||
String[][] users = {
|
||||
{"admin", "admin@example.com", "password123"},
|
||||
{"user1", "user1@example.com", "password123"},
|
||||
{"user2", "user2@example.com", "password123"}
|
||||
};
|
||||
|
||||
for (String[] user : users) {
|
||||
pstmt.setString(1, user[0]);
|
||||
pstmt.setString(2, user[1]);
|
||||
pstmt.setString(3, user[2]);
|
||||
pstmt.executeUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
// 插入产品数据
|
||||
try (PreparedStatement pstmt = conn.prepareStatement(
|
||||
"INSERT INTO products (name, description, price, stock, category) VALUES (?, ?, ?, ?, ?)")) {
|
||||
Object[][] products = {
|
||||
{"笔记本电脑", "高性能笔记本电脑", 5999.99, 50, "电子"},
|
||||
{"智能手机", "最新款智能手机", 3999.99, 100, "电子"},
|
||||
{"办公椅", "舒适办公椅", 299.99, 30, "家居"},
|
||||
{"咖啡机", "全自动咖啡机", 899.99, 20, "家电"}
|
||||
};
|
||||
|
||||
for (Object[] product : products) {
|
||||
pstmt.setString(1, (String) product[0]);
|
||||
pstmt.setString(2, (String) product[1]);
|
||||
pstmt.setDouble(3, (Double) product[2]);
|
||||
pstmt.setInt(4, (Integer) product[3]);
|
||||
pstmt.setString(5, (String) product[4]);
|
||||
pstmt.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,32 +43,33 @@ public class RegistrationSettingsItem extends WindowsJDialog {
|
||||
private final AxisInnovatorsBox mainWindow;
|
||||
|
||||
static {
|
||||
RegistrationSettingsItem registrationSettingsItem = new RegistrationSettingsItem();
|
||||
JPanel pluginPanel = createPluginSettingsPanel();
|
||||
JPanel generalPanel = createGeneralSettingsPanel();
|
||||
JPanel aboutPanel = createAboutPanel();
|
||||
JPanel themePanel = createThemePanel();
|
||||
|
||||
registrationSettingsItem.addSettings(
|
||||
generalPanel, language.getText("settings.2.title"),
|
||||
null, language.getText("settings.2.tip"), "system:settings_appearance_item"
|
||||
);
|
||||
registrationSettingsItem.addSettings(
|
||||
pluginPanel, language.getText("settings.1.title"),
|
||||
null, language.getText("settings.1.tip"), "system:settings_plugins_item"
|
||||
);
|
||||
registrationSettingsItem.addSettings(
|
||||
themePanel, language.getText("settings.4.title"),
|
||||
null, language.getText("settings.4.tip"), "system:settings_theme_item"
|
||||
);
|
||||
registrationSettingsItem.addSettings(
|
||||
aboutPanel, language.getText("settings.3.title"),
|
||||
null, language.getText("settings.3.tip"), "system:settings_information_item"
|
||||
);
|
||||
|
||||
registrationSettingsItemList.add(
|
||||
registrationSettingsItem
|
||||
);
|
||||
//RegistrationSettingsItem registrationSettingsItem = new RegistrationSettingsItem();
|
||||
//JPanel pluginPanel = createPluginSettingsPanel();
|
||||
//JPanel generalPanel = createGeneralSettingsPanel();
|
||||
//JPanel aboutPanel = createAboutPanel();
|
||||
//JPanel themePanel = createThemePanel();
|
||||
//
|
||||
//registrationSettingsItem.addSettings(
|
||||
// generalPanel, language.getText("settings.2.title"),
|
||||
// null, language.getText("settings.2.tip"), "system:settings_appearance_item"
|
||||
//);
|
||||
//registrationSettingsItem.addSettings(
|
||||
// pluginPanel, language.getText("settings.1.title"),
|
||||
// null, language.getText("settings.1.tip"), "system:settings_plugins_item"
|
||||
//);
|
||||
//registrationSettingsItem.addSettings(
|
||||
// themePanel, language.getText("settings.4.title"),
|
||||
// null, language.getText("settings.4.tip"), "system:settings_theme_item"
|
||||
//);
|
||||
//registrationSettingsItem.addSettings(
|
||||
// aboutPanel, language.getText("settings.3.title"),
|
||||
// null, language.getText("settings.3.tip"), "system:settings_information_item"
|
||||
//);
|
||||
//
|
||||
//registrationSettingsItemList.add(
|
||||
// registrationSettingsItem
|
||||
//);
|
||||
overloading();
|
||||
}
|
||||
|
||||
public static void overloading() {
|
||||
@@ -624,7 +625,7 @@ public class RegistrationSettingsItem extends WindowsJDialog {
|
||||
MainWindow mainWindow = getMainWindow();
|
||||
if (mainWindow != null) {
|
||||
mainWindow.setBackgroundWithGlassEffect(bgImage, blurAmount,1.0f);
|
||||
logger.info("图片背景已应用,模糊度: " + blurAmount);
|
||||
logger.info("图片背景已应用,模糊度: {}", blurAmount);
|
||||
|
||||
// 保存设置到 StateManager
|
||||
String backgroundPath = (String) backgroundPreview.getClientProperty("backgroundPath");
|
||||
@@ -957,7 +958,7 @@ public class RegistrationSettingsItem extends WindowsJDialog {
|
||||
settingsManager.saveState("background.path", backgroundPath);
|
||||
settingsManager.saveState("background.blur", blurAmount);
|
||||
settingsManager.saveState("background.enabled", true);
|
||||
logger.info("背景设置已保存: " + backgroundPath + ", 模糊度: " + blurAmount);
|
||||
logger.info("背景设置已保存: {}, 模糊度: {}", backgroundPath, blurAmount);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -82,6 +82,16 @@ public class RegistrationTool {
|
||||
}
|
||||
}));
|
||||
|
||||
programmingToolsCategory.addTool(new MainWindow.ToolItem("数据库管理工具", "programming/programming_dark.png",
|
||||
"用于管理数据库" +
|
||||
"\n作者:tzdwindows 7", ++id, new AbstractAction() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
// Window owner = SwingUtilities.windowForComponent((Component) e.getSource());
|
||||
MainApplication.popupDataBaseWindow();
|
||||
}
|
||||
}));
|
||||
|
||||
MainWindow.ToolCategory aICategory = new MainWindow.ToolCategory("AI工具",
|
||||
"ai/ai.png",
|
||||
"人工智能/大语言模型");
|
||||
|
||||
@@ -938,7 +938,15 @@ public class MainWindow extends JFrame {
|
||||
|
||||
// ---------- 工具卡/面板 ----------
|
||||
private JPanel createToolsPanel(ToolCategory category) {
|
||||
JPanel panel = new JPanel(new WrapLayout(FlowLayout.LEFT, 16, 16));
|
||||
JPanel panel = new JPanel(new WrapLayout(FlowLayout.LEFT, 16, 16)) {
|
||||
@Override
|
||||
public Dimension getPreferredSize() {
|
||||
// 计算容器宽度以恰好容纳3个卡片和间隙
|
||||
int cardWidth = 240; // 卡片宽度
|
||||
int gap = 16;
|
||||
return new Dimension(cardWidth * 3 + gap * 2, super.getPreferredSize().height);
|
||||
}
|
||||
};
|
||||
panel.setOpaque(false);
|
||||
panel.setBorder(null);
|
||||
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
BIN
src/main/resources/icons/programming/database.png
Normal file
BIN
src/main/resources/icons/programming/database.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
src/main/resources/icons/programming/database_dark.png
Normal file
BIN
src/main/resources/icons/programming/database_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 16 KiB |
Reference in New Issue
Block a user