๊ด€๋ฆฌ ๋ฉ”๋‰ด

๐‘†๐‘ข๐‘›๐‘ โ„Ž๐‘–๐‘›๐‘’ ๐‘Ž๐‘“๐‘ก๐‘’๐‘Ÿ ๐‘Ÿ๐‘Ž๐‘–๐‘›โœง

[Redis] Redis์„ ํ†ตํ•ด JWT ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„ํ•˜๊ธฐ ๋ณธ๋ฌธ

๐—ฃ๐—ฟ๐—ผ๐—ด๐—ฟ๐—ฎ๐—บ๐—บ๐—ถ๐—ป๐—ด๐Ÿ’ป/๐‘๐ž๐๐ข๐ฌ

[Redis] Redis์„ ํ†ตํ•ด JWT ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„ํ•˜๊ธฐ

๐ŸคRyusun๐Ÿค 2024. 3. 11. 08:00

ํ”„๋กœ์ ํŠธ์—์„œ JWT์„ ์‚ฌ์šฉํ–ˆ๋Š”๋ฐ ๋กœ๊ทธ์•„์›ƒ ๊ตฌํ˜„์„ ์œ„ํ•ด Redis๋ฅผ ์‚ฌ์šฉํ•ด์•ผํ–ˆ๋‹ค.

JWT์˜ ํŠน์„ฑ์ƒ ํ•œ ๋ฒˆ ๋ฐœ๊ธ‰๋œ ํ† ํฐ์€ ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „๊นŒ์ง€ ๊ณ„์† ์œ ํšจํ•˜๊ฒŒ ๋‚จ์•„์žˆ๊ธฐ๋•Œ๋ฌธ์— ๋กœ๊ทธ์•„์›ƒ์„ ์œ„ํ•ด์„œ๋Š” ์„œ๋ฒ„๋Š” ํ•ด๋‹น ์‚ฌ์šฉ์ž์˜ ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•ด์•ผ ํ•œ๋‹ค. Redis๋Š” ์ด๋Ÿฌํ•œ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ๋ฅผ ์‰ฝ๊ฒŒ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ธฐ๋ฐ˜์˜ ๋ฐ์ดํ„ฐ ๊ตฌ์กฐ๋ฅผ ์ œ๊ณตํ•˜๋ฉฐ, ๋†’์€ ์„ฑ๋Šฅ์„ ์ œ๊ณตํ•œ๋‹ค.

Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐ„๋‹จํ•˜๊ฒŒ ๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ์„ ๊ตฌํ˜„ํ•ด๋ณด์ž.

 


 

์˜์กด์„ฑ ์ถ”๊ฐ€ & Redis ์„ค์ •

 

build.gradle์— redis dependency๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ž.

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

 

 

RedisRepositoryConfig.java

Redis ์„ค์ •ํ•˜๊ธฐ ์œ„ํ•œ ํด๋ž˜์Šค์ด๋‹ค. 

@Configuration
@EnableRedisRepositories
public class RedisRepositoryConfig {

    @Value("${spring.redis.host}")
    private String redisHost;

    @Value("${spring.redis.port}")
    private int redisPort;

    @Bean
    public RedisConnectionFactory redisConnectionFactory() {
        return new LettuceConnectionFactory(redisHost, redisPort);
    }

    @Bean
    public RedisTemplate<?, ?> redisTemplate() {
        RedisTemplate<?, ?> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory());
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        return redisTemplate;
    }
}

 

RedisConnectionFactory

RedisConnection์ด ์ƒ์„ฑ๋˜์–ด Redis ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ํ• ์ˆ˜ ์žˆ๊ฒŒ ํ•œ๋‹ค.

 

RedisTemplate

RedisTemplate ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•˜์—ฌ Redis๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒํ•œ๋‹ค. RedisConnection์˜ ๊ฒฝ์šฐ binary value๋ฅผ ์ฃผ๊ณ  ๋ฐ›๋Š”๋ฐ RedisTemplate์˜ ๊ฒฝ์šฐ ๋†’์€ ์ˆ˜์ค€์˜ ์ถ”์ƒํ™”์™€ ์ง๋ ฌํ™”๋ฅผ ์ œ๊ณตํ•œ๋‹ค. RedisTemplate์€ ๋ฐ์ดํ„ฐ๋ฅผ ์ง๋ ฌํ™” / ์—ญ์ง๋ ฌํ™” ํ•˜์—ฌ ์ €์žฅ / ์กฐํšŒ๋ฅผ ํ•˜๋ฏ€๋กœ ์ ์ ˆํ•œ ์ง๋ ฌํ™” ๋ฐฉ์‹์„ ์„ค์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. 

