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 2e2c789

Browse files
committed
feat: add junit test for java code
添加 Java 代码及单元测试
1 parent 8735131 commit 2e2c789

File tree

11 files changed

+389
-3
lines changed

11 files changed

+389
-3
lines changed

‎README.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@
2424
| 2 | Redis 使用手册[2019] | 黄健宏 | 帮助读者学习如何将 Redis 应用到实际开发中,内容涵盖最新的 Redis 5。 |
2525

2626

27-
学习下面知识之前,先来[感受一波 Redis 面试连环炮](/docs/redis-interview.md)
28-
2927
## Redis 数据结构与应用
3028

3129
### [String 字符串](/docs/redis-string-introduction.md)

‎java/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,6 @@ repositories {
1313
dependencies {
1414
testCompile group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.5.2'
1515
compile group: 'redis.clients', name: 'jedis', version: '3.1.0'
16+
compile group: 'commons-codec', name: 'commons-codec', version: '1.13'
17+
1618
}

‎java/src/main/java/LoginSession.java

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import org.apache.commons.codec.binary.Hex;
2+
import redis.clients.jedis.Jedis;
3+
4+
import java.security.MessageDigest;
5+
import java.security.NoSuchAlgorithmException;
6+
import java.time.Instant;
7+
import java.util.Random;
8+
9+
10+
public class LoginSession {
11+
12+
private final String SESSION_TOKEN_KEY = "SESSION:TOKEN";
13+
private final String SESSION_EXPIRE_TS_KEY = "SESSION:EXPIRE";
14+
15+
private final String SESSION_NOT_LOGIN = "SESSION_NOT_LOGIN";
16+
private final String SESSION_EXPIRE = "SESSION_EXPIRE";
17+
private final String SESSION_TOKEN_CORRECT = "SESSION_TOKEN_CORRECT";
18+
private final String SESSION_TOKEN_INCORRECT = "SESSION_TOKEN_INCORRECT";
19+
20+
private Jedis client;
21+
private String userId;
22+
23+
public LoginSession(Jedis client, String userId) {
24+
this.client = client;
25+
this.userId = userId;
26+
}
27+
28+
/**
29+
* 生成随机token
30+
*
31+
* @return token
32+
*/
33+
private String generateToken() {
34+
byte[] b = new byte[256];
35+
new Random().nextBytes(b);
36+
37+
MessageDigest messageDigest;
38+
39+
String sessionToken = "";
40+
try {
41+
messageDigest = MessageDigest.getInstance("SHA-256");
42+
byte[] hash = messageDigest.digest(b);
43+
sessionToken = Hex.encodeHexString(hash);
44+
} catch (NoSuchAlgorithmException e) {
45+
e.printStackTrace();
46+
}
47+
return sessionToken;
48+
}
49+
50+
/**
51+
* 创建会话,并返回token
52+
*
53+
* @param timeout 过期时长
54+
* @return token
55+
*/
56+
public String create(int timeout) {
57+
String token = generateToken();
58+
long expireTime = Instant.now().getEpochSecond() + timeout;
59+
client.hset(SESSION_TOKEN_KEY, userId, token);
60+
client.hset(SESSION_EXPIRE_TS_KEY, userId, String.valueOf(expireTime));
61+
return token;
62+
}
63+
64+
public String create() {
65+
// 设置默认过期时长
66+
int defaultTimeout = 30 * 24 * 3600;
67+
return create(defaultTimeout);
68+
}
69+
70+
/**
71+
* 校验token
72+
*
73+
* @param token 输入的token
74+
* @return 校验结果
75+
*/
76+
public String validate(String token) {
77+
String sessionToken = client.hget(SESSION_TOKEN_KEY, userId);
78+
String expireTimeStr = client.hget(SESSION_EXPIRE_TS_KEY, userId);
79+
80+
if (sessionToken == null || expireTimeStr == null) {
81+
return SESSION_NOT_LOGIN;
82+
}
83+
84+
Long expireTime = Long.parseLong(expireTimeStr);
85+
if (Instant.now().getEpochSecond() > expireTime) {
86+
return SESSION_EXPIRE;
87+
}
88+
89+
if (sessionToken.equals(token)) {
90+
return SESSION_TOKEN_CORRECT;
91+
}
92+
return SESSION_TOKEN_INCORRECT;
93+
}
94+
95+
/**
96+
* 销毁会话
97+
*/
98+
public void destroy() {
99+
client.hdel(SESSION_TOKEN_KEY, userId);
100+
client.hdel(SESSION_EXPIRE_TS_KEY, userId);
101+
}
102+
}

‎java/src/main/java/Paginate.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import redis.clients.jedis.Jedis;
2+
3+
import java.util.List;
4+
5+
public class Paginate {
6+
7+
private Jedis client;
8+
private String key;
9+
10+
public Paginate(Jedis client, String key) {
11+
this.client = client;
12+
this.key = key;
13+
}
14+
15+
/**
16+
* 添加元素到分页列表中
17+
*
18+
* @param item 元素
19+
*/
20+
public void add(String item) {
21+
client.lpush(key, item);
22+
}
23+
24+
/**
25+
* 根据页码取出指定数量的元素
26+
*
27+
* @param page 页码
28+
* @param pageSize 数量
29+
* @return 元素列表
30+
*/
31+
public List<String> getPage(int page, int pageSize) {
32+
long start = (page - 1) * pageSize;
33+
long end = page * pageSize - 1;
34+
return client.lrange(key, start, end);
35+
}
36+
37+
/**
38+
* 获取列表的元素数量
39+
*
40+
* @return 总数
41+
*/
42+
public Long getTotalCount() {
43+
return client.llen(key);
44+
}
45+
}

‎java/src/main/java/Ranking.java

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import redis.clients.jedis.Jedis;
2+
import redis.clients.jedis.Tuple;
3+
4+
import java.util.Calendar;
5+
import java.util.Set;
6+
7+
/**
8+
* @author bingoyang
9+
* @date 2019年9月7日
10+
*/
11+
public class Ranking {
12+
private Jedis client = new Jedis();
13+
private Calendar calendar = Calendar.getInstance();
14+
15+
public Ranking() {
16+
client.flushAll();
17+
calendar.setFirstDayOfWeek(Calendar.MONDAY);
18+
}
19+
20+
private String getDayRankKey() {
21+
return String.format("rank:day:%s%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH));
22+
}
23+
24+
private String getWeekRankKey() {
25+
return String.format("rank:week:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.WEEK_OF_YEAR));
26+
}
27+
28+
private String getMonthRankKey() {
29+
return String.format("rank:month:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH));
30+
}
31+
32+
public void incr(String user, double score) {
33+
client.zincrby(getDayRankKey(), score, user);
34+
client.zincrby(getWeekRankKey(), score, user);
35+
client.zincrby(getMonthRankKey(), score, user);
36+
}
37+
38+
/**
39+
* 获取日榜单topN
40+
*
41+
* @param n 前n位
42+
* @return 结果集合
43+
*/
44+
public Set<Tuple> getTodayTopNWithScores(long n) {
45+
return client.zrevrangeWithScores(getDayRankKey(), 0, n - 1);
46+
}
47+
48+
/**
49+
* 获取周榜单topN
50+
*
51+
* @param n 前n位
52+
* @return 结果集合
53+
*/
54+
public Set<Tuple> getWeekTopNWithScores(long n) {
55+
return client.zrevrangeWithScores(getWeekRankKey(), 0, n - 1);
56+
}
57+
58+
/**
59+
* 获取月榜单topN
60+
*
61+
* @param n 前n位
62+
* @return 结果集合
63+
*/
64+
public Set<Tuple> getMonthTopNWithScores(long n) {
65+
return client.zrevrangeWithScores(getMonthRankKey(), 0, n - 1);
66+
}
67+
}

‎java/src/main/java/URLShorten.java

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import redis.clients.jedis.Jedis;
2+
3+
public class URLShorten {
4+
private Jedis client;
5+
6+
private final String URL_HASH_SHORT_SOURCE_KEY = "url_hash:short_source";
7+
private final String ID_COUNTER = "short_url:id_counter";
8+
9+
/**
10+
* 将10进制数转换为36进制字符串
11+
*
12+
* @param number 10进制数
13+
* @return 36进制字符串
14+
*/
15+
private String base10ToBase36(long number) {
16+
String alphabets = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
17+
char[] chars = alphabets.toCharArray();
18+
StringBuilder result = new StringBuilder();
19+
while (number != 0) {
20+
int i = (int) number % 36;
21+
number /= 36;
22+
result.insert(0, chars[i]);
23+
}
24+
return result.toString();
25+
}
26+
27+
public URLShorten(Jedis client) {
28+
this.client = client;
29+
// 设置初始ID值,保留1-5位的短码,从6位的短码开始生成
30+
this.client.set(ID_COUNTER, String.valueOf((long) Math.pow(36, 5) - 1));
31+
}
32+
33+
/**
34+
* 对源网址进行缩短,返回短网址ID
35+
*
36+
* @param sourceUrl 源网址
37+
* @return 短网址ID
38+
*/
39+
public String shorten(String sourceUrl) {
40+
long newId = client.incr(ID_COUNTER);
41+
String shortId = base10ToBase36(newId);
42+
client.hset(URL_HASH_SHORT_SOURCE_KEY, shortId, sourceUrl);
43+
return shortId;
44+
}
45+
46+
/**
47+
* 根据短网址ID,返回对应的源网址
48+
*
49+
* @param shortId 短网址ID
50+
* @return 源网址
51+
*/
52+
public String restore(String shortId) {
53+
return client.hget(URL_HASH_SHORT_SOURCE_KEY, shortId);
54+
}
55+
}

‎java/src/test/java/DistributedLockTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
public class DistributedLockTest {
1010

1111
@Test
12-
public void test() throws InterruptedException {
12+
public void testDistributedLock() throws InterruptedException {
1313
Jedis jedis = new Jedis();
1414
jedis.flushAll();
1515

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import org.junit.jupiter.api.Test;
2+
import redis.clients.jedis.Jedis;
3+
4+
import static org.junit.jupiter.api.Assertions.assertEquals;
5+
6+
public class LoginSessionTest {
7+
8+
@Test
9+
public void testLoginSession() {
10+
Jedis client = new Jedis();
11+
client.flushAll();
12+
LoginSession session = new LoginSession(client, "bingo");
13+
14+
String token = session.create();
15+
16+
String res = session.validate("this is a wrong token");
17+
assertEquals( "SESSION_TOKEN_INCORRECT", res);
18+
19+
res = session.validate(token);
20+
assertEquals("SESSION_TOKEN_CORRECT", res);
21+
22+
session.destroy();
23+
res = session.validate(token);
24+
assertEquals("SESSION_NOT_LOGIN", res);
25+
}
26+
}

‎java/src/test/java/PaginateTest.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import org.junit.jupiter.api.Test;
2+
import redis.clients.jedis.Jedis;
3+
4+
import java.util.Arrays;
5+
6+
import static org.junit.jupiter.api.Assertions.assertEquals;
7+
8+
public class PaginateTest {
9+
10+
@Test
11+
public void testPaginate() {
12+
Jedis client = new Jedis();
13+
client.flushAll();
14+
15+
Paginate topics = new Paginate(client, "user-topics");
16+
for (int i = 0; i < 24; ++i) {
17+
topics.add(i + "");
18+
}
19+
20+
// 取总数
21+
assertEquals(24, topics.getTotalCount());
22+
23+
// 以每页5条数据的方式取出第1页数据
24+
assertEquals(Arrays.asList("23", "22", "21", "20", "19"),
25+
topics.getPage(1, 5));
26+
27+
// 以每页10条数据的方式取出第1页数据
28+
assertEquals(Arrays.asList("23", "22", "21", "20", "19", "18", "17", "16", "15", "14"),
29+
topics.getPage(1, 10));
30+
31+
// 以每页5条数据的方式取出第5页数据
32+
assertEquals(Arrays.asList("3", "2", "1", "0"),
33+
topics.getPage(5, 5));
34+
35+
}
36+
}

‎java/src/test/java/RankingTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import org.junit.jupiter.api.Test;
2+
import redis.clients.jedis.Tuple;
3+
4+
import java.util.HashSet;
5+
import java.util.Set;
6+
7+
import static org.junit.jupiter.api.Assertions.assertEquals;
8+
9+
10+
public class RankingTest {
11+
12+
@Test
13+
public void testRanking() {
14+
Ranking ranking = new Ranking();
15+
16+
ranking.incr("bingo", 5);
17+
ranking.incr("iris", 3);
18+
ranking.incr("lily", 4);
19+
ranking.incr("helen", 6);
20+
21+
Set<Tuple> expectResult = new HashSet<Tuple>() {{
22+
add(new Tuple("helen", 6.0));
23+
add(new Tuple("bingo", 5.0));
24+
}};
25+
assertEquals(expectResult, ranking.getTodayTopNWithScores(2));
26+
assertEquals(expectResult, ranking.getWeekTopNWithScores(2));
27+
28+
expectResult.add(new Tuple("lily", 4.0));
29+
assertEquals(expectResult, ranking.getMonthTopNWithScores(3));
30+
}
31+
}

0 commit comments

Comments
(0)

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