diff --git a/src/main/java/com/waterquality/projectmanagement/ProjectManagementApplication.java b/src/main/java/com/waterquality/projectmanagement/ProjectManagementApplication.java index 2cb50b7..1c83e13 100644 --- a/src/main/java/com/waterquality/projectmanagement/ProjectManagementApplication.java +++ b/src/main/java/com/waterquality/projectmanagement/ProjectManagementApplication.java @@ -2,7 +2,9 @@ package com.waterquality.projectmanagement; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +/* @SpringBootApplication public class ProjectManagementApplication { @@ -11,3 +13,11 @@ public class ProjectManagementApplication { } } +*/ + +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class}) +public class ProjectManagementApplication { + public static void main(String[] args) { + SpringApplication.run(ProjectManagementApplication.class, args); + } +} diff --git a/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java index 5f01173..4d34eaa 100644 --- a/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java +++ b/src/main/java/com/waterquality/projectmanagement/config/SecurityConfig.java @@ -66,6 +66,7 @@ public class SecurityConfig { .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) .authorizeHttpRequests(authz -> authz .requestMatchers("/api/auth/**").permitAll() // 允许认证相关接口无需鉴权 + .requestMatchers("/health").permitAll() // 允许认证相关接口无需鉴权 .requestMatchers("/api/**").authenticated() // 只有 /api/** 下的路由需要鉴权 .requestMatchers("/static/**", "/css/**", "/js/**", "/assets/**", "/favicon.ico").permitAll() // 显式放通静态资源 .requestMatchers("/", "/index.html").permitAll() // 放通 SPA 的入口页面 diff --git a/src/main/java/com/waterquality/projectmanagement/config/database/DataSourceConfig.java b/src/main/java/com/waterquality/projectmanagement/config/database/DataSourceConfig.java new file mode 100644 index 0000000..2d6981d --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/database/DataSourceConfig.java @@ -0,0 +1,58 @@ +package com.waterquality.projectmanagement.config.database; + +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.jdbc.datasource.DataSourceTransactionManager; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.annotation.EnableTransactionManagement; + +import javax.sql.DataSource; +import java.util.HashMap; +import java.util.Map; + +@Configuration +@EnableTransactionManagement +public class DataSourceConfig { + + // 主库数据源 + @Bean(name = "masterDataSource") + @ConfigurationProperties(prefix = "spring.datasource.master") + public DataSource masterDataSource() { + return DataSourceBuilder.create().build(); + } + + // 备库数据源 + @Bean(name = "slaveDataSource") + @ConfigurationProperties(prefix = "spring.datasource.slave") + public DataSource slaveDataSource() { + return DataSourceBuilder.create().build(); + } + + // 动态数据源(主备切换) + @Primary + @Bean(name = "dynamicDataSource") + public DataSource dynamicDataSource( + @Qualifier("masterDataSource") DataSource master, + @Qualifier("slaveDataSource") DataSource slave) { + + DynamicRoutingDataSource dynamicDataSource = new DynamicRoutingDataSource(); + Map dataSourceMap = new HashMap<>(); + dataSourceMap.put("master", master); + dataSourceMap.put("slave", slave); + + // 默认使用主库 + dynamicDataSource.setDefaultTargetDataSource(master); + dynamicDataSource.setTargetDataSources(dataSourceMap); + return dynamicDataSource; + } + + // 配置事务管理器 + @Bean + public PlatformTransactionManager transactionManager(DataSource dynamicDataSource) { + return new DataSourceTransactionManager(dynamicDataSource); + } +} diff --git a/src/main/java/com/waterquality/projectmanagement/config/database/DynamicRoutingDataSource.java b/src/main/java/com/waterquality/projectmanagement/config/database/DynamicRoutingDataSource.java new file mode 100644 index 0000000..e762bb3 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/config/database/DynamicRoutingDataSource.java @@ -0,0 +1,20 @@ +package com.waterquality.projectmanagement.config.database; + +import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class DynamicRoutingDataSource extends AbstractRoutingDataSource { + + private static final AtomicBoolean isMasterAvailable = new AtomicBoolean(true); + + @Override + protected Object determineCurrentLookupKey() { + // 默认路由到主库,若主库不可用则切换到备库 + return isMasterAvailable.get() ? "master" : "slave"; + } + + public static void setMasterAvailable(boolean available) { + isMasterAvailable.set(available); + } +} diff --git a/src/main/java/com/waterquality/projectmanagement/controller/HealthController.java b/src/main/java/com/waterquality/projectmanagement/controller/HealthController.java new file mode 100644 index 0000000..19ed218 --- /dev/null +++ b/src/main/java/com/waterquality/projectmanagement/controller/HealthController.java @@ -0,0 +1,18 @@ +package com.waterquality.projectmanagement.controller; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Collections; +import java.util.Map; + +@RestController +public class HealthController { + @GetMapping("/health") + public ResponseEntity> health() { + // 简单返回 UP 状态 + Map status = Collections.singletonMap("status", "UP"); + return ResponseEntity.ok(status); + } +} \ No newline at end of file