Skip to content

Commit e729ff1

Browse files
committed
Add Redis Configuration
1 parent bdd09ee commit e729ff1

File tree

13 files changed

+160
-5
lines changed

13 files changed

+160
-5
lines changed

build.gradle

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ dependencies {
2626
implementation 'org.springframework.boot:spring-boot-starter-web'
2727
implementation 'org.springframework.boot:spring-boot-starter-security'
2828
implementation 'org.springframework.boot:spring-boot-starter-actuator'
29+
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
30+
//embedded-redis
31+
implementation 'it.ozimov:embedded-redis:0.7.2'
2932
implementation 'io.jsonwebtoken:jjwt:0.9.1'
3033
implementation 'io.springfox:springfox-swagger2:2.6.1'
3134
implementation 'io.springfox:springfox-swagger-ui:2.6.1'
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.rest.api.common;
2+
3+
public class CacheKey {
4+
5+
public static final int DEFAULT_EXPIRE_SEC = 60; // 1 minutes
6+
public static final String USER = "user";
7+
public static final int USER_EXPIRE_SEC = 60 * 5; // 5 minutes
8+
public static final String BOARD = "board";
9+
public static final int BOARD_EXPIRE_SEC = 60 * 10; // 10 minutes
10+
public static final String POST = "post";
11+
public static final String POSTS = "posts";
12+
public static final int POST_EXPIRE_SEC = 60 * 5; // 5 minutes
13+
14+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package com.rest.api.config;
2+
3+
import org.springframework.beans.factory.annotation.Value;
4+
import org.springframework.context.annotation.Configuration;
5+
import org.springframework.context.annotation.Profile;
6+
import redis.embedded.RedisServer;
7+
8+
import javax.annotation.PostConstruct;
9+
import javax.annotation.PreDestroy;
10+
11+
/**
12+
* 로컬 환경일경우 내장 레디스가 실행된다.
13+
*/
14+
@Profile("local")
15+
@Configuration
16+
public class EmbeddedRedisConfig {
17+
18+
@Value("${spring.redis.port}")
19+
private int redisPort;
20+
21+
private RedisServer redisServer;
22+
23+
@PostConstruct
24+
public void redisServer() {
25+
redisServer = new RedisServer(redisPort);
26+
redisServer.start();
27+
}
28+
29+
@PreDestroy
30+
public void stopRedis() {
31+
if (redisServer != null) {
32+
redisServer.stop();
33+
}
34+
}
35+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.rest.api.config;
2+
3+
import com.rest.api.common.CacheKey;
4+
import lombok.RequiredArgsConstructor;
5+
import org.springframework.cache.annotation.EnableCaching;
6+
import org.springframework.context.annotation.Bean;
7+
import org.springframework.context.annotation.Configuration;
8+
import org.springframework.data.redis.cache.CacheKeyPrefix;
9+
import org.springframework.data.redis.cache.RedisCacheConfiguration;
10+
import org.springframework.data.redis.cache.RedisCacheManager;
11+
import org.springframework.data.redis.connection.RedisConnectionFactory;
12+
import org.springframework.data.redis.core.RedisTemplate;
13+
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
14+
import org.springframework.data.redis.serializer.RedisSerializationContext;
15+
import org.springframework.data.redis.serializer.StringRedisSerializer;
16+
17+
import java.time.Duration;
18+
import java.util.HashMap;
19+
import java.util.Map;
20+
21+
@RequiredArgsConstructor
22+
@EnableCaching
23+
@Configuration
24+
public class RedisConfig {
25+
26+
@Bean(name = "cacheManager")
27+
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {
28+
29+
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
30+
.disableCachingNullValues()
31+
.entryTtl(Duration.ofSeconds(CacheKey.DEFAULT_EXPIRE_SEC))
32+
.computePrefixWith(CacheKeyPrefix.simple())
33+
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));
34+
35+
Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
36+
// 캐시 default 유효시간 설정
37+
cacheConfigurations.put(CacheKey.USER, RedisCacheConfiguration.defaultCacheConfig()
38+
.entryTtl(Duration.ofSeconds(CacheKey.USER_EXPIRE_SEC)));
39+
cacheConfigurations.put(CacheKey.BOARD, RedisCacheConfiguration.defaultCacheConfig()
40+
.entryTtl(Duration.ofSeconds(CacheKey.BOARD_EXPIRE_SEC)));
41+
cacheConfigurations.put(CacheKey.POST, RedisCacheConfiguration.defaultCacheConfig()
42+
.entryTtl(Duration.ofSeconds(CacheKey.POST_EXPIRE_SEC)));
43+
cacheConfigurations.put(CacheKey.POSTS, RedisCacheConfiguration.defaultCacheConfig()
44+
.entryTtl(Duration.ofSeconds(CacheKey.POST_EXPIRE_SEC)));
45+
46+
return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory).cacheDefaults(configuration)
47+
.withInitialCacheConfigurations(cacheConfigurations).build();
48+
}
49+
50+
51+
}

