diff --git a/pom.xml b/pom.xml
index 41a8dcf..0bd87c9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,11 +65,7 @@
true
-
- javax.annotation
- javax.annotation-api
- 1.3.2
-
+
@@ -110,4 +106,33 @@
+
+
+ coverage
+
+
+
+ org.jacoco
+ jacoco-maven-plugin
+ 0.8.10
+
+
+
+ prepare-agent
+
+
+
+ report
+ verify
+
+ report
+
+
+
+
+
+
+
+
+
diff --git a/src/main/java/com/mosquito/project/config/CacheConfig.java b/src/main/java/com/mosquito/project/config/CacheConfig.java
new file mode 100644
index 0000000..8017220
--- /dev/null
+++ b/src/main/java/com/mosquito/project/config/CacheConfig.java
@@ -0,0 +1,34 @@
+package com.mosquito.project.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializationContext;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class CacheConfig {
+
+ @Bean
+ public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
+ RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
+ .entryTtl(Duration.ofMinutes(5))
+ .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
+ new JdkSerializationRedisSerializer()
+ ));
+
+ Map cacheConfigs = new HashMap<>();
+ cacheConfigs.put("leaderboards", defaultConfig.entryTtl(Duration.ofMinutes(5)));
+
+ return RedisCacheManager.builder(connectionFactory)
+ .cacheDefaults(defaultConfig)
+ .withInitialCacheConfigurations(cacheConfigs)
+ .build();
+ }
+}
diff --git a/src/main/java/com/mosquito/project/service/ActivityService.java b/src/main/java/com/mosquito/project/service/ActivityService.java
index 9a47286..b7a7539 100644
--- a/src/main/java/com/mosquito/project/service/ActivityService.java
+++ b/src/main/java/com/mosquito/project/service/ActivityService.java
@@ -42,6 +42,12 @@ public class ActivityService {
private final Map apiKeys = new ConcurrentHashMap<>();
private final AtomicLong apiKeyIdCounter = new AtomicLong();
+ private final DelayProvider delayProvider;
+
+ public ActivityService(DelayProvider delayProvider) {
+ this.delayProvider = delayProvider;
+ }
+
public Activity createActivity(CreateActivityRequest request) {
if (request.getEndTime().isBefore(request.getStartTime())) {
throw new InvalidActivityDataException("活动结束时间不能早于开始时间。");
@@ -116,12 +122,15 @@ public class ActivityService {
}
private String hashApiKey(String apiKey, byte[] salt) {
+ // Strengthen hashing using PBKDF2WithHmacSHA256
try {
- MessageDigest md = MessageDigest.getInstance("SHA-256");
- md.update(salt);
- byte[] hashedApiKey = md.digest(apiKey.getBytes(StandardCharsets.UTF_8));
- return Base64.getEncoder().encodeToString(hashedApiKey);
- } catch (NoSuchAlgorithmException e) {
+ javax.crypto.SecretKeyFactory skf = javax.crypto.SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
+ javax.crypto.spec.PBEKeySpec spec = new javax.crypto.spec.PBEKeySpec(
+ apiKey.toCharArray(), salt, 185000, 256
+ );
+ byte[] derived = skf.generateSecret(spec).getEncoded();
+ return Base64.getEncoder().encodeToString(derived);
+ } catch (Exception e) {
throw new RuntimeException("无法创建API密钥哈希", e);
}
}
@@ -211,8 +220,7 @@ public class ActivityService {
// Simulate fetching and ranking data
log.info("正在为活动ID {} 生成排行榜...", activityId);
try {
- // Simulate database query delay
- Thread.sleep(2000);
+ delayProvider.delayMillis(2000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
diff --git a/src/main/java/com/mosquito/project/service/DelayProvider.java b/src/main/java/com/mosquito/project/service/DelayProvider.java
new file mode 100644
index 0000000..07d3028
--- /dev/null
+++ b/src/main/java/com/mosquito/project/service/DelayProvider.java
@@ -0,0 +1,6 @@
+package com.mosquito.project.service;
+
+public interface DelayProvider {
+ void delayMillis(long millis) throws InterruptedException;
+}
+
diff --git a/src/main/java/com/mosquito/project/service/NoOpDelayProvider.java b/src/main/java/com/mosquito/project/service/NoOpDelayProvider.java
new file mode 100644
index 0000000..ad5f743
--- /dev/null
+++ b/src/main/java/com/mosquito/project/service/NoOpDelayProvider.java
@@ -0,0 +1,12 @@
+package com.mosquito.project.service;
+
+import org.springframework.stereotype.Component;
+
+@Component
+public class NoOpDelayProvider implements DelayProvider {
+ @Override
+ public void delayMillis(long millis) {
+ // no-op by default to avoid blocking
+ }
+}
+
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..112b060
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,10 @@
+spring:
+ profiles:
+ active: dev
+ redis:
+ host: localhost
+ port: ${spring.redis.port:6379}
+logging:
+ level:
+ root: INFO
+
diff --git a/src/main/resources/application-prod.yml b/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..7d868e7
--- /dev/null
+++ b/src/main/resources/application-prod.yml
@@ -0,0 +1,12 @@
+spring:
+ profiles:
+ active: prod
+ redis:
+ host: ${REDIS_HOST:localhost}
+ port: ${REDIS_PORT:6379}
+ flyway:
+ enabled: true
+logging:
+ level:
+ root: INFO
+
diff --git a/src/main/resources/application-test.yml b/src/main/resources/application-test.yml
new file mode 100644
index 0000000..2f91616
--- /dev/null
+++ b/src/main/resources/application-test.yml
@@ -0,0 +1,12 @@
+spring:
+ profiles:
+ active: test
+ redis:
+ host: localhost
+ port: ${spring.redis.port:6379}
+ flyway:
+ enabled: true
+logging:
+ level:
+ root: WARN
+
diff --git a/src/test/java/com/mosquito/project/config/EmbeddedRedisConfiguration.java b/src/test/java/com/mosquito/project/config/EmbeddedRedisConfiguration.java
index c2316f6..7e78455 100644
--- a/src/test/java/com/mosquito/project/config/EmbeddedRedisConfiguration.java
+++ b/src/test/java/com/mosquito/project/config/EmbeddedRedisConfiguration.java
@@ -3,8 +3,8 @@ package com.mosquito.project.config;
import org.springframework.context.annotation.Configuration;
import redis.embedded.RedisServer;
-import javax.annotation.PostConstruct;
-import javax.annotation.PreDestroy;
+import jakarta.annotation.PostConstruct;
+import jakarta.annotation.PreDestroy;
import java.io.IOException;
import java.net.ServerSocket;