|
23 | 23 | opts.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All); |
24 | 24 | }); |
25 | 25 |
|
26 | | -// SQLite + EF Core(支持 DB_PATH 环境变量,容器部署时指向挂载卷) |
27 | | -var dbPath = Environment.GetEnvironmentVariable("DB_PATH") |
28 | | - ?? Path.Combine(Directory.GetCurrentDirectory(), "juggle.db"); |
29 | | -builder.Services.AddDbContext<JuggleDbContext>(opts => |
30 | | - opts.UseSqlite($"Data Source={dbPath}")); |
| 26 | +// ==================== 数据库配置(支持多种数据库) ==================== |
| 27 | +// 通过环境变量切换:DB_TYPE=sqlite|sqlserver|mysql|postgresql |
| 28 | +// 连接字符串通过:DB_CONNECTION_STRING 或各数据库专属变量设置 |
| 29 | +var dbType = (Environment.GetEnvironmentVariable("DB_TYPE") ?? "sqlite").ToLower(); |
| 30 | +var dbConnStr = Environment.GetEnvironmentVariable("DB_CONNECTION_STRING"); |
| 31 | + |
| 32 | +void ConfigureDbContext(DbContextOptionsBuilder opts) |
| 33 | +{ |
| 34 | + switch (dbType) |
| 35 | + { |
| 36 | + case "sqlserver" or "mssql": |
| 37 | + var sqlServerConn = dbConnStr |
| 38 | + ?? $"Server={Env("DB_HOST","localhost")},{Env("DB_PORT","1433")};Database={Env("DB_NAME","juggle")};User Id={Env("DB_USER","sa")};Password={Env("DB_PASS","Juggle@2026")};TrustServerCertificate=True;"; |
| 39 | + opts.UseSqlServer(sqlServerConn); |
| 40 | + break; |
| 41 | + case "mysql": |
| 42 | + var mysqlConn = dbConnStr |
| 43 | + ?? $"Server={Env("DB_HOST","localhost")};Port={Env("DB_PORT","3306")};Database={Env("DB_NAME","juggle")};User={Env("DB_USER","root")};Password={Env("DB_PASS","juggle")};CharSet=utf8mb4;"; |
| 44 | + opts.UseMySql(mysqlConn, ServerVersion.AutoDetect(mysqlConn), |
| 45 | + mySql => { mySql.EnableRetryOnFailure(3); }); |
| 46 | + break; |
| 47 | + case "postgresql" or "postgres": |
| 48 | + var pgConn = dbConnStr |
| 49 | + ?? $"Host={Env("DB_HOST","localhost")};Port={Env("DB_PORT","5432")};Database={Env("DB_NAME","juggle")};Username={Env("DB_USER","postgres")};Password={Env("DB_PASS","juggle")};"; |
| 50 | + opts.UseNpgsql(pgConn); |
| 51 | + break; |
| 52 | + default: // sqlite |
| 53 | + var dbPath = dbConnStr |
| 54 | + ?? Environment.GetEnvironmentVariable("DB_PATH") |
| 55 | + ?? Path.Combine(Directory.GetCurrentDirectory(), "juggle.db"); |
| 56 | + opts.UseSqlite($"Data Source={dbPath}"); |
| 57 | + break; |
| 58 | + } |
| 59 | +} |
| 60 | + |
| 61 | +// 临时辅助函数 |
| 62 | +static string Env(string key, string defaultValue) => Environment.GetEnvironmentVariable(key) ?? defaultValue; |
| 63 | + |
| 64 | +/// <summary>隐藏连接字符串中的密码部分</summary> |
| 65 | +static string MaskPassword(string connStr) |
| 66 | +{ |
| 67 | + if (string.IsNullOrEmpty(connStr)) return connStr; |
| 68 | + return System.Text.RegularExpressions.Regex.Replace( |
| 69 | + connStr, |
| 70 | + @"(Password|PWD|User Id.*?Password)\s*=\s*[^;]+", |
| 71 | + m => m.Value.Contains('=') ? m.Value.Substring(0, m.Value.IndexOf('=') + 1) + "***" : m.Value, |
| 72 | + System.Text.RegularExpressions.RegexOptions.IgnoreCase |
| 73 | + ); |
| 74 | +} |
| 75 | + |
| 76 | +builder.Services.AddDbContext<JuggleDbContext>(ConfigureDbContext); |
| 77 | + |
| 78 | +// 如果不是 SQLite,则需要在启动时确保数据库已迁移 |
| 79 | +// SQLite 使用 EnsureCreated,其他数据库使用 Migrate 或 EnsureCreated |
31 | 80 |
|
32 | 81 | // JWT 认证 |
33 | 82 | var jwtKey = builder.Configuration["Jwt:Key"] ?? "JuggleNet6SecretKey2026!"; |
@@ -116,98 +165,26 @@ await ctx.Response.WriteAsync( |
116 | 165 | // ==================== 应用构建 ==================== |
117 | 166 | var app = builder.Build(); |
118 | 167 |
|
119 | | -// 自动迁移数据库:EnsureCreated 仅在首次创建时建表 |
120 | | -// 对于已存在的数据库,补建后续迭代新增的表(幂等 CREATE TABLE IF NOT EXISTS) |
| 168 | +// 启动日志:显示数据库类型 |
| 169 | +Console.WriteLine($"[Juggle] 系统数据库类型: {dbType.ToUpper()}"); |
| 170 | +if (!string.IsNullOrEmpty(dbConnStr)) |
| 171 | + Console.WriteLine($"[Juggle] 连接字符串: {MaskPassword(dbConnStr)}"); |
| 172 | + |
| 173 | +// ==================== 数据库初始化 ==================== |
| 174 | +// SQLite: EnsureCreated 自动建表 |
| 175 | +// SQLServer/MySQL/PostgreSQL: EnsureCreated 自动建表(生产环境建议改用 Migration) |
121 | 176 | using (var scope = app.Services.CreateScope()) |
122 | 177 | { |
123 | 178 | var db = scope.ServiceProvider.GetRequiredService<JuggleDbContext>(); |
124 | 179 | db.Database.EnsureCreated(); |
125 | 180 |
|
126 | | - // 补建迭代四新增的三张表(若已存在则跳过) |
127 | | - db.Database.ExecuteSqlRaw(@" |
128 | | -CREATE TABLE IF NOT EXISTS t_flow_log ( |
129 | | - id INTEGER PRIMARY KEY AUTOINCREMENT, |
130 | | - deleted INTEGER NOT NULL DEFAULT 0, |
131 | | - created_at TEXT, |
132 | | - created_by TEXT, |
133 | | - updated_at TEXT, |
134 | | - updated_by TEXT, |
135 | | - flow_key TEXT, |
136 | | - flow_name TEXT, |
137 | | - version INTEGER, |
138 | | - trigger_type TEXT, |
139 | | - status TEXT, |
140 | | - start_time TEXT, |
141 | | - end_time TEXT, |
142 | | - cost_ms INTEGER, |
143 | | - error_message TEXT, |
144 | | - input_json TEXT, |
145 | | - output_json TEXT |
146 | | -);"); |
147 | | - |
148 | | - db.Database.ExecuteSqlRaw(@" |
149 | | -CREATE TABLE IF NOT EXISTS t_flow_node_log ( |
150 | | - id INTEGER PRIMARY KEY AUTOINCREMENT, |
151 | | - deleted INTEGER NOT NULL DEFAULT 0, |
152 | | - created_at TEXT, |
153 | | - created_by TEXT, |
154 | | - updated_at TEXT, |
155 | | - updated_by TEXT, |
156 | | - flow_log_id INTEGER, |
157 | | - node_key TEXT, |
158 | | - node_label TEXT, |
159 | | - node_type TEXT, |
160 | | - seq_no INTEGER, |
161 | | - status TEXT, |
162 | | - start_time TEXT, |
163 | | - end_time TEXT, |
164 | | - cost_ms INTEGER, |
165 | | - input_snapshot TEXT, |
166 | | - output_snapshot TEXT, |
167 | | - detail TEXT, |
168 | | - error_message TEXT |
169 | | -);"); |
170 | | - |
171 | | - db.Database.ExecuteSqlRaw(@" |
172 | | -CREATE TABLE IF NOT EXISTS t_static_variable ( |
173 | | - id INTEGER PRIMARY KEY AUTOINCREMENT, |
174 | | - deleted INTEGER NOT NULL DEFAULT 0, |
175 | | - created_at TEXT, |
176 | | - created_by TEXT, |
177 | | - updated_at TEXT, |
178 | | - updated_by TEXT, |
179 | | - var_code TEXT NOT NULL, |
180 | | - var_name TEXT, |
181 | | - data_type TEXT, |
182 | | - value TEXT, |
183 | | - default_value TEXT, |
184 | | - description TEXT, |
185 | | - group_name TEXT |
186 | | -);"); |
187 | | - |
188 | | - // 补建流程定义分组字段 |
189 | | - try { db.Database.ExecuteSqlRaw("ALTER TABLE t_flow_definition ADD COLUMN group_name TEXT DEFAULT NULL;"); } |
190 | | - catch { /* 列已存在则忽略 */ } |
191 | | - |
192 | | - // 补建定时任务表 |
193 | | - db.Database.ExecuteSqlRaw(@" |
194 | | -CREATE TABLE IF NOT EXISTS t_schedule_task ( |
195 | | - id INTEGER PRIMARY KEY AUTOINCREMENT, |
196 | | - deleted INTEGER NOT NULL DEFAULT 0, |
197 | | - created_at TEXT, |
198 | | - created_by TEXT, |
199 | | - updated_at TEXT, |
200 | | - updated_by TEXT, |
201 | | - flow_key TEXT, |
202 | | - flow_name TEXT, |
203 | | - cron_expression TEXT, |
204 | | - input_json TEXT, |
205 | | - status INTEGER NOT NULL DEFAULT 0, |
206 | | - last_run_time TEXT, |
207 | | - last_run_status TEXT, |
208 | | - next_run_time TEXT, |
209 | | - run_count INTEGER NOT NULL DEFAULT 0 |
210 | | -);"); |
| 181 | + // 补建迭代新增字段/表(仅 SQLite 需要手动 ALTER TABLE,其他数据库由 Migration 处理) |
| 182 | + if (dbType == "sqlite") |
| 183 | + { |
| 184 | + // 补建流程定义分组字段 |
| 185 | + try { db.Database.ExecuteSqlRaw("ALTER TABLE t_flow_definition ADD COLUMN group_name TEXT DEFAULT NULL;"); } |
| 186 | + catch { /* 列已存在则忽略 */ } |
| 187 | + } |
211 | 188 | } |
212 | 189 |
|
213 | 190 | if (app.Environment.IsDevelopment()) |
|
0 commit comments