setKeySerializer, setValueSerializer ์„ค์ •ํ•ด์ฃผ๋Š” ์ด์œ ๋Š” RedisTemplate๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ Spring - Redis ๊ฐ„ ๋ฐ์ดํ„ฐ ์ง๋ ฌํ™”, ์—ญ์ง๋ ฌํ™” ์‹œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹์ด Jdk ์ง๋ ฌํ™” ๋ฐฉ์‹์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋™์ž‘์—๋Š” ๋ฌธ์ œ๊ฐ€ ์—†์ง€๋งŒ redis-cli์„ ํ†ตํ•ด ์ง์ ‘ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด๋ ค๊ณ  ํ•  ๋•Œ ์•Œ์•„๋ณผ ์ˆ˜ ์—†๋Š” ํ˜•ํƒœ๋กœ ์ถœ๋ ฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ ์šฉํ•œ ์„ค์ •์ด๋‹ค.

 

StringRedisSerializer

Redis์— ๋ฌธ์ž์—ด์„ ์ €์žฅํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ๋œ๋‹ค. Java์˜ ๋ฌธ์ž์—ด์„ Redis์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ˜•์‹์œผ๋กœ ์ง๋ ฌํ™”ํ•˜๊ณ , Redis์—์„œ ์ฝ์€ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค์‹œ Java์˜ ๋ฌธ์ž์—ด๋กœ ์—ญ์ง๋ ฌํ™”ํ•œ๋‹ค.

 

 

2. AuthenticationConfig.java

Security + JWT ํ† ํฐ ๊ฒ€์ฆ์„ ํ•œ๋‹ค.

@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class AuthenticationConfig {

    private final UserServiceImpl userServiceImpl;
    @Value("${jwt.token.secret}")
    private String secretKey;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        return httpSecurity
                .httpBasic().disable()
                .csrf().disable()
                .cors().and()
                .authorizeRequests()
                .antMatchers("/user/signup", "/user/login", "/search/**", "/item/**","/sendmail", "/newpassword")
                .permitAll()
                .antMatchers(HttpMethod.POST, "/**").authenticated()
                .and()
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .addFilterBefore(new JwtFilter(userServiceImpl, secretKey), UsernamePasswordAuthenticationFilter.class)
                .build();
    }
 }

 

 

SecurityFilterChain์— JWT ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๋Š” ํด๋ž˜์Šค๋ฅผ ๋„ฃ์–ด์ค€๋‹ค.

 

 

3.JwtFilter.java

ํ† ํฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•œ๋‹ค.

@RequiredArgsConstructor
@Slf4j
public class JwtFilter extends OncePerRequestFilter {

    private final UserServiceImpl userServiceImpl;
    private final String secretKey;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {

        final String authorization = request.getHeader(HttpHeaders.AUTHORIZATION);
        log.info("authorization : {}", authorization);

        if(authorization == null || !authorization.startsWith("Bearer")){
            log.error("authorization is null or not Bearer");
            filterChain.doFilter(request, response);
            return;
        }

        if (authorization.split(" ").length != 2) {
            log.error("Token is not valid");
            filterChain.doFilter(request, response);
            return;
        }

        // Token ๊บผ๋‚ด๊ธฐ
        String token = authorization.split(" ")[1].trim();


        // ํ† ํฐ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
        if (!userServiceImpl.isValid(token)) {
            log.error("Logged out user");
            filterChain.doFilter(request, response);
            return;
        }

        // UserName Token์—์„œ ๊บผ๋‚ด๊ธฐ
        String userName = JwtUtil.getUserEmail(token, secretKey);
        log.info("userName : {}", userName);

        //๊ถŒํ•œ ๋ถ€์—ฌ
        UsernamePasswordAuthenticationToken authenticationToken=
                new UsernamePasswordAuthenticationToken(userName, null, List.of(new SimpleGrantedAuthority("USER")));

        //Detail์„ ๋„ฃ์–ด์ค๋‹ˆ๋‹ค.
        authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        filterChain.doFilter(request, response);
    }
}

 

