Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
implementation 'com.google.code.gson:gson'
implementation 'com.h2database:h2'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testCompileOnly 'org.projectlombok:lombok'
}
3 changes: 2 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#Tue May 07 23:44:13 KST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.3-all.zip
8 changes: 0 additions & 8 deletions src/main/java/com/redis/cluster/RedisClusterApplication.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,11 @@

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

@SpringBootApplication
public class RedisClusterApplication {

public static void main(String[] args) {
SpringApplication.run(RedisClusterApplication.class, args);
}

@Bean
public PasswordEncoder passwordEncoder() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
}
12 changes: 12 additions & 0 deletions src/main/java/com/redis/cluster/common/CacheKey.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.redis.cluster.common;

public class CacheKey {

private CacheKey() {
}

public static final int DEFAULT_EXPIRE_SEC = 60;

public static final String USER = "user";
public static final int USER_EXPIRE_SEC = 180;
}
39 changes: 39 additions & 0 deletions src/main/java/com/redis/cluster/config/RedisCacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.redis.cluster.config;

import com.redis.cluster.common.CacheKey;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.CacheKeyPrefix;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

@Configuration
@EnableCaching
public class RedisCacheConfig {

@Bean(name = "cacheManager")
public RedisCacheManager cacheManager(RedisConnectionFactory connectionFactory) {

RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig()
.disableCachingNullValues()
.entryTtl(Duration.ofSeconds(CacheKey.DEFAULT_EXPIRE_SEC))
.computePrefixWith(CacheKeyPrefix.simple())
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()));

Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
// User
cacheConfigurations.put(CacheKey.USER, RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(CacheKey.USER_EXPIRE_SEC)));

return RedisCacheManager.RedisCacheManagerBuilder.fromConnectionFactory(connectionFactory).cacheDefaults(configuration)
.withInitialCacheConfigurations(cacheConfigurations).build();
}
}
54 changes: 27 additions & 27 deletions src/main/java/com/redis/cluster/controller/RedisController.java
Original file line number Diff line number Diff line change
@@ -1,45 +1,45 @@
package com.redis.cluster.controller;

import com.redis.cluster.common.CacheKey;
import com.redis.cluster.entity.User;
import com.redis.cluster.repo.UserJpaRepo;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@RequiredArgsConstructor
@RequestMapping("/redis")
@RestController
public class RedisController {

private final RedisTemplate<String, String> redisTemplate;
private final UserJpaRepo userJpaRepo;
private final PasswordEncoder passwordEncoder;

@GetMapping("/ops/value")
public List<String> redisClusterTest() {
ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
Collection<String> keys = new ArrayList<>();
for (int i = 0; i < 10; i++) {
keys.add("valueOps_" + i);
valueOps.set("valueOps_" + i, String.valueOf(i));
}
return valueOps.multiGet(keys);
@Cacheable(value = CacheKey.USER, key = "#msrl", unless = "#result == null")
@GetMapping("/user/{msrl}")
public User findOne(@PathVariable long msrl) {
return userJpaRepo.findById(msrl).orElse(null);
}

@PostMapping("/user")
@ResponseBody
public User postUser(@RequestBody User user) {
return userJpaRepo.save(user);
}

@CachePut(value = CacheKey.USER, key = "#user.msrl")
@PutMapping("/user")
@ResponseBody
public User putUser(@RequestBody User user) {
return userJpaRepo.save(user);
}

@PostMapping("/post/user")
public void redisClusterPostUser() {
userJpaRepo.save(User.builder()
.uid("strongdaddy@naver.com")
.password(passwordEncoder.encode("1234"))
.name("strongdaddy")
.roles(Collections.singletonList("ROLE_USER"))
.build());
@CacheEvict(value = CacheKey.USER, key = "#msrl")
@DeleteMapping("/user/{msrl}")
@ResponseBody
public boolean deleteUser(@PathVariable long msrl) {
userJpaRepo.deleteById(msrl);
return true;
}
}
13 changes: 11 additions & 2 deletions src/main/resources/application.yml
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
server:
port: 8081

logging:
level:
root: warn
com.rest.api: debug

spring:
datasource:
url: jdbc:h2:tcp://localhost/~/test
driver-class-name: org.h2.Driver
username: sa
jpa:
database-platform: org.hibernate.dialect.H2Dialect
properties.hibernate.hbm2ddl.auto: update
properties.hibernate:
hbm2ddl.auto: update
format_sql: true
showSql: true
generate-ddl: true
redis:
cluster:
nodes:
Expand All @@ -19,4 +27,5 @@ spring:
- 15.164.98.87:6400
- 15.164.98.87:6401
- 15.164.98.87:6402
password: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
max-redirects: 3
password: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Original file line number Diff line number Diff line change
@@ -1,42 +1,107 @@
package com.redis.cluster.controller;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.redis.cluster.entity.User;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
import org.junit.FixMethodOrder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.MethodSorters;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.json.JacksonJsonParser;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;

import static org.hamcrest.Matchers.hasSize;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import java.util.Collections;

import static org.hamcrest.Matchers.greaterThan;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;


@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class RedisControllerTest {

@Autowired
private MockMvc mockMvc;

@Autowired
private ObjectMapper objectMapper;

private long msrl;

@Before
public void setUp() throws Exception {
User user = User.builder()
.uid("happydaddy@naver.com")
.name("happydaddy")
.password("password")
.roles(Collections.singletonList("ROLE_USER"))
.build();
MvcResult action = mockMvc.perform(post("/redis/user")
.header("Accept", "application/json;charset=UTF-8")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.msrl").value(greaterThan(0)))
.andExpect(jsonPath("$.uid").value("happydaddy@naver.com"))
.andExpect(jsonPath("$.name").value("happydaddy"))
.andExpect(jsonPath("$.roles").isArray())
.andReturn();

String resultString = action.getResponse().getContentAsString();
JacksonJsonParser jsonParser = new JacksonJsonParser();
msrl = Long.valueOf(jsonParser.parseMap(resultString).get("msrl").toString());
}

@Test
public void opsForValue() throws Exception {
mockMvc.perform(get("/redis/ops/value"))
public void A_getUser() throws Exception {
mockMvc.perform(get("/redis/user/" + msrl))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$").isArray())
.andExpect(jsonPath("$", hasSize(10)));
.andExpect(jsonPath("$.msrl").value(msrl))
.andExpect(jsonPath("$.uid").value("happydaddy@naver.com"))
.andExpect(jsonPath("$.name").value("happydaddy"))
.andExpect(jsonPath("$.roles[0]").value("ROLE_USER"));
}

@Test
public void postUser() throws Exception {
mockMvc.perform(post("/redis/post/user"))
public void B_putUser() throws Exception {
User user = User.builder()
.msrl(msrl)
.uid("happydaddy@naver.com")
.name("happydaddy_re")
.roles(Collections.singletonList("ROLE_ADMIN")).build();
mockMvc.perform(put("/redis/user")
.header("Accept", "application/json;charset=UTF-8")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(user)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.msrl").value(msrl))
.andExpect(jsonPath("$.uid").value("happydaddy@naver.com"))
.andExpect(jsonPath("$.name").value("happydaddy_re"))
.andExpect(jsonPath("$.roles[0]").value("ROLE_ADMIN"));
}

@After
public void delUser() throws Exception {
mockMvc.perform(delete("/redis/user/" + msrl))
.andDo(print())
.andExpect(status().isOk());

}
}