feat: add configurations and utility classes
This commit is contained in:
@@ -44,7 +44,6 @@ dependencies {
|
||||
implementation(libs.spring.boot.starter.validation)
|
||||
implementation(libs.spring.boot.starter.redis)
|
||||
implementation(libs.spring.boot.starter.cache)
|
||||
implementation(libs.spring.boot.starter.security)
|
||||
implementation(libs.spring.boot.starter.jpa)
|
||||
implementation(libs.mybatis.starter.core)
|
||||
implementation(libs.flyway.core)
|
||||
@@ -52,9 +51,7 @@ dependencies {
|
||||
implementation(libs.jackson.jsr310)
|
||||
testImplementation(libs.spring.boot.starter.test)
|
||||
testImplementation(libs.reactor.test)
|
||||
testImplementation(libs.spring.security.test)
|
||||
testImplementation(libs.mybatis.starter.test)
|
||||
// runtimeOnly(libs.postgres.driver)
|
||||
runtimeOnly(libs.mysql.driver)
|
||||
testRuntimeOnly(libs.h2.database)
|
||||
testRuntimeOnly(libs.junit.launcher)
|
||||
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.onixbyte.deltaforceguide.config;
|
||||
|
||||
import com.onixbyte.deltaforceguide.shared.JacksonRedisSerialiser;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
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.core.RedisTemplate;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
import org.springframework.data.redis.serializer.RedisSerializer;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
/**
|
||||
* Configuration class for Redis-based caching components.
|
||||
* <p>
|
||||
* This configuration class provides beans for Redis cache management and template operations
|
||||
* within the Helix application. It configures custom serialisation strategies using
|
||||
* {@link GenericJackson2JsonRedisSerializer} for values and string serialisation for keys,
|
||||
* ensuring optimal performance and compatibility with JSON-based data structures.
|
||||
* <p>
|
||||
* The configuration includes:
|
||||
* <ul>
|
||||
* <li>Custom {@link RedisCacheManager} with JSON serialisation support</li>
|
||||
* <li>Configured {@link RedisTemplate} for direct Redis operations</li>
|
||||
* </ul>
|
||||
*
|
||||
* @author zihluwang
|
||||
* @see RedisCacheManager
|
||||
* @see RedisTemplate
|
||||
* @see GenericJackson2JsonRedisSerializer
|
||||
* @since 1.0.0
|
||||
*/
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class CacheConfig {
|
||||
|
||||
/**
|
||||
* Creates a custom Redis cache manager with JSON serialisation support.
|
||||
* <p>
|
||||
* This method configures a {@link RedisCacheManager} that uses string serialisation for cache
|
||||
* keys and {@link GenericJackson2JsonRedisSerializer} for cache values. This setup ensures that
|
||||
* complex objects can be stored and retrieved from Redis cache whilst maintaining readability
|
||||
* and compatibility with JSON-based systems.
|
||||
*
|
||||
* @param connectionFactory the Redis connection factory used to establish connections
|
||||
* @return a configured {@link RedisCacheManager} with custom serialisation settings
|
||||
* @see RedisCacheManager
|
||||
* @see GenericJackson2JsonRedisSerializer
|
||||
* @see RedisSerializationContext
|
||||
*/
|
||||
@Bean
|
||||
public RedisCacheManager cacheManager(
|
||||
RedisConnectionFactory connectionFactory
|
||||
) {
|
||||
var _keySerializer = RedisSerializer.string();
|
||||
|
||||
var cacheConfiguration = RedisCacheConfiguration.defaultCacheConfig()
|
||||
.serializeKeysWith(RedisSerializationContext.SerializationPair
|
||||
.fromSerializer(_keySerializer))
|
||||
.serializeValuesWith(RedisSerializationContext.SerializationPair
|
||||
.fromSerializer(JacksonRedisSerialiser.INSTANCE))
|
||||
.entryTtl(Duration.ofMinutes(90L));
|
||||
|
||||
return RedisCacheManager.RedisCacheManagerBuilder
|
||||
.fromConnectionFactory(connectionFactory)
|
||||
.cacheDefaults(cacheConfiguration)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a Redis template for direct Redis operations with custom serialisation.
|
||||
* <p>
|
||||
* This method configures a {@link RedisTemplate} that uses string serialisation for keys
|
||||
* and {@link GenericJackson2JsonRedisSerializer} for values. This template provides low-level
|
||||
* access to Redis operations whilst ensuring consistent serialisation strategies across
|
||||
* the application.
|
||||
* <p>
|
||||
* The template is fully configured and ready for use after bean creation.
|
||||
*
|
||||
* @param connectionFactory the Redis connection factory used to establish connections
|
||||
* @return a fully configured {@link RedisTemplate} for Redis operations
|
||||
* @see RedisTemplate
|
||||
* @see GenericJackson2JsonRedisSerializer
|
||||
* @see RedisSerializer
|
||||
*/
|
||||
@Bean
|
||||
public RedisTemplate<String, Object> redisTemplate(
|
||||
RedisConnectionFactory connectionFactory
|
||||
) {
|
||||
var redisTemplate = new RedisTemplate<String, Object>();
|
||||
redisTemplate.setConnectionFactory(connectionFactory);
|
||||
redisTemplate.setKeySerializer(RedisSerializer.string());
|
||||
redisTemplate.setValueSerializer(JacksonRedisSerialiser.INSTANCE);
|
||||
redisTemplate.afterPropertiesSet();
|
||||
return redisTemplate;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.onixbyte.deltaforceguide.config;
|
||||
|
||||
import com.onixbyte.deltaforceguide.properties.CorsProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties({CorsProperties.class})
|
||||
public class CorsConfig implements WebMvcConfigurer {
|
||||
|
||||
private final CorsProperties properties;
|
||||
|
||||
public CorsConfig(CorsProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins(properties.allowedOrigins())
|
||||
.allowedHeaders(properties.allowedHeaders())
|
||||
.allowedMethods(toHttpMethodNames(properties.allowedMethods()))
|
||||
.allowCredentials(properties.allowCredentials())
|
||||
.maxAge(properties.maxAge().toSeconds())
|
||||
.exposedHeaders(properties.exposedHeaders());
|
||||
}
|
||||
|
||||
private static String[] toHttpMethodNames(HttpMethod[] methods) {
|
||||
return Optional.ofNullable(methods)
|
||||
.stream()
|
||||
.flatMap(Stream::of)
|
||||
.map(HttpMethod::name)
|
||||
.toList()
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.onixbyte.deltaforceguide.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.onixbyte.deltaforceguide.shared.JacksonModules;
|
||||
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class JacksonConfig {
|
||||
|
||||
@Bean
|
||||
public Jackson2ObjectMapperBuilderCustomizer jacksonCustomiser() {
|
||||
return (builder) -> {
|
||||
builder.modules(JacksonModules.DATE_TIME_MODULE);
|
||||
builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.onixbyte.deltaforceguide.config;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@MapperScan(basePackages = {"com.onixbyte.deltaforceguide.mapper"})
|
||||
public class MyBatisConfig {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.onixbyte.deltaforceguide.config;
|
||||
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
|
||||
@Configuration
|
||||
@EnableJpaRepositories(basePackages = {"com.onixbyte.deltaforceguide.repository"})
|
||||
public class SpringDataConfig {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.onixbyte.deltaforceguide.properties;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.bind.DefaultValue;
|
||||
import org.springframework.http.HttpMethod;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@ConfigurationProperties(prefix = "app.cors")
|
||||
public record CorsProperties(
|
||||
@DefaultValue({"Content-Type", "Authorization"})
|
||||
String[] allowedHeaders,
|
||||
@DefaultValue({"GET", "POST", "PUT", "PATCH", "DELETE"})
|
||||
HttpMethod[] allowedMethods,
|
||||
String[] allowedOrigins,
|
||||
boolean allowCredentials,
|
||||
boolean allowPrivateNetwork,
|
||||
@DefaultValue("PT2H")
|
||||
Duration maxAge,
|
||||
@DefaultValue({"Content-Type", "Authorization"})
|
||||
String[] exposedHeaders
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.onixbyte.deltaforceguide.shared;
|
||||
|
||||
import java.time.format.DateTimeFormatter;
|
||||
|
||||
/**
|
||||
* Utility class providing predefined {@link DateTimeFormatter} instances for common date and
|
||||
* time patterns. These formatters can be used to parse and format {@code java.time} objects
|
||||
* consistently throughout an application.
|
||||
*
|
||||
* @author zihluwang
|
||||
*/
|
||||
public class DateTimeFormatters {
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} for formatting and parsing full date and time with seconds, using
|
||||
* the pattern "yyyy-MM-dd HH:mm:ss".
|
||||
* <p>
|
||||
* Example: "{@code 2023-10-27 15:30:45}"
|
||||
*/
|
||||
public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} for formatting and parsing dates only, using the
|
||||
* pattern "yyyy-MM-dd".
|
||||
* <p>
|
||||
* Example: "{@code 2023-10-27}"
|
||||
*/
|
||||
public static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} for formatting and parsing times only, using the
|
||||
* pattern "HH:mm:ss".
|
||||
* <p>
|
||||
* Example: "{@code 15:30:45}"
|
||||
*/
|
||||
public static final DateTimeFormatter TIME_FORMATTER = DateTimeFormatter.ofPattern("HH:mm:ss");
|
||||
|
||||
/**
|
||||
* A {@link DateTimeFormatter} for formatting and parsing year and month only, using the
|
||||
* pattern "yyyy-MM".
|
||||
* <p>
|
||||
* Example: "{@code 2023-10}"
|
||||
*/
|
||||
public static final DateTimeFormatter YEAR_MONTH_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.onixbyte.deltaforceguide.shared;
|
||||
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
|
||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.LocalTime;
|
||||
|
||||
public class JacksonModules {
|
||||
|
||||
public static final SimpleModule DATE_TIME_MODULE = initialiseDateTimeModule();
|
||||
|
||||
private static SimpleModule initialiseDateTimeModule() {
|
||||
var javaTimeModule = new JavaTimeModule();
|
||||
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatters.DATE_TIME_FORMATTER));
|
||||
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatters.DATE_TIME_FORMATTER));
|
||||
|
||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatters.DATE_FORMATTER));
|
||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatters.DATE_FORMATTER));
|
||||
|
||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatters.TIME_FORMATTER));
|
||||
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatters.TIME_FORMATTER));
|
||||
|
||||
return javaTimeModule;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.onixbyte.deltaforceguide.shared;
|
||||
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
|
||||
public class JacksonRedisSerialiser {
|
||||
|
||||
public static final GenericJackson2JsonRedisSerializer INSTANCE = initialiseSerializer();
|
||||
|
||||
private static GenericJackson2JsonRedisSerializer initialiseSerializer() {
|
||||
var serializer = new GenericJackson2JsonRedisSerializer();
|
||||
|
||||
serializer.configure((configurer) -> {
|
||||
configurer.registerModule(new JavaTimeModule());
|
||||
configurer.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
|
||||
});
|
||||
|
||||
return serializer;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user