HTTP ์š”์ฒญ์—์„œ "Authorization" ํ—ค๋”์˜ ๊ฐ’์„ ๊ฐ€์ ธ์™€์„œ ํ† ํฐ์„ ์ถ”์ถœํ•œ๋‹ค. ํ•ด๋‹น ํ† ํฐ์„ userServiceImpl.isValid() ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆํ•œ๋‹ค.

 

 

UserServiceImpl.java

๋กœ๊ทธ์ธ, ๋กœ๊ทธ์•„์›ƒ, ํ† ํฐ ๊ฒ€์ฆ์„ ํ•œ๋‹ค.

์‹ค์Šต์„ ์œ„ํ•ด ๋ฐ˜ํ™˜๊ฐ’์„ String ์œผ๋กœ ์„ค์ •ํ•˜์˜€๋‹ค.

@Service
@RequiredArgsConstructor
@Slf4j
public class UserServiceImpl implements UserService {

    private final UserRepository userRepository;
    private final BCryptPasswordEncoder encoder;
    private final StringRedisTemplate redisTemplate;

    @Value("${jwt.token.secret}")
    private String secretKey;
    private Long expiredMs = 1000 * 60 * 60 * 24 * 7L; //์ผ์ฃผ์ผ


    @Override
    public LoginResponseDTO login(String userEmail, String password) {
        //userEmail ์—†์Œ
        EntityUser selectedUser = userRepository.findByUserEmail(userEmail)
                .orElseThrow(() -> new AppException(ErrorCode.USERMAIL_NOT_FOUND, userEmail + " ์กด์žฌํ•˜์ง€ ์•Š๋Š” ํšŒ์›์ž…๋‹ˆ๋‹ค."));

        //password ํ‹€๋ฆผ
        if (!encoder.matches(password, selectedUser.getUserPassword())) { //์ˆœ์„œ ์ค‘์š”. inputpassword, DBpassword
            throw new AppException(ErrorCode.INVALID_PASSWORD, "๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ํ‹€๋ ธ์Šต๋‹ˆ๋‹ค.");
        }
        String token = JwtUtil.createToken(selectedUser.getUserEmail(), secretKey, expiredMs);
        // ๋ ˆ๋””์Šค์— ํ‚ค ๋ฒจ๋ฅ˜ ํ˜•์‹์œผ๋กœ ํšŒ์› ์ด๋ฉ”์ผ, ํ† ํฐ ์ €์žฅ
        redisTemplate.opsForValue().set("RT:" + userEmail, token);
        return new LoginResponseDTO(selectedUser.getUserName(), token);
    }

    @Override
    public Boolean isValid(String userToken) {
        try {
            ValueOperations<String, String> logoutValueOperations = redisTemplate.opsForValue();
            if(logoutValueOperations.get(userToken) != null){
                System.out.println("๋กœ๊ทธ์•„์›ƒ๋œ ํ† ํฐ ์ž…๋‹ˆ๋‹ค.");
                return false;
            }
            return !Jwts.parser().setSigningKey(secretKey).parseClaimsJws(userToken)
                    .getBody().getExpiration().before(new Date());
        } catch (ExpiredJwtException e) {
            e.getMessage();
            return false;
        }
    }

    @Override
    public String logout(HttpServletRequest request) {
        String token = request.getHeader(HttpHeaders.AUTHORIZATION).split(" ")[1].trim();
        String userEmail = JwtUtil.getUserEmail(token, secretKey);
        System.out.println(userEmail);
        if (redisTemplate.opsForValue().get("RT:" + userEmail)!= null) {
            redisTemplate.delete("RT:" + userEmail);}
        redisTemplate.opsForValue().set(token, "logout");
        return "LOGOUT_SUCCESS";
    }
 }

 

์šฐ์„  redis ์—ฐ์‚ฐํ•˜๊ธฐ์œ„ํ•ด StringRedisTemplate ์˜์กด์„ฑ ์ฃผ์ž…์„ ํ•ด์•ผํ•œ๋‹ค.

 

