generated from doocs/doc-template
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
添加 Java 代码及单元测试
- Loading branch information
Showing
11 changed files
with
389 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
import org.apache.commons.codec.binary.Hex; | ||
import redis.clients.jedis.Jedis; | ||
|
||
import java.security.MessageDigest; | ||
import java.security.NoSuchAlgorithmException; | ||
import java.time.Instant; | ||
import java.util.Random; | ||
|
||
|
||
public class LoginSession { | ||
|
||
private final String SESSION_TOKEN_KEY = "SESSION:TOKEN"; | ||
private final String SESSION_EXPIRE_TS_KEY = "SESSION:EXPIRE"; | ||
|
||
private final String SESSION_NOT_LOGIN = "SESSION_NOT_LOGIN"; | ||
private final String SESSION_EXPIRE = "SESSION_EXPIRE"; | ||
private final String SESSION_TOKEN_CORRECT = "SESSION_TOKEN_CORRECT"; | ||
private final String SESSION_TOKEN_INCORRECT = "SESSION_TOKEN_INCORRECT"; | ||
|
||
private Jedis client; | ||
private String userId; | ||
|
||
public LoginSession(Jedis client, String userId) { | ||
this.client = client; | ||
this.userId = userId; | ||
} | ||
|
||
/** | ||
* 生成随机token | ||
* | ||
* @return token | ||
*/ | ||
private String generateToken() { | ||
byte[] b = new byte[256]; | ||
new Random().nextBytes(b); | ||
|
||
MessageDigest messageDigest; | ||
|
||
String sessionToken = ""; | ||
try { | ||
messageDigest = MessageDigest.getInstance("SHA-256"); | ||
byte[] hash = messageDigest.digest(b); | ||
sessionToken = Hex.encodeHexString(hash); | ||
} catch (NoSuchAlgorithmException e) { | ||
e.printStackTrace(); | ||
} | ||
return sessionToken; | ||
} | ||
|
||
/** | ||
* 创建会话,并返回token | ||
* | ||
* @param timeout 过期时长 | ||
* @return token | ||
*/ | ||
public String create(int timeout) { | ||
String token = generateToken(); | ||
long expireTime = Instant.now().getEpochSecond() + timeout; | ||
client.hset(SESSION_TOKEN_KEY, userId, token); | ||
client.hset(SESSION_EXPIRE_TS_KEY, userId, String.valueOf(expireTime)); | ||
return token; | ||
} | ||
|
||
public String create() { | ||
// 设置默认过期时长 | ||
int defaultTimeout = 30 * 24 * 3600; | ||
return create(defaultTimeout); | ||
} | ||
|
||
/** | ||
* 校验token | ||
* | ||
* @param token 输入的token | ||
* @return 校验结果 | ||
*/ | ||
public String validate(String token) { | ||
String sessionToken = client.hget(SESSION_TOKEN_KEY, userId); | ||
String expireTimeStr = client.hget(SESSION_EXPIRE_TS_KEY, userId); | ||
|
||
if (sessionToken == null || expireTimeStr == null) { | ||
return SESSION_NOT_LOGIN; | ||
} | ||
|
||
Long expireTime = Long.parseLong(expireTimeStr); | ||
if (Instant.now().getEpochSecond() > expireTime) { | ||
return SESSION_EXPIRE; | ||
} | ||
|
||
if (sessionToken.equals(token)) { | ||
return SESSION_TOKEN_CORRECT; | ||
} | ||
return SESSION_TOKEN_INCORRECT; | ||
} | ||
|
||
/** | ||
* 销毁会话 | ||
*/ | ||
public void destroy() { | ||
client.hdel(SESSION_TOKEN_KEY, userId); | ||
client.hdel(SESSION_EXPIRE_TS_KEY, userId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import redis.clients.jedis.Jedis; | ||
|
||
import java.util.List; | ||
|
||
public class Paginate { | ||
|
||
private Jedis client; | ||
private String key; | ||
|
||
public Paginate(Jedis client, String key) { | ||
this.client = client; | ||
this.key = key; | ||
} | ||
|
||
/** | ||
* 添加元素到分页列表中 | ||
* | ||
* @param item 元素 | ||
*/ | ||
public void add(String item) { | ||
client.lpush(key, item); | ||
} | ||
|
||
/** | ||
* 根据页码取出指定数量的元素 | ||
* | ||
* @param page 页码 | ||
* @param pageSize 数量 | ||
* @return 元素列表 | ||
*/ | ||
public List<String> getPage(int page, int pageSize) { | ||
long start = (page - 1) * pageSize; | ||
long end = page * pageSize - 1; | ||
return client.lrange(key, start, end); | ||
} | ||
|
||
/** | ||
* 获取列表的元素数量 | ||
* | ||
* @return 总数 | ||
*/ | ||
public Long getTotalCount() { | ||
return client.llen(key); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import redis.clients.jedis.Jedis; | ||
import redis.clients.jedis.Tuple; | ||
|
||
import java.util.Calendar; | ||
import java.util.Set; | ||
|
||
/** | ||
* @author bingoyang | ||
* @date 2019/9/7 | ||
*/ | ||
public class Ranking { | ||
private Jedis client = new Jedis(); | ||
private Calendar calendar = Calendar.getInstance(); | ||
|
||
public Ranking() { | ||
client.flushAll(); | ||
calendar.setFirstDayOfWeek(Calendar.MONDAY); | ||
} | ||
|
||
private String getDayRankKey() { | ||
return String.format("rank:day:%s%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH)); | ||
} | ||
|
||
private String getWeekRankKey() { | ||
return String.format("rank:week:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.WEEK_OF_YEAR)); | ||
} | ||
|
||
private String getMonthRankKey() { | ||
return String.format("rank:month:%s%s", calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH)); | ||
} | ||
|
||
public void incr(String user, double score) { | ||
client.zincrby(getDayRankKey(), score, user); | ||
client.zincrby(getWeekRankKey(), score, user); | ||
client.zincrby(getMonthRankKey(), score, user); | ||
} | ||
|
||
/** | ||
* 获取日榜单topN | ||
* | ||
* @param n 前n位 | ||
* @return 结果集合 | ||
*/ | ||
public Set<Tuple> getTodayTopNWithScores(long n) { | ||
return client.zrevrangeWithScores(getDayRankKey(), 0, n - 1); | ||
} | ||
|
||
/** | ||
* 获取周榜单topN | ||
* | ||
* @param n 前n位 | ||
* @return 结果集合 | ||
*/ | ||
public Set<Tuple> getWeekTopNWithScores(long n) { | ||
return client.zrevrangeWithScores(getWeekRankKey(), 0, n - 1); | ||
} | ||
|
||
/** | ||
* 获取月榜单topN | ||
* | ||
* @param n 前n位 | ||
* @return 结果集合 | ||
*/ | ||
public Set<Tuple> getMonthTopNWithScores(long n) { | ||
return client.zrevrangeWithScores(getMonthRankKey(), 0, n - 1); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import redis.clients.jedis.Jedis; | ||
|
||
public class URLShorten { | ||
private Jedis client; | ||
|
||
private final String URL_HASH_SHORT_SOURCE_KEY = "url_hash:short_source"; | ||
private final String ID_COUNTER = "short_url:id_counter"; | ||
|
||
/** | ||
* 将10进制数转换为36进制字符串 | ||
* | ||
* @param number 10进制数 | ||
* @return 36进制字符串 | ||
*/ | ||
private String base10ToBase36(long number) { | ||
String alphabets = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; | ||
char[] chars = alphabets.toCharArray(); | ||
StringBuilder result = new StringBuilder(); | ||
while (number != 0) { | ||
int i = (int) number % 36; | ||
number /= 36; | ||
result.insert(0, chars[i]); | ||
} | ||
return result.toString(); | ||
} | ||
|
||
public URLShorten(Jedis client) { | ||
this.client = client; | ||
// 设置初始ID值,保留1-5位的短码,从6位的短码开始生成 | ||
this.client.set(ID_COUNTER, String.valueOf((long) Math.pow(36, 5) - 1)); | ||
} | ||
|
||
/** | ||
* 对源网址进行缩短,返回短网址ID | ||
* | ||
* @param sourceUrl 源网址 | ||
* @return 短网址ID | ||
*/ | ||
public String shorten(String sourceUrl) { | ||
long newId = client.incr(ID_COUNTER); | ||
String shortId = base10ToBase36(newId); | ||
client.hset(URL_HASH_SHORT_SOURCE_KEY, shortId, sourceUrl); | ||
return shortId; | ||
} | ||
|
||
/** | ||
* 根据短网址ID,返回对应的源网址 | ||
* | ||
* @param shortId 短网址ID | ||
* @return 源网址 | ||
*/ | ||
public String restore(String shortId) { | ||
return client.hget(URL_HASH_SHORT_SOURCE_KEY, shortId); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import org.junit.jupiter.api.Test; | ||
import redis.clients.jedis.Jedis; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
public class LoginSessionTest { | ||
|
||
@Test | ||
public void testLoginSession() { | ||
Jedis client = new Jedis(); | ||
client.flushAll(); | ||
LoginSession session = new LoginSession(client, "bingo"); | ||
|
||
String token = session.create(); | ||
|
||
String res = session.validate("this is a wrong token"); | ||
assertEquals( "SESSION_TOKEN_INCORRECT", res); | ||
|
||
res = session.validate(token); | ||
assertEquals("SESSION_TOKEN_CORRECT", res); | ||
|
||
session.destroy(); | ||
res = session.validate(token); | ||
assertEquals("SESSION_NOT_LOGIN", res); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import org.junit.jupiter.api.Test; | ||
import redis.clients.jedis.Jedis; | ||
|
||
import java.util.Arrays; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
public class PaginateTest { | ||
|
||
@Test | ||
public void testPaginate() { | ||
Jedis client = new Jedis(); | ||
client.flushAll(); | ||
|
||
Paginate topics = new Paginate(client, "user-topics"); | ||
for (int i = 0; i < 24; ++i) { | ||
topics.add(i + ""); | ||
} | ||
|
||
// 取总数 | ||
assertEquals(24, topics.getTotalCount()); | ||
|
||
// 以每页5条数据的方式取出第1页数据 | ||
assertEquals(Arrays.asList("23", "22", "21", "20", "19"), | ||
topics.getPage(1, 5)); | ||
|
||
// 以每页10条数据的方式取出第1页数据 | ||
assertEquals(Arrays.asList("23", "22", "21", "20", "19", "18", "17", "16", "15", "14"), | ||
topics.getPage(1, 10)); | ||
|
||
// 以每页5条数据的方式取出第5页数据 | ||
assertEquals(Arrays.asList("3", "2", "1", "0"), | ||
topics.getPage(5, 5)); | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import org.junit.jupiter.api.Test; | ||
import redis.clients.jedis.Tuple; | ||
|
||
import java.util.HashSet; | ||
import java.util.Set; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
|
||
|
||
public class RankingTest { | ||
|
||
@Test | ||
public void testRanking() { | ||
Ranking ranking = new Ranking(); | ||
|
||
ranking.incr("bingo", 5); | ||
ranking.incr("iris", 3); | ||
ranking.incr("lily", 4); | ||
ranking.incr("helen", 6); | ||
|
||
Set<Tuple> expectResult = new HashSet<Tuple>() {{ | ||
add(new Tuple("helen", 6.0)); | ||
add(new Tuple("bingo", 5.0)); | ||
}}; | ||
assertEquals(expectResult, ranking.getTodayTopNWithScores(2)); | ||
assertEquals(expectResult, ranking.getWeekTopNWithScores(2)); | ||
|
||
expectResult.add(new Tuple("lily", 4.0)); | ||
assertEquals(expectResult, ranking.getMonthTopNWithScores(3)); | ||
} | ||
} |
Oops, something went wrong.