Skip to content

Commit

Permalink
feat : Cache 기능 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
hongdosan committed Jan 5, 2024
1 parent 1731896 commit 909344c
Show file tree
Hide file tree
Showing 5 changed files with 137 additions and 34 deletions.
54 changes: 33 additions & 21 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,26 @@ java {
sourceCompatibility = '17'
}

compileJava {
options.compilerArgs << '-parameters'
options.encoding = 'UTF-8'
}

compileTestJava {
options.compilerArgs << '-parameters'
options.encoding = 'UTF-8'
}

ext {
snippetsDir = file('build/generated-snippets')
}

def querydslSrcDir = 'src/main/generated'

clean {
delete file(querydslSrcDir)
}

tasks.withType(JavaCompile) {
options.generatedSourceOutputDirectory = file(querydslSrcDir)
}
Expand Down Expand Up @@ -75,6 +87,9 @@ dependencies {
// Apache Commons Lang 3
implementation 'org.apache.commons:commons-lang3:3.13.0'

// Cache
implementation 'org.springframework.boot:spring-boot-starter-cache'

// Redis
implementation 'org.springframework.boot:spring-boot-starter-data-redis'

Expand Down Expand Up @@ -134,28 +149,25 @@ jacocoTestReport {

afterEvaluate {
classDirectories.setFrom(
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"**/*Application*",
"**/*Config*",
"**/*Request*",
"**/*Response*",
"**/*Exception*",
"**/*Mapper*",
"**/*ErrorMessage*",
"**/*DynamicQuery*",
"**/*BaseTimeEntity*",
"**/*HealthCheckController*",
"**/*S3Manager*",
] + Qdomains)
})
files(classDirectories.files.collect {
fileTree(dir: it, excludes: [
"**/*Application*",
"**/*Config*",
"**/*Request*",
"**/*Response*",
"**/*Exception*",
"**/*Mapper*",
"**/*ErrorMessage*",
"**/*DynamicQuery*",
"**/*BaseTimeEntity*",
"**/*HealthCheckController*",
"**/*S3Manager*",
] + Qdomains)
})
)
}
}

compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'