StringRedisTemplate Redis๋Š” Redis ๋ฐ์ดํ„ฐ ์ €์žฅ์†Œ์— ๋Œ€ํ•œ ๋ฌธ์ž์—ด ๊ธฐ๋ฐ˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋œ๋‹ค.

 

ํšŒ์›์ด ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด ํ† ํฐ์„ redis์— key, value ํ˜•์‹์œผ๋กœ ์ด๋ฉ”์ผ, ํ† ํฐ์„ ์ €์žฅํ•œ๋‹ค.

 

StringRedisTemplate.opsForValue() ๋ฉ”์„œ๋“œ๋Š” ๋ฌธ์ž์—ด ๊ฐ’์„ ๋‹ค๋ฃจ๊ธฐ ์œ„ํ•œ ์—ฐ์‚ฐ์ž๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

set์„ ํ†ตํ•ด์„œ ์‚ฌ์šฉ์ž์˜ ์ด๋ฉ”์ผ๊ณผ ํ† ํฐ์„ ์ €์žฅํ•œ๋‹ค.

RT๋Š” "Redis Token"์˜ ์ถ•์•ฝ์–ด์ด๋ฉฐ, ํ† ํฐ ๋ฐ์ดํ„ฐ๋ฅผ ๊ตฌ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ–ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ๊ตฌ๋ณ„ํ•จ์œผ๋กœ์จ Redis ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๋‚ด์—์„œ ์—ฌ๋Ÿฌ ์ข…๋ฅ˜์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ๊ด€๋ฆฌํ•  ๋•Œ ํŠน์ • ์œ ํ˜•์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‹๋ณ„ํ•˜๊ธฐ ์‰ฝ๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค.

 

ํ† ํฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

 

๋กœ๊ทธ์•„์›ƒ์„ ํ•˜๋ฉด ํ† ํฐ์„ key๋กœ ์ €์žฅํ•˜๋Š”๋ฐ get(ํ† ํฐ) ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ๋กœ๊ทธ์•„์›ƒ๋œ ํ† ํฐ์ด๋ผ๊ณ  ์ •์˜ํ•ด์ค€๋‹ค.

 

๋กœ๊ทธ์•„์›ƒ ๋ฉ”์„œ๋“œ์ด๋‹ค.

์šฐ์„  redis์— key๋กœ ์ €์žฅํ•œ ์ด๋ฉ”์ผ์— ํ•ด๋‹นํ•˜๋Š” value ๊ฐ’์ด ์žˆ๋‹ค๋ฉด ์‚ญ์ œํ•ด์ค€๋‹ค.

๊ทธ๋ฆฌ๊ณ  ํ† ํฐ๊ฐ’์„ key๋กœ ์ €์žฅํ•œ๋‹ค.

 

 

์ž˜ ์‹คํ–‰๋˜๋Š”์ง€ ์‹ค์Šต์„ ํ•ด๋ณด์ž.

ํฌ์ŠคํŠธ๋งจ์œผ๋กœ ์ ‘์†ํ›„ ๋กœ๊ทธ์ธ์„ ํ•˜๋ฉด ํ† ํฐ์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

redis ์ปจํ…Œ์ด๋„ˆ๋กœ ์ ‘์†ํ•ด์„œ key๊ฐ’์œผ๋กœ ์ด๋ฉ”์ผ์ด ์ž˜ ์ €์žฅ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž

docker ps

์‹คํ–‰์ค‘์ธ ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ณด์—ฌ์ค€๋‹ค.

docker exec -it <container Id> redis-cli --raw

์ด ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด์„œ redis ์ปจํ…Œ์ด๋„ˆ๋กœ ์ ‘์†ํ•œ๋‹ค.

// ๋ชจ๋“  Key ์กฐํšŒ
keys *

// key์— ํ•ด๋‹นํ•˜๋Š” value ์กฐํšŒ
get <key>

๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅํ•ด๋ณด๋ฉด ํ† ํฐ์ด ์ž˜ ์ €์žฅ๋˜์—ˆ๋‹ค!!

 

 

์ด์ œ ๋กœ๊ทธ์•„์›ƒ์„ ํ•ด๋ณด์ž

