需求如下:
1蕊温、用戶可以發(fā)布文章或者帖子,每個(gè)用戶發(fā)布的信息遏乔,從發(fā)布日期開始算义矛,只能在一周內(nèi)被點(diǎn)贊,且不能被同一個(gè)用戶重復(fù)點(diǎn)贊盟萨。
2凉翻、文章或者帖子信息可以按照積分或者時(shí)間來進(jìn)行排序,且能夠分頁顯示捻激。
3制轰、每個(gè)用戶發(fā)布的文章應(yīng)該歸屬到一個(gè)組里面,例如張三發(fā)布的屬于科技篇和互聯(lián)網(wǎng)篇胞谭,李四發(fā)布的屬于互聯(lián)網(wǎng)篇和人工智能篇垃杖,王五發(fā)布的屬于互聯(lián)網(wǎng)篇
4、歸組以后可以查詢出任何組與組之間交集的文章或者帖子信息丈屹。
需求分析:
1缩滨、首先我們需要知道文章信息應(yīng)該用redis哪種方式去存儲(chǔ),縱觀其五種存儲(chǔ)方式泉瞻,選擇了hash脉漏,為什么呢,因?yàn)閔ash方便擴(kuò)展和維護(hù)袖牙,后期需要修改里面某個(gè)字段內(nèi)容非常方便或者新增字段也非常方便侧巨。
2、控制一周內(nèi)部被重復(fù)點(diǎn)贊鞭达,則直接設(shè)置文章的點(diǎn)贊過期時(shí)間即可司忱,每次點(diǎn)贊前先判斷文章是否有效
3皇忿、控制重復(fù)點(diǎn)贊用set方式存儲(chǔ),技能統(tǒng)計(jì)點(diǎn)贊用戶集合坦仍,又能控制重復(fù)
4鳍烁、既然涉及到排序,那么毫無疑問用sortSet方式存儲(chǔ)
5繁扎、這里注意到無論是交集幔荒、并集、差集都只能用set集合去存梳玫。
代碼如下:
package redis.clients.test;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.util.DateTimeUtil;
public class D01_Test {
private static final int ONE_WEEK_IN_SECONDS = 7 * 86400;//每周多少秒 ?控制點(diǎn)贊過期時(shí)間
private static final int VOTE_SCORE = 10;//點(diǎn)贊積分
private static final int ARTICLES_PER_PAGE = 25;//每頁多少篇文章
static Jedis jedis=null;
static{
jedis=new Jedis("127.0.0.1");
}
/**
* 用戶發(fā)布文章信息
* @param wzzt ? 文章主題
* @param wznr文章內(nèi)容
* @param wzzb ? 文章組別 ? 多個(gè)用逗號(hào)","隔開
* @param username ?用戶名
* @return
*/
public String postArticle(String wzzt,String wznr,String wzzb,String username){
try {
/**
* 用hash方式存放文章信息(hash方式方便擴(kuò)展子彈和修改數(shù)據(jù))
*/
String id=DateTimeUtil.getDateSecondFormatNoSplit(new Date());
Map articleMap=new HashMap();
articleMap.put("wzzt", wzzt);
articleMap.put("wzid", id);
articleMap.put("wznr", wznr);
articleMap.put("username", username);
articleMap.put("fbsj", DateTimeUtil.getDateSecondFormat(new Date()));//文章發(fā)布時(shí)間
articleMap.put("votes", "1");//初始化文章的點(diǎn)贊信息
jedis.hmset("article:"+id, articleMap);
/**
* 控制文章點(diǎn)贊的過期時(shí)間為一周(set集合可以去重爹梁,設(shè)置過期時(shí)間)
*/
jedis.sadd("voted:"+id, username);//默認(rèn)存在自己點(diǎn)贊信息
jedis.expire("voted:"+id, ONE_WEEK_IN_SECONDS);
/**
* 存放文章對(duì)應(yīng)積分和時(shí)間 --初始化積分為100 ?(排序必須用sortSet集合方式)
*/
jedis.zadd("article_score:", 100, "article:"+id);
jedis.zadd("article_time:", System.currentTimeMillis() / 1000, "article:"+id);
/**
* 分組存放文章信息 (只有set集合才可以去交集、并集提澎、差集)
*/
String[] wzzbs=wzzb.split(",");
for (int i = 0; i < wzzbs.length; i++) {
String str=wzzbs[i];//遍歷出每個(gè)組別的名稱
jedis.sadd("article_group:"+str, "article:"+id);//此處只能用set集合存放組別姚垃,因?yàn)樾枰〗患?/p>
}
System.out.println(username+"============文章發(fā)布成功===========");
return "1";
} catch (Exception e) {
System.out.println("文章發(fā)布異常!");
return "-1";
}
}
/**
* 點(diǎn)贊操作
* @param wzid ? ? ? ?文章ID
* @param username ? ?點(diǎn)贊用戶
* @return
*/
public int votedArticle(String wzid,String username){
try {
//文章只有在一周內(nèi)才可以被點(diǎn)贊盼忌,在發(fā)布文章的時(shí)候此處的key過期時(shí)間為1周
if(jedis.exists("voted:"+wzid)){
//判斷是否用戶重復(fù)點(diǎn)贊
long num=jedis.sadd("voted:"+wzid, username);//因?yàn)楫?dāng)用戶點(diǎn)贊后积糯,此處再次新增時(shí)結(jié)果為0
if(num==1){
System.out.println(username+"點(diǎn)贊成功");
jedis.zincrby("article_score:", VOTE_SCORE, "article:"+wzid);//加積分
jedis.hincrBy("article:"+wzid, "votes", 1L);//修改hash里面的點(diǎn)贊數(shù)量
return 1;
}else{
System.out.println(username+"不允許重復(fù)點(diǎn)贊");
return -1;
}
}else{
System.out.println("文章已超過點(diǎn)贊時(shí)間,不允許點(diǎn)贊");
return -1;
}
} catch (Exception e) {
System.out.println("文章點(diǎn)贊異常谦纱!");
return -1;
}
}
/**
* 分頁倒序查詢文章信息
* @param type ? 1-按照積分 ?2-按照時(shí)間
* @param pageNum 當(dāng)前頁數(shù)
* @return
*/
public List> getArticles(String type,int pageNum){
List> lists=new ArrayList>();
try {
int start = (pageNum - 1) * ARTICLES_PER_PAGE;//0
int end = start + ARTICLES_PER_PAGE - 1;//24
if("1".equals(type)){
Set sets= jedis.zrevrange("article_score:", start, end);
for (String id : sets) {
Map data=jedis.hgetAll(id);
lists.add(data);
}
}else{
Set sets= jedis.zrevrange("article_time:", start, end);
for (String id : sets) {
Map data=jedis.hgetAll(id);
lists.add(data);
}
}
} catch (Exception e) {
System.out.println("查詢文章信息失敗");
}
return lists;
}
/**
* 分組獲取對(duì)應(yīng)文章信息
* 此處分組交集查詢是不能按照規(guī)則去排序的絮宁,
* 如果需要排序,可以在hash里面加時(shí)間和積分或者點(diǎn)贊數(shù)量字段后服协,直接將此處的List集合按照對(duì)應(yīng)條件進(jìn)行排序
* @param groups ? 組別 按照逗號(hào)分隔 ","
* @return
*/
public List> getArticlesByGroup(String groups){
List> lists=new ArrayList>();
try {
String[] strs=groups.split(",");
Set sets= jedis.sinter(strs);
for (String id : sets) {
Map data=jedis.hgetAll(id);
lists.add(data);
}
} catch (Exception e) {
System.out.println("分組查詢文章信息失敗");
}
return lists;
}
@Test
public void testD01_Test(){
D01_Test test=new D01_Test();
/**
* 第一步:張三 绍昂、李四 、王五各發(fā)布一篇文章偿荷,
* ? ? ?其中張三發(fā)布文章為科技(technology)篇和互聯(lián)網(wǎng)(internet)篇
* ? ? ?李四發(fā)布文章互聯(lián)網(wǎng)(internet)篇和人工智能(artificial)篇
* ? ? ?王五發(fā)布的屬于互聯(lián)網(wǎng)(internet)篇
//jedis.flushDB();
test.postArticle("張三測(cè)試", "張三發(fā)布的問內(nèi)容為科技篇和互聯(lián)網(wǎng)篇", "technology,internet", "zhangsan");
// test.postArticle("李四測(cè)試", "李四發(fā)布文章互聯(lián)網(wǎng)和人工智能", "internet,artificial", "lisi");
// test.postArticle("王五測(cè)試", "王五發(fā)布的為互聯(lián)網(wǎng)篇", "internet", "wangwu");
*/
/**
* 第二步:
* 李四和王五都點(diǎn)贊張三 ? ? ? ? ? 張三的文章ID=20170725143410
* 王五點(diǎn)贊李四李四的文章ID=20170725143502
* 王五再次點(diǎn)贊張三王五的文章ID=20170725143532
*/
// test.votedArticle("20170725143410","lisi");
//test.votedArticle("20170725143410","wangwu");
// test.votedArticle("20170725143502","wangwu");
// test.votedArticle("20170725143410","wangwu");
/**
* 第三步:此時(shí)查詢出所有文章內(nèi)容
List> resultLists=test.getArticles("1", 1);
System.out.println("==========按照積分倒敘排序start==========");
System.out.println(resultLists);
System.out.println("==========按照積分倒敘排序end==========");
List> resultLists2=test.getArticles("2", 1);
System.out.println("==========按照時(shí)間倒敘排序start==========");
System.out.println(resultLists2);
System.out.println("==========按照時(shí)間倒敘排序end==========");*/
/**
*第四步:
* ? ?查詢和互聯(lián)網(wǎng)相關(guān)的文章
* ? ?查詢出互聯(lián)網(wǎng) 窘游、科技相關(guān)的文章
*/
/* List> resultLists3=test.getArticlesByGroup("article_group:internet");
System.out.println("==========按照組別交集查詢?yōu)榛ヂ?lián)網(wǎng)的文章start==========");
System.out.println(resultLists3);
System.out.println("==========按照組別交集查詢?yōu)榛ヂ?lián)網(wǎng)的文章end==========");*/
List> resultLists4=test.getArticlesByGroup("article_group:internet,article_group:technology");
System.out.println("==========按照組別交集查詢?yōu)榛ヂ?lián)網(wǎng)且為科技的文start==========");
System.out.println(resultLists4);
System.out.println("==========按照組別交集查詢?yōu)榛ヂ?lián)網(wǎng)且為科技的文end==========");
}
}
總結(jié)分析:實(shí)際上很多人會(huì)疑問,一篇文章或者帖子起始數(shù)據(jù)量很大跳纳,redis能否承受忍饰,當(dāng)然,文章的整篇內(nèi)容是不適合存放在redis中的寺庄,畢竟數(shù)據(jù)量比較大艾蓝,所以這里適合去存放每篇文章或者帖子的簡單主題介紹,這樣無論是在PC端還是APP端都可以很快查詢出對(duì)應(yīng)的列表信息斗塘,當(dāng)點(diǎn)擊某一篇文章時(shí)赢织,再去mysql或者oracle數(shù)據(jù)庫查詢整篇文章詳情。