tasks.withType(Checkstyle).configureEach {
reports {
xml.required = true
Expand All @@ -177,9 +189,9 @@ sonar {
property "sonar.host.url", "https://sonarcloud.io"
property 'sonar.coverage.jacoco.xmlReportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml'
property 'sonar.coverage.exclusions', '**/test/**, **/Q*.java, **/*Doc*.java, **/resources/** ' +
',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' +
',**/*ErrorMessage*.java, **/*Mapper*.java, **/*DynamicQuery*, **/*BaseTimeEntity*, **/*HealthCheckController* ' +
', **/*S3Manager*.java'
',**/*Application*.java , **/*Config*.java, **/*Request*.java, **/*Response*.java ,**/*Exception*.java ' +
',**/*ErrorMessage*.java, **/*Mapper*.java, **/*DynamicQuery*, **/*BaseTimeEntity*, **/*HealthCheckController* ' +
', **/*S3Manager*.java'
property 'sonar.java.checkstyle.reportPaths', 'build/reports/checkstyle/main.xml'
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.moabam.api.application.coupon;

import java.time.LocalDate;
import java.util.Optional;

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.global.error.exception.NotFoundException;
import com.moabam.global.error.model.ErrorMessage;

import lombok.RequiredArgsConstructor;

@Service
@RequiredArgsConstructor
@CacheConfig(cacheNames = "coupons")
public class CouponCacheService {

private final CouponRepository couponRepository;

@Cacheable(key = "#couponName + #now")
public Coupon getByNameAndStartAt(String couponName, LocalDate now) {
return couponRepository.findByNameAndStartAt(couponName, now)
.orElseThrow(() -> new NotFoundException(ErrorMessage.INVALID_COUPON_PERIOD));
}

@Cacheable(key = "#now")
public Optional<Coupon> getByStartAt(LocalDate now) {
return couponRepository.findByStartAt(now);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,10 @@
import com.moabam.api.domain.coupon.Coupon;
import com.moabam.api.domain.coupon.CouponWallet;
import com.moabam.api.domain.coupon.repository.CouponManageRepository;
import com.moabam.api.domain.coupon.repository.CouponRepository;
import com.moabam.api.domain.coupon.repository.CouponWalletRepository;
import com.moabam.global.common.util.ClockHolder;
import com.moabam.global.error.exception.BadRequestException;
import com.moabam.global.error.exception.ConflictException;
import com.moabam.global.error.exception.NotFoundException;
import com.moabam.global.error.model.ErrorMessage;

import lombok.RequiredArgsConstructor;
Expand All @@ -34,14 +32,14 @@ public class CouponManageService {
private final ClockHolder clockHolder;
private final NotificationService notificationService;

private final CouponRepository couponRepository;
private final CouponCacheService couponCacheService;
private final CouponManageRepository couponManageRepository;
private final CouponWalletRepository couponWalletRepository;

@Scheduled(fixedDelay = 1000)
public void issue() {
LocalDate now = clockHolder.date();
Optional<Coupon> optionalCoupon = couponRepository.findByStartAt(now);
Optional<Coupon> optionalCoupon = couponCacheService.getByStartAt(now);

if (optionalCoupon.isEmpty()) {
return;
Expand Down Expand Up @@ -70,21 +68,20 @@ public void issue() {
couponManageRepository.increase(couponName, membersId.size());
}

public void delete(String couponName) {
couponManageRepository.deleteQueue(couponName);
couponManageRepository.deleteCount(couponName);
}

public void registerQueue(String couponName, Long memberId) {
double registerTime = System.currentTimeMillis();
validateRegisterQueue(couponName, memberId);
couponManageRepository.addIfAbsentQueue(couponName, memberId, registerTime);
}

public void delete(String couponName) {
couponManageRepository.deleteQueue(couponName);
couponManageRepository.deleteCount(couponName);
}

private void validateRegisterQueue(String couponName, Long memberId) {
LocalDate now = clockHolder.date();
Coupon coupon = couponRepository.findByNameAndStartAt(couponName, now)
.orElseThrow(() -> new NotFoundException(ErrorMessage.INVALID_COUPON_PERIOD));
Coupon coupon = couponCacheService.getByNameAndStartAt(couponName, now);

if (couponManageRepository.hasValue(couponName, memberId)) {
throw new ConflictException(ErrorMessage.CONFLICT_COUPON_ISSUE);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ public interface CouponRepository extends JpaRepository<Coupon, Long> {
Optional<Coupon> findByStartAt(LocalDate startAt);

Optional<Coupon> findByNameAndStartAt(String couponName, LocalDate startAt);

boolean existsByNameAndStartAt(String couponName, LocalDate startAt);
}
62 changes: 62 additions & 0 deletions src/main/java/com/moabam/global/config/CacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package com.moabam.global.config;

import static org.springframework.data.redis.serializer.RedisSerializationContext.*;

import java.time.Duration;
import java.time.LocalTime;

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.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.databind.jsontype.BasicPolymorphicTypeValidator;
import com.fasterxml.jackson.databind.jsontype.PolymorphicTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.moabam.global.common.util.ClockHolder;

import lombok.RequiredArgsConstructor;

@EnableCaching
@Configuration
@RequiredArgsConstructor
public class CacheConfig {

private final ClockHolder clockHolder;

@Bean
public RedisCacheConfiguration redisCacheConfiguration() {
var strSerializePair = SerializationPair.fromSerializer(new StringRedisSerializer());
var objSerializePair = SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer(objectMapper()));

return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(getTtl())
.serializeKeysWith(strSerializePair)
.serializeValuesWith(objSerializePair);
}

private Duration getTtl() {
LocalTime now = clockHolder.time();
LocalTime end = clockHolder.endOfDay();

return Duration.between(now, end);
}

private ObjectMapper objectMapper() {
PolymorphicTypeValidator polymorphicTypeValidator = BasicPolymorphicTypeValidator.builder()
.allowIfSubType(Object.class)
.build();

return JsonMapper.builder()
.polymorphicTypeValidator(polymorphicTypeValidator)
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.addModule(new JavaTimeModule())
.activateDefaultTyping(polymorphicTypeValidator, ObjectMapper.DefaultTyping.NON_FINAL)
.build();
}
}

0 comments on commit 909344c

Please sign in to comment.