ํฌ์ŠคํŠธ๋งจ์—์„œ Authorization -> Bearer Token์„ ์„ ํƒํ›„ ํ† ํฐ์„ ์ž…๋ ฅํ•œ๋‹ค.

 

 

๋กœ๊ทธ์•„์›ƒ์ด ๋˜์—ˆ์œผ๋ฉด redis๋กœ ๊ฐ€์„œ ํ•ด๋‹น ํ† ํฐ์„ ์ €์žฅํ•˜์˜€๋Š”์ง€ ํ™•์ธํ•ด๋ณด์ž

redis ์ปจํ…Œ์ด๋„ˆ์—์„œ ๋ชจ๋“  keys ๊ฐ’๋“ค์„ ์กฐํšŒํ•ด๋ณด๋ฉด ํ† ํฐ์ด ์ž˜ ์ €์žฅ๋œ๊ฑธ ํ™•์ธํ• ์ˆ˜ ์žˆ๋‹ค.

 

๋‹ค์‹œ ์ด ํ† ํฐ์œผ๋กœ ์ ‘์†์„ ์‹คํ–‰ํ•ด๋ณด์ž.

 

๋กœ๊ทธ๋ฅผ ๋ณด๋ฉด ๋กœ๊ทธ์•„์›ƒ ํ† ํฐ์ด๋ผ๊ณ  ์•Œ๋ ค์ค€๋‹ค.

๋!!

 

 

 

<์ฃผ์˜>

ํ”„๋กœ์ ํŠธ์šฉ์œผ๋กœ Redis๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ AWS์„ ํ†ตํ•ด ๋ฐฐํฌํ•˜๋ฉด ๊ณผ๊ธˆ์ด ์—„์ฒญ ๋‚˜์˜ฌ์ˆ˜์žˆ๋‹ค.

ํ•„์ž๋Š” ์•ฝ 250๋งŒ์› ์ •๋„ ๊ณผ๊ธˆ์ด ๋‚˜์˜จ ๊ฒฝํ—˜์ด ์žˆ๋‹ค...^^;

๋งŒ์•ฝ ํ”„๋กœ์ ํŠธ๋ฅผ ์œ„ํ•ด redis๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ๋ฐฐํฌํ•œํ›„์—๋Š” ๊ฐ€๋Šฅํ•œ ๋นจ๋ฆฌ ์„œ๋ฒ„๋ฅผ ์ค‘์ง€์‹œํ‚ค๊ณ  ๊ผญ ๋ชจ๋“  ์„œ๋น„์Šค๋ฅผ ์‚ญ์ œํ•˜์ž!!

 

 

 

์ฐธ๊ณ ํ•˜๋ฉด ์ข‹์„ ์ž๋ฃŒ

https://freeblogger.tistory.com/10

 

redis-cli ๋ช…๋ น์–ด ์ •๋ฆฌ

redis-cli ๋ช…๋ น์–ด ์ •๋ฆฌ redis-cli ์ ‘์† ํ˜ธ์ŠคํŠธ๋ช…๊ณผ ํฌํŠธ๋ฒˆํ˜ธ๋ฅผ ์ƒ๋žตํ•˜๋ฉด localhost์˜ 6379๋กœ ์ ‘์†๋ฉ๋‹ˆ๋‹ค. -n db๋ฒˆํ˜ธ -a ๋น„๋ฐ€๋ฒˆํ˜ธ -s ์†Œ์ผ“ -u ์„œ๋ฒ„ url ๋“ฑ ์ ‘์† ์‹œ ๋‹ค์–‘ํ•œ ์˜ต์…˜ ์„ค์ •์ด ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. # localhost

freeblogger.tistory.com

 

 

์ฐธ๊ณ  

https://velog.io/@hkyo96/Spring-RedisTemplate-Serializer-์„ค์ •

 

Spring RedisTemplate Serializer ์„ค์ •

Spring Data Redis / RedisTemplate์œผ๋กœ ๊ฐ์ฒด ์ €์žฅ ์‹œ ์‚ฌ์šฉํ•  Serializer์˜ ์žฅ๋‹จ์  ๋ถ„์„ ๋ฐ ์ ์šฉ ๋ฐฉ๋ฒ•.

velog.io