Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b88ebb4

Browse files
author
kimyonghwa
committed
Spring data redis
- initialize redis cluster
1 parent 63132f0 commit b88ebb4

File tree

11 files changed

+354
-26
lines changed

11 files changed

+354
-26
lines changed

‎build.gradle

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ dependencies {
2323
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
2424
implementation 'org.springframework.boot:spring-boot-starter-freemarker'
2525
implementation 'org.springframework.boot:spring-boot-starter-web'
26-
implementation 'org.springframework.boot:spring-boot-starter-redis:1.4.7.RELEASE'
26+
implementation 'org.springframework.boot:spring-boot-starter-security'
27+
implementation 'org.springframework.boot:spring-boot-starter-data-redis'
2728
implementation 'com.google.code.gson:gson'
2829
compileOnly 'org.projectlombok:lombok'
2930
runtimeOnly 'com.h2database:h2'
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.redis.cluster;
2+
3+
import org.springframework.boot.SpringApplication;
4+
import org.springframework.boot.autoconfigure.SpringBootApplication;
5+
import org.springframework.context.annotation.Bean;
6+
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
7+
import org.springframework.security.crypto.password.PasswordEncoder;
8+
9+
@SpringBootApplication
10+
public class RedisClusterApplication {
11+
12+
public static void main(String[] args) {
13+
SpringApplication.run(RedisClusterApplication.class, args);
14+
}
15+
16+
@Bean
17+
public PasswordEncoder passwordEncoder() {
18+
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
19+
}
20+
}

‎src/main/java/com/redis/cluster/RedisCluterApplication.java

Lines changed: 0 additions & 12 deletions
This file was deleted.
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.redis.cluster.controller;
2+
3+
import com.redis.cluster.entity.User;
4+
import com.redis.cluster.repo.UserJpaRepo;
5+
import lombok.RequiredArgsConstructor;
6+
import org.springframework.data.redis.core.RedisTemplate;
7+
import org.springframework.data.redis.core.ValueOperations;
8+
import org.springframework.security.crypto.password.PasswordEncoder;
9+
import org.springframework.web.bind.annotation.*;
10+
11+
import java.util.ArrayList;
12+
import java.util.Collection;
13+
import java.util.Collections;
14+
import java.util.List;
15+
16+
@RequiredArgsConstructor
17+
@RequestMapping("/redis")
18+
@RestController
19+
public class RedisController {
20+
21+
private final RedisTemplate<String, String> redisTemplate;
22+
private final UserJpaRepo userJpaRepo;
23+
private final PasswordEncoder passwordEncoder;
24+
25+
@GetMapping("/ops/value")
26+
public List<String> redisClusterTest() {
27+
ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
28+
Collection<String> keys = new ArrayList<>();
29+
for (int i = 0; i < 10; i++) {
30+
keys.add("valueOps_" + i);
31+
valueOps.set("valueOps_" + i, String.valueOf(i));
32+
}
33+
return valueOps.multiGet(keys);
34+
}
35+
36+
@PostMapping("/post/user")
37+
public void redisClusterPostUser() {
38+
userJpaRepo.save(User.builder()
39+
.uid("strongdaddy@naver.com")
40+
.password(passwordEncoder.encode("1234"))
41+
.name("strongdaddy")
42+
.roles(Collections.singletonList("ROLE_USER"))
43+
.build());
44+
}
45+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.redis.cluster.entity;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Getter;
7+
import lombok.NoArgsConstructor;
8+
9+
import javax.persistence.*;
10+
import java.io.Serializable;
11+
import java.util.ArrayList;
12+
import java.util.List;
13+
14+
@Entity // jpa entity임을 알립니다.
15+
@Builder // builder를 사용할수 있게 합니다.
16+
@Getter // user 필드값의 getter를 자동으로 생성합니다.
17+
@NoArgsConstructor // 인자없는 생성자를 자동으로 생성합니다.
18+
@AllArgsConstructor // 인자를 모두 갖춘 생성자를 자동으로 생성합니다.
19+
@Table(name = "user") // 'user' 테이블과 매핑됨을 명시
20+
//@RedisHash("user")
21+
public class User implements Serializable {
22+
@Id // pk
23+
@GeneratedValue(strategy = GenerationType.IDENTITY)
24+
private long msrl;
25+
@Column(nullable = false, unique = true, length = 50)
26+
private String uid;
27+
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
28+
@Column(length = 100)
29+
private String password;
30+
@Column(nullable = false, length = 100)
31+
private String name;
32+
33+
@ElementCollection(fetch = FetchType.EAGER)
34+
@Builder.Default
35+
private List<String> roles = new ArrayList<>();
36+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.redis.cluster.repo;
2+
3+
import com.redis.cluster.entity.User;
4+
import org.springframework.data.jpa.repository.JpaRepository;
5+
6+
import java.util.Optional;
7+
8+
public interface UserJpaRepo extends JpaRepository<User, Long> {
9+
10+
Optional<User> findByUid(String email);
11+
}

‎src/main/resources/application.yml

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1-
port: 8080
1+
server:
2+
port: 8081
23

34
spring:
5+
datasource:
6+
url: jdbc:h2:tcp://localhost/~/test
7+
driver-class-name: org.h2.Driver
8+
username: sa
9+
jpa:
10+
database-platform: org.hibernate.dialect.H2Dialect
11+
properties.hibernate.hbm2ddl.auto: update
12+
showSql: true
413
redis:
514
cluster:
615
nodes:
716
- 15.164.98.87:6300
817
- 15.164.98.87:6301
9-
- 15.164.98.87:6302
18+
- 15.164.98.87:6302
19+
- 15.164.98.87:6400
20+
- 15.164.98.87:6401
21+
- 15.164.98.87:6402
22+
password: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
package com.redis.cluster;
2+
3+
import org.junit.Test;
4+
import org.junit.runner.RunWith;
5+
import org.slf4j.Logger;
6+
import org.slf4j.LoggerFactory;
7+
import org.springframework.beans.factory.annotation.Autowired;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.data.geo.Distance;
10+
import org.springframework.data.geo.Point;
11+
import org.springframework.data.redis.connection.DataType;
12+
import org.springframework.data.redis.core.*;
13+
import org.springframework.test.context.junit4.SpringRunner;
14+
15+
import java.util.ArrayList;
16+
import java.util.Collection;
17+
import java.util.List;
18+
import java.util.Set;
19+
import java.util.concurrent.TimeUnit;
20+
21+
import static org.junit.Assert.*;
22+
23+
@RunWith(SpringRunner.class)
24+
@SpringBootTest
25+
public class RedisClusterTest {
26+
27+
private Logger log = LoggerFactory.getLogger(this.getClass());
28+
29+
@Autowired
30+
private RedisTemplate<String, String> redisTemplate;
31+
32+
/**
33+
* 문자 데이터 구조 처리
34+
*/
35+
@Test
36+
public void opsValue() {
37+
ValueOperations<String, String> valueOps = redisTemplate.opsForValue();
38+
Collection<String> cacheKeys = new ArrayList<>();
39+
String cacheKey = "value_";
40+
for (int i = 0; i < 10; i++) {
41+
cacheKeys.add(cacheKey + i);
42+
valueOps.set(cacheKey + i, String.valueOf(i), 60, TimeUnit.SECONDS);
43+
}
44+
List<String> values = valueOps.multiGet(cacheKeys);
45+
assertNotNull(values);
46+
assertEquals(10, values.size());
47+
log.info("##### opsValue #####");
48+
log.info("{}", values);
49+
}
50+
51+
/**
52+
* List 데이터 구조 처리 - 순서 있음. value 중복 허용
53+
*/
54+
@Test
55+
public void opsList() {
56+
ListOperations<String, String> listOps = redisTemplate.opsForList();
57+
String cacheKey = "valueList";
58+
for (int i = 0; i < 10; i++)
59+
listOps.leftPush(cacheKey, String.valueOf(i));
60+
61+
assertSame(DataType.LIST, redisTemplate.type(cacheKey));
62+
assertSame(10L, listOps.size(cacheKey));
63+
log.info("##### opsList #####");
64+
log.info("{}", listOps.range(cacheKey, 0, 10));
65+
assertEquals("0", listOps.rightPop(cacheKey));
66+
assertEquals("9", listOps.leftPop(cacheKey));
67+
assertEquals(true, redisTemplate.delete(cacheKey));
68+
}
69+
70+
/**
71+
* Hash 데이터 구조 처리 - 순서 없음. key 중복허용 안함, value 중복 허용
72+
*/
73+
@Test
74+
public void opsHash() {
75+
HashOperations<String, String, String> hashOps = redisTemplate.opsForHash();
76+
String cacheKey = "valueHash";
77+
for (int i = 0; i < 10; i++)
78+
hashOps.put(cacheKey, "key_" + i, "value_" + i);
79+
80+
assertSame(DataType.HASH, redisTemplate.type(cacheKey));
81+
assertSame(10L, hashOps.size(cacheKey));
82+
log.info("##### opsHash #####");
83+
Set<String> hkeys = hashOps.keys(cacheKey);
84+
for (String hkey : hkeys) {
85+
log.info("{} / {}", hkey, hashOps.get(cacheKey, hkey));
86+
}
87+
88+
assertEquals("value_5", hashOps.get(cacheKey, "key_5"));
89+
assertSame(1L, hashOps.delete(cacheKey, "key_5"));
90+
assertSame(null, hashOps.get(cacheKey, "key_5"));
91+
}
92+
93+
/**
94+
* Set 데이터 구조 처리 - 순서 없음, value 중복 허용 안함
95+
*/
96+
@Test
97+
public void opsSet() {
98+
SetOperations<String, String> setOps = redisTemplate.opsForSet();
99+
String cacheKey = "valueSet";
100+
for (int i = 0; i < 10; i++)
101+
setOps.add(cacheKey, String.valueOf(i));
102+
103+
assertSame(DataType.SET, redisTemplate.type(cacheKey));
104+
assertSame(10L, setOps.size(cacheKey));
105+
106+
log.info("##### opsList #####");
107+
log.info("{}", setOps.members(cacheKey));
108+
109+
assertEquals(true, setOps.isMember(cacheKey, "5"));
110+
}
111+
112+
/**
113+
* SortedSet 데이터 구조 처리 - 순서 있음, value 중복 허용 안함
114+
*/
115+
@Test
116+
public void opsSortedSet() {
117+
ZSetOperations<String, String> zsetOps = redisTemplate.opsForZSet();
118+
String cacheKey = "valueZSet";
119+
for (int i = 0; i < 10; i++)
120+
zsetOps.add(cacheKey, String.valueOf(i), i);
121+
122+
assertSame(DataType.ZSET, redisTemplate.type(cacheKey));
123+
assertSame(10L, zsetOps.size(cacheKey));
124+
log.info("##### opsSortedSet #####");
125+
log.info("{}", zsetOps.range(cacheKey, 0, 10));
126+
assertSame(0L, zsetOps.reverseRank(cacheKey, "9"));
127+
}
128+
129+
/**
130+
* Geo 데이터 구조 처리 - 좌표 정보 처리, 타입은 zset으로 저장.
131+
*/
132+
@Test
133+
public void opsGeo() {
134+
GeoOperations<String, String> geoOps = redisTemplate.opsForGeo();
135+
String[] cities = {"서울", "부산"};
136+
String[] gu = {"강남구", "서초구", "관악구", "동작구", "마포구", "사하구", "해운대구", "영도구", "동래구", "수영구"};
137+
String cacheKey = "valueGeo";
138+
for (int x = 0; x < cities.length; x++) {
139+
for (int y = 0; y < gu.length / 2; y++) {
140+
geoOps.add(cacheKey, new Point(x, y), gu[x * y]);
141+
}
142+
}
143+
log.info("##### opsGeo #####");
144+
Distance distance = geoOps.distance(cacheKey, "강남구", "동작구");
145+
assertNotNull(distance);
146+
log.info("Distance : {}", distance.getValue());
147+
List<Point> position = geoOps.position(cacheKey, "동작구");
148+
assertNotNull(position);
149+
for (Point point : position) {
150+
log.info("Position : {} x {}", point.getX(), point.getY());
151+
}
152+
}
153+
154+
/**
155+
* HyperLogLog 데이터 구조 처리 - 집합의 원소의 개수 추정, 타입은 string으로 저장.
156+
*/
157+
@Test
158+
public void opsHyperLogLog() {
159+
HyperLogLogOperations<String, String> hyperLogLogOps = redisTemplate.opsForHyperLogLog();
160+
String cacheKey = "valueHyperLogLog";
161+
String[] arr1 = {"1", "2", "2", "3", "4", "5", "5", "5", "5", "6", "7", "7", "7"};
162+
hyperLogLogOps.add(cacheKey, arr1);
163+
log.info("##### opsHyperLogLog #####");
164+
log.info("count : {}", hyperLogLogOps.size(cacheKey));
165+
redisTemplate.delete(cacheKey);
166+
}
167+
}

‎src/test/java/com/redis/cluster/RedisCluterApplicationTest.java

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.redis.cluster.controller;
2+
3+
import org.junit.Ignore;
4+
import org.junit.Test;
5+
import org.junit.runner.RunWith;
6+
import org.springframework.beans.factory.annotation.Autowired;
7+
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
8+
import org.springframework.boot.test.context.SpringBootTest;
9+
import org.springframework.test.context.junit4.SpringRunner;
10+
import org.springframework.test.web.servlet.MockMvc;
11+
12+
import static org.hamcrest.Matchers.hasSize;
13+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
14+
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
15+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
16+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
17+
18+
19+
@RunWith(SpringRunner.class)
20+
@SpringBootTest
21+
@AutoConfigureMockMvc
22+
public class RedisControllerTest {
23+
24+
@Autowired
25+
private MockMvc mockMvc;
26+
27+
@Test
28+
public void opsForValue() throws Exception {
29+
mockMvc.perform(get("/redis/ops/value"))
30+
.andDo(print())
31+
.andExpect(status().isOk())
32+
.andExpect(jsonPath("$").isArray())
33+
.andExpect(jsonPath("$", hasSize(10)));
34+
}
35+
36+
@Test
37+
public void postUser() throws Exception {
38+
mockMvc.perform(post("/redis/post/user"))
39+
.andDo(print())
40+
.andExpect(status().isOk());
41+
}
42+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /