[Spring Boot]Redis 사용법
오늘은 Redis를 데이터 저장소로 사용하는 과정을 포스팅하려고 합니다.
Redis는 설치되었다는 가정하에 진행되니 참고해주세요. (Redis 설치 방법)
※테스트 환경
- Spring Boot
- Maven
- CentOS 7
1) Maven 추가
<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
Spring 설정에 들어가기전에 Redis에 데이터를 저장하는 방법은 2가지가 있습니다. RedisTemplate을 이용한 방법과 RedisRepository를 이용한 방법입니다.
RedisTemplate을 이용한 방법은 직렬화,역직렬화 설정 후 데이터를 저장,조회하는 방법입니다.(생성자 주입 후 사용)
RedisRepository를 이용한 방법은 CrudRepository를 상속받아 JPA 처럼 사용하는 방법입니다.
본 포스팅에서는 두 가지 방법을 소개합니다.
2) Redis 접속 정보 설정
# Redis 설정
spring.redis.host=127.0.0.1
spring.redis.port=6379
3) 데이터 저장
3-1) RedisRepository 사용 방식 설정
3-1-1) Configuration 등록
package com.study.app.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
}
3-1-2) Entity 등록
package com.study.app.common.redis;
import org.springframework.data.annotation.Id;
import org.springframework.data.redis.core.RedisHash;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor
@RedisHash(value = "companyUser")
public class CompanyUser {
@Id
private String userId;
private String userName;
public CompanyUser(String userId, String userName) {
this.userId = userId;
this.userName = userName;
}
}
@RedisHash로 데이터의 prefix가 설정됩니다.
@Id 어노테이션 사용시 javax.persistence.Id가 아닌 org.springframework.data.annotation.Id를 임포트해야합니다.
import org.springframework.data.annotation.Id;
3-1-3) Repository 등록
package com.study.app.common.redis;
import java.util.List;
import org.springframework.data.repository.CrudRepository;
public interface CompanyRepository extends CrudRepository<CompanyUser, String>{
List<CompanyUser> findAll();
}
3-1-4) Test Component 등록
package com.study.app.common.component;
import javax.annotation.PostConstruct;
import org.springframework.stereotype.Component;
import com.wwl.app.common.redis.CompanyRepository;
import com.wwl.app.common.redis.CompanyUser;
@Component
public class RedisCompany {
private final CompanyRepository companyRepository;
public RedisCompany(CompanyRepository companyRepository) {
this.companyRepository = companyRepository;
}
@PostConstruct
public void init() {
companyRepository.save(new CompanyUser("lsh", "홍길동"));
}
}
서버를 실행하게 되면 @PostConstruct 에 의해 최초 1회 Redis 에 저장됩니다.
이제 Redis에 저장된 값을 조회해보겠습니다.
3-1-5) 전체 리스트 조회
결과를 리턴할 MsgEntity 클래스와 Enum 타입 생성
package com.study.app.common.entity;
import lombok.Data;
@Data
public class MsgEntity {
private StatusEnum status;
private String message;
private Object result;
public MsgEntity(StatusEnum status, String message) {
this.status = status;
this.message = message;
}
public MsgEntity(StatusEnum status, Object result) {
this.status = status;
this.result = result;
}
}
package com.study.app.common.entity;
public enum StatusEnum {
OK(200, "OK"),
BAD_REQUEST(400, "BAD_REQUEST"),
NOT_FOUND(404, "NOT_FOUND"),
INTERNAL_SERVER_ERROR(500, "INTERNAL_SERVER_ERROR");
int code;
String message;
StatusEnum(int code, String message) {
this.code = code;
this.message = message;
}
}
데이터 조회를 위한 컨트롤러를 만들고 테스트해보겠습니다.
package com.study.app.common.redis;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.wwl.app.common.entity.MsgEntity;
import com.wwl.app.common.entity.StatusEnum;
import lombok.AllArgsConstructor;
@RestController
@RequiredArgsConstructor
public class CompanyController {
private final CompanyRepository companyRepository;
@GetMapping(value="/company/list")
public ResponseEntity<MsgEntity> companyList() throws Exception {
return ResponseEntity.ok()
.body(new MsgEntity(StatusEnum.OK, companyRepository.findAll()));
}
}
@Id로 지정된 lsh를 키값으로 홍길동의 값을 조회할 수 있습니다.
2개의 키(companyUser, companyUser:lsh)가 생성된 것을 확인할 수 있습니다.
여기서 companyUser는 companyUser와 관련된 모든 키를 관리하며 companyUser의 Id와 매핑된 정보는 companyUser:Id와 같은 형태로 저장됩니다.
각각의 타입을 확인해보면 companyUser는 Set의 형태를 하고 실제 정보가 있는 companyUser:lsh는 Hash 타입임을 알 수 있습니다.
Redis에서는 각각의 자료구조별로 조회하는 명령어가 존재합니다.
Set 타입 조회시에는 SMEMBERS라는 명령어로 조회를 할 수 있습니다.
Hash 타입 조회시에는 hkeys로 키 리스트를 볼 수 있고, hvals로 값을 볼 수 있습니다.
입력된 값은 인코딩 과정에서 한글이 깨지는 문제로 redis-cli --raw 옵션을 붙이게 되면 확인할 수 있습니다.
[Postman 호출 테스트]
3-2) RedisTemplate 사용 방식
3-2-1) Configuration 등록
RedisTemplate은 Redis 서버에 커맨드를 수행하기 위한 메소드를 제공합니다. 자료구조에 따라 각기 다른 메소드가 사용되는데 각 메소드는 *Operations 인터페이스를 반환하기에 타입에 맞는 Operations을 선언해 사용합니다.
- opsForValue() : String -> ValueOperations
- opsForSet() : Set -> SetOperations
- opsForList() : List -> ListOperations
- opsForZSet() : Sorted Set -> ZSetOperations
- opsForHash() : Hash -> HashOperations
package com.study.app.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
@Configuration
public class RedisConfig {
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private int port;
@Bean
public LettuceConnectionFactory redisConnectionFactory() {
return new LettuceConnectionFactory(host, port);
}
@Bean
public RedisTemplate<String, CompanyUserDTO> companyTemplate() {
RedisTemplate<String, CompanyUserDTO> accessTemplate = new RedisTemplate<>();
accessTemplate.setConnectionFactory(redisConnectionFactory());
accessTemplate.setKeySerializer(new StringRedisSerializer());
accessTemplate.setValueSerializer(new Jackson2JsonRedisSerializer<>(CompanyUserDTO.class));
return accessTemplate;
}
}
3-2-2) DTO 등록
package com.study.app.common.redis;
import lombok.Data;
@Data
public class CompanyUserDTO {
private String userId;
private String userName;
}
3-2-3) Controller 등록
- [GET] "/company/list" : 사용자 조회
- [POST] "/company/user" : 사용자 등록
package com.study.app.common.redis;
import com.wwl.app.common.entity.MsgEntity;
import com.wwl.app.common.entity.StatusEnum;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.Set;
@RestController
@RequiredArgsConstructor
public class CompanyController {
private final RedisTemplate<String, CompanyUserDTO> companyTemplate;
@GetMapping(value="/company/list")
public ResponseEntity<MsgEntity> companyList() throws Exception {
SetOperations<String, CompanyUserDTO> setOpertaions = companyTemplate.opsForSet();
Set<CompanyUserDTO> companyUserList = setOpertaions.members("companyUser");
return ResponseEntity.ok()
.body(new MsgEntity(StatusEnum.OK, companyUserList));
}
@PostMapping(value="/company/user")
public ResponseEntity<MsgEntity> insertCompanyUser(@RequestBody CompanyUserDTO companyUserDTO) throws Exception {
SetOperations<String, CompanyUserDTO> setOpertaions = companyTemplate.opsForSet();
setOpertaions.add("companyUser", companyUserDTO);
return ResponseEntity.ok()
.body(new MsgEntity(StatusEnum.OK, "Success"));
}
}
RedisRepository를 이용한 방식과 동일하게 SET 타입으로 사용자를 등록하도록 했습니다.
먼저 redis-cli 명령어를 통해 접속 후 키 리스트를 조회해보면 아래와 같이 아무것도 조회되지 않는 것을 확인할 수 있습니다.
사용자를 등록하고 다시 조회해보겠습니다.
[Postman 호출 테스트]
다시 redis-cli 후 키를 조회해보면 companyUser가 추가된 것을 확인할 수 있고, SMEMBERS 명령어로 등록된 값을 확인할 수 있습니다.
깨진 한글은 위에서와 마찬가지로 redis-cli --raw 옵션 설정 후 재조회하면 해결됩니다.
+ 피드백은 언제나 환영입니다 :)