레디스에서 회원 데이터를 저장/조회

This commit is contained in:
assu10
2020-10-03 18:38:55 +09:00
parent 172667004a
commit b569b62569
9 changed files with 191 additions and 9 deletions

View File

@@ -226,6 +226,34 @@ springCloudBus
-- 메시지 발행/수신 확인 -- 메시지 발행/수신 확인
[POST] http://localhost:8090/member/assu [POST] http://localhost:8090/member/assu
-- 레디스 설치확인
C:\Users\ju>netstat -an|findstr 6379
TCP 127.0.0.1:6379 0.0.0.0:0 LISTENING
C:\Users\ju>redis-cli
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set key value
OK
127.0.0.1:6379> get key
"value"
127.0.0.1:6379>
-- 레디스 실행
redis-server.bat 실행
-- 모든 키 확인
127.0.0.1:6379> keys *
1) "member"
-- key-value 확인 (get 은 String 만 다루므로 여기선 에러로 표시)
127.0.0.1:6379> get member
(error) WRONGTYPE Operation against a key holding the wrong kind of value
-- 모든 키 삭제
127.0.0.1:6379> flushall
OK
``` ```

View File

@@ -67,7 +67,6 @@ public class EventServiceApplication {
/** /**
* 레디스 서버에 작업 수행 시 사용할 RedisTemplate 객체 생성 * 레디스 서버에 작업 수행 시 사용할 RedisTemplate 객체 생성
* @return
*/ */
@Bean @Bean
public RedisTemplate<String, Object> redisTemplate() { public RedisTemplate<String, Object> redisTemplate() {

View File

@@ -0,0 +1,89 @@
package com.assu.cloud.eventservice.client;
import com.assu.cloud.eventservice.config.CustomConfig;
import com.assu.cloud.eventservice.model.Member;
import com.assu.cloud.eventservice.repository.MemberRedisRepository;
import com.assu.cloud.eventservice.utils.CustomContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
/**
* 회원 데이터 필요 시 회원 서비스 호출 전 레디스 캐시 먼저 확인
*/
@Component
public class MemberCacheRestTemplateClient {
private static final Logger logger = LoggerFactory.getLogger(MemberCacheRestTemplateClient.class);
private final RestTemplate restTemplate;
private final MemberRedisRepository memberRedisRepository;
private final CustomConfig customConfig;
public MemberCacheRestTemplateClient(RestTemplate restTemplate, MemberRedisRepository memberRedisRepository, CustomConfig customConfig) {
this.restTemplate = restTemplate;
this.memberRedisRepository = memberRedisRepository;
this.customConfig = customConfig;
}
String URL_PREFIX = "/api/mb/member/"; // 회원 서비스의 주울 라우팅경로와 회원 클래스 주소
/**
* 회원 아이디로 레디스에 저장된 Member 클래스 조회
*/
private Member checkRedisCache(String userId) {
try {
return memberRedisRepository.findMember(userId);
} catch (Exception e) {
logger.error("======= Error encountered while trying to retrieve member {} check Redis Cache., Exception {}", userId, e);
return null;
}
}
/**
* 레디스 캐시에 데이터 저장
*/
private void cacheMemberObject(Member member) {
try {
memberRedisRepository.saveMember(member);
} catch (Exception e) {
e.printStackTrace();
logger.error("======= Unable to cache member {} in Redis. Exception {}", member.getId(), e);
}
}
public Member getMember(String userId) {
Member member = checkRedisCache(userId);
// 레디스에 데이터가 없다면 원본 데이터에서 데이터를 조회하기 위해 회원 서비스 호출
if (member != null) {
logger.debug("======= Successfully retrieved an Member {} from the redis cache: {}", userId, member);
return member;
}
logger.debug("======= Unable to locate member from the redis cache: {}", userId);
ResponseEntity<Member> restExchange =
restTemplate.exchange(
"http://" + customConfig.getServiceIdZuul() + URL_PREFIX + "{userId}", // http://localhost:5555/api/mb/member/userInfo/rinda
HttpMethod.GET,
null,
Member.class,
userId
);
// 캐시 레코드 저장
member = restExchange.getBody();
// 조회한 객체를 캐시에 저장
if (member != null) {
cacheMemberObject(member);
}
return member;
}
}

View File

@@ -1,8 +1,10 @@
package com.assu.cloud.eventservice.controller; package com.assu.cloud.eventservice.controller;
import com.assu.cloud.eventservice.client.MemberCacheRestTemplateClient;
import com.assu.cloud.eventservice.client.MemberRestTemplateClient; import com.assu.cloud.eventservice.client.MemberRestTemplateClient;
import com.assu.cloud.eventservice.client.MemberFeignClient; import com.assu.cloud.eventservice.client.MemberFeignClient;
import com.assu.cloud.eventservice.config.CustomConfig; import com.assu.cloud.eventservice.config.CustomConfig;
import com.assu.cloud.eventservice.model.Member;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@@ -15,11 +17,14 @@ public class EventController {
private final CustomConfig customConfig; private final CustomConfig customConfig;
private final MemberFeignClient memberFeignClient; private final MemberFeignClient memberFeignClient;
private final MemberRestTemplateClient memberRestTemplateClient; private final MemberRestTemplateClient memberRestTemplateClient;
private final MemberCacheRestTemplateClient memberCacheRestTemplateClient;
public EventController(CustomConfig customConfig, MemberFeignClient memberFeignClient, MemberRestTemplateClient memberRestTemplateClient) { public EventController(CustomConfig customConfig, MemberFeignClient memberFeignClient, MemberRestTemplateClient memberRestTemplateClient,
MemberCacheRestTemplateClient memberCacheRestTemplateClient) {
this.customConfig = customConfig; this.customConfig = customConfig;
this.memberFeignClient = memberFeignClient; this.memberFeignClient = memberFeignClient;
this.memberRestTemplateClient = memberRestTemplateClient; this.memberRestTemplateClient = memberRestTemplateClient;
this.memberCacheRestTemplateClient = memberCacheRestTemplateClient;
} }
@GetMapping(value = "name/{nick}") @GetMapping(value = "name/{nick}")
@@ -49,6 +54,14 @@ public class EventController {
return "[EVENT] Gift is " + gift; return "[EVENT] Gift is " + gift;
} }
/**
* 레디스 캐싱 데이터 사용
*/
@GetMapping(value = "{userId}")
public Member userInfo(@PathVariable("userId") String userId) {
return memberCacheRestTemplateClient.getMember(userId);
}
/*@GetMapping("userInfo/{name}") /*@GetMapping("userInfo/{name}")
public String userInfo(@PathVariable("name") String name) { public String userInfo(@PathVariable("name") String name) {
return "[EVENT-MEMBER] " + memberRestTemplateClient.userInfo(name); return "[EVENT-MEMBER] " + memberRestTemplateClient.userInfo(name);

View File

@@ -2,6 +2,9 @@ package com.assu.cloud.eventservice.repository;
import com.assu.cloud.eventservice.model.Member; import com.assu.cloud.eventservice.model.Member;
/**
* 레디스에 액세스해야 하는 클래스에 주입된 인터페이스
*/
public interface MemberRedisRepository { public interface MemberRedisRepository {
void saveMember(Member member); void saveMember(Member member);
void updateMember(Member member); void updateMember(Member member);

View File

@@ -1,30 +1,38 @@
package com.assu.cloud.eventservice.repository; package com.assu.cloud.eventservice.repository;
import com.assu.cloud.eventservice.model.Member; import com.assu.cloud.eventservice.model.Member;
import com.netflix.discovery.converters.Auto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.HashOperations; import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Repository; import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
/**
* 부트스트랩 클래스에서 정의한 RedisTemplate 빈을 사용하여 레디스 서버와 통신
*/
@Repository @Repository
public class MemberRedisRepositoryImpl implements MemberRedisRepository { public class MemberRedisRepositoryImpl implements MemberRedisRepository {
private static final String HASH_NAME = "member"; // 회원 데이터가 저장되는 레디스 서버의 해시명 private static final String HASH_NAME = "member"; // 회원 데이터가 저장되는 레디스 서버의 해시명
private RedisTemplate<String, Member> redisTemplate; private final RedisTemplate<String, Member> redisTemplate;
private HashOperations hashOperations; // HashOperation 클래스는 레디스 서버에 데이터 작업을 수행하는 스프링 헬퍼 메서드의 집합 private HashOperations hashOperations; // HashOperation 클래스는 레디스 서버에 데이터 작업을 수행하는 스프링 헬퍼 메서드의 집합
public MemberRedisRepositoryImpl() { public MemberRedisRepositoryImpl(RedisTemplate redisTemplate) {
super();
}
public MemberRedisRepositoryImpl(RedisTemplate<String, Member> redisTemplate) {
this.redisTemplate = redisTemplate; this.redisTemplate = redisTemplate;
} }
@PostConstruct @PostConstruct
public void init() { public void init() {
hashOperations = redisTemplate.opsForHash(); hashOperations = redisTemplate.opsForHash();
// 키와 값을 명시적으로 직렬화해주지 않으면 default serializer 로 JdkSerializationRedisSerializer 를 사용하는데
// 그러면 \xac\xed\x00\x05t\x00\x06member 이런 식으로 저장됨
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
} }
@Override @Override

View File

@@ -15,5 +15,5 @@ spring:
brokers: localhost brokers: localhost
#redis #redis
redis: redis:
server: redis server: localhost
port: 6379 port: 6379

View File

@@ -3,6 +3,9 @@ package com.assu.cloud.memberservice.controller;
import com.assu.cloud.memberservice.client.EventRestTemplateClient; import com.assu.cloud.memberservice.client.EventRestTemplateClient;
import com.assu.cloud.memberservice.config.CustomConfig; import com.assu.cloud.memberservice.config.CustomConfig;
import com.assu.cloud.memberservice.event.source.SimpleSourceBean; import com.assu.cloud.memberservice.event.source.SimpleSourceBean;
import com.assu.cloud.memberservice.model.Member;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.ServletRequest; import javax.servlet.ServletRequest;
@@ -11,6 +14,8 @@ import javax.servlet.ServletRequest;
@RequestMapping("/member") @RequestMapping("/member")
public class MemberController { public class MemberController {
private static final Logger logger = LoggerFactory.getLogger(MemberController.class);
private final CustomConfig customConfig; private final CustomConfig customConfig;
private final EventRestTemplateClient eventRestTemplateClient; private final EventRestTemplateClient eventRestTemplateClient;
private final SimpleSourceBean simpleSourceBean; private final SimpleSourceBean simpleSourceBean;
@@ -60,4 +65,17 @@ public class MemberController {
simpleSourceBean.publishMemberChange("SAVE", userId); simpleSourceBean.publishMemberChange("SAVE", userId);
} }
/**
* 이벤트 서비스에서 캐시 용도로 회원 데이터 조회
*/
@GetMapping("{userId}")
public Member userInfoCache(@PathVariable("userId") String userId) {
logger.debug("====== 회원 서비스 호출!");
// DB 를 조회하여 회원 데이터 조회 (간편성을 위해 아래와 같이 리턴함)
Member member = new Member();
member.setId(userId);
member.setName("rinda");
return member;
}
} }

View File

@@ -0,0 +1,24 @@
package com.assu.cloud.memberservice.model;
import java.io.Serializable;
public class Member implements Serializable {
private String id;
private String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}