src/main/java/com/rest/api/entity/User.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.fasterxml.jackson.annotation.JsonProperty;
55
import com.rest.api.entity.common.CommonDateEntity;
66
import lombok.*;
7+
import org.hibernate.annotations.Proxy;
78
import org.springframework.security.core.GrantedAuthority;
89
import org.springframework.security.core.authority.SimpleGrantedAuthority;
910
import org.springframework.security.core.userdetails.UserDetails;
@@ -22,6 +23,7 @@
2223
@AllArgsConstructor // 인자를 모두 갖춘 생성자를 자동으로 생성합니다.
2324
@Table(name = "user") // 'user' 테이블과 매핑됨을 명시
2425
@JsonIgnoreProperties({"hibernateLazyInitializer", "handler"}) // Post Entity에서 User와의 관계를 Json으로 변환시 오류 방지를 위한 코드
26+
@Proxy(lazy = false)
2527
public class User extends CommonDateEntity implements UserDetails {
2628
@Id // pk
2729
@GeneratedValue(strategy = GenerationType.IDENTITY)

src/main/java/com/rest/api/entity/board/Board.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,12 @@
55
import lombok.NoArgsConstructor;
66

77
import javax.persistence.*;
8+
import java.io.Serializable;
89

910
@Entity
1011
@Getter
1112
@NoArgsConstructor
12-
public class Board extends CommonDateEntity {
13+
public class Board extends CommonDateEntity implements Serializable {
1314
@Id
1415
@GeneratedValue(strategy = GenerationType.IDENTITY)
1516
private Long boardId;

src/main/java/com/rest/api/entity/board/Post.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package com.rest.api.entity.board;
22

3+
import com.fasterxml.jackson.annotation.JsonIgnore;
34
import com.rest.api.entity.User;
45
import com.rest.api.entity.common.CommonDateEntity;
56
import lombok.Getter;
67
import lombok.NoArgsConstructor;
8+
import org.hibernate.annotations.Proxy;
79

810
import javax.persistence.*;
11+
import java.io.Serializable;
912

1013
@Entity
1114
@Getter
1215
@NoArgsConstructor
13-
public class Post extends CommonDateEntity {
16+
public class Post extends CommonDateEntity implements Serializable {
1417
@Id
1518
@GeneratedValue(strategy = GenerationType.IDENTITY)
1619
private Long postId;
@@ -25,13 +28,13 @@ public class Post extends CommonDateEntity {
2528
@JoinColumn(name = "board_id")
2629
private Board board; // 게시글 - 게시판의 관계 - N:1
2730

28-
2931
@ManyToOne(fetch = FetchType.LAZY)
3032
@JoinColumn(name = "msrl")
3133
private User user; // 게시글 - 회원의 관계 - N:1
3234

3335
// Join 테이블이 Json결과에 표시되지 않도록 처리.
34-
protected Board getBoard() {
36+
@JsonIgnore
37+
public Board getBoard() {
3538
return board;
3639
}
3740

src/main/java/com/rest/api/repo/board/PostJpaRepo.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package com.rest.api.repo.board;
22

3+
import com.rest.api.common.CacheKey;
34
import com.rest.api.entity.board.Board;
45
import com.rest.api.entity.board.Post;
6+
import org.springframework.cache.annotation.CacheEvict;
7+
import org.springframework.cache.annotation.Caching;
58
import org.springframework.data.jpa.repository.JpaRepository;
69

710
import java.util.List;

src/main/java/com/rest/api/service/board/BoardService.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,26 @@
33
import com.rest.api.advice.exception.CNotOwnerException;
44
import com.rest.api.advice.exception.CResourceNotExistException;
55
import com.rest.api.advice.exception.CUserNotFoundException;
6+
import com.rest.api.common.CacheKey;
67
import com.rest.api.entity.User;
78
import com.rest.api.entity.board.Board;
89
import com.rest.api.entity.board.Post;
910
import com.rest.api.model.board.ParamsPost;
1011
import com.rest.api.repo.UserJpaRepo;
1112
import com.rest.api.repo.board.BoardJpaRepo;
1213
import com.rest.api.repo.board.PostJpaRepo;
14+
import com.rest.api.service.cache.CacheSevice;
1315
import lombok.RequiredArgsConstructor;
16+
import lombok.extern.slf4j.Slf4j;
17+
import org.springframework.cache.annotation.CacheEvict;
18+
import org.springframework.cache.annotation.Cacheable;
1419
import org.springframework.stereotype.Service;
1520

1621
import javax.transaction.Transactional;
1722
import java.util.List;
1823
import java.util.Optional;
1924

25+
@Slf4j
2026
@Service
2127
@Transactional
2228
@RequiredArgsConstructor
@@ -25,23 +31,28 @@ public class BoardService {
2531
private final BoardJpaRepo boardJpaRepo;
2632
private final PostJpaRepo postJpaRepo;
2733
private final UserJpaRepo userJpaRepo;
34+
private final CacheSevice cacheSevice;
2835

2936
// 게시판 이름으로 게시판을 조회. 없을경우 CResourceNotExistException 처리
37+
@Cacheable(value = CacheKey.BOARD, key = "#boardName", unless = "#result == null")
3038
public Board findBoard(String boardName) {
3139
return Optional.ofNullable(boardJpaRepo.findByName(boardName)).orElseThrow(CResourceNotExistException::new);
3240
}
3341

3442
// 게시판 이름으로 게시물 리스트 조회.
43+
@Cacheable(value = CacheKey.POSTS, key = "#boardName", unless = "#result == null")
3544
public List<Post> findPosts(String boardName) {
3645
return postJpaRepo.findByBoard(findBoard(boardName));
3746
}
3847

3948
// 게시물ID로 게시물 단건 조회. 없을경우 CResourceNotExistException 처리
49+
@Cacheable(value = CacheKey.POST, key = "#postId", unless = "#result == null")
4050
public Post getPost(long postId) {
4151
return postJpaRepo.findById(postId).orElseThrow(CResourceNotExistException::new);
4252
}
4353

4454
// 게시물을 등록합니다. 게시물의 회원UID가 조회되지 않으면 CUserNotFoundException 처리합니다.
55+
@CacheEvict(value = CacheKey.POSTS, key = "#boardName")
4556
public Post writePost(String uid, String boardName, ParamsPost paramsPost) {
4657
Board board = findBoard(boardName);
4758
Post post = new Post(userJpaRepo.findByUid(uid).orElseThrow(CUserNotFoundException::new), board, paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent());
@@ -57,6 +68,7 @@ public Post updatePost(long postId, String uid, ParamsPost paramsPost) {
5768

5869
// 영속성 컨텍스트의 변경감지(dirty checking) 기능에 의해 조회한 Post내용을 변경만 해도 Update쿼리가 실행됩니다.
5970
post.setUpdate(paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent());
71+
cacheSevice.deleteBoardCache(post.getPostId(), post.getBoard().getName());
6072
return post;
6173
}
6274

@@ -67,6 +79,7 @@ public boolean deletePost(long postId, String uid) {
6779
if (!uid.equals(user.getUid()))
6880
throw new CNotOwnerException();
6981
postJpaRepo.delete(post);
82+
cacheSevice.deleteBoardCache(post.getPostId(), post.getBoard().getName());
7083
return true;
7184
}
7285
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.rest.api.service.cache;
2+
3+
import com.rest.api.common.CacheKey;
4+
import lombok.extern.slf4j.Slf4j;
5+
import org.springframework.cache.annotation.CacheEvict;
6+
import org.springframework.cache.annotation.Caching;
7+
import org.springframework.stereotype.Service;
8+
9+
@Slf4j
10+
@Service
11+
public class CacheSevice {
12+
13+
@Caching(evict = {
14+
@CacheEvict(value = CacheKey.POST, key = "#postId"),
15+
@CacheEvict(value = CacheKey.POSTS, key = "#boardName")
16+
})
17+
public boolean deleteBoardCache(long postId, String boardName) {
18+
log.debug("deleteBoardCache - postId {}, boardName {}", postId, boardName);
19+
return true;
20+
}
21+
}

0 commit comments

Comments
 (0)