摘要:序?qū)崙?zhàn)是本好東東,值得詳細研讀。本文主要是對第一章的投票服務(wù)的代碼從改為的版本。
序
redis實戰(zhàn)是本好東東,值得詳細研讀。本文主要是對第一章的投票服務(wù)的代碼從jredis改為SpringBoot的redis template版本。
功能說明用redis來存儲文章
對文章投票
每個用戶只能投一次
文章按投票和時間排行
文章打標(biāo)簽
數(shù)據(jù)結(jié)構(gòu)選擇文章采用hash存儲
用redis的incr來實現(xiàn)文章的自增id
用set來記錄每篇文章已投票的用戶
用zset存儲文章與得分,創(chuàng)建時間
用set來存儲標(biāo)簽里有哪些文章
常量聲明/** * incr,獲取文章的id */ public static final String KEY_ARTICLE_ID_SEQ = "articleIdSeq"; /** * 數(shù)據(jù)結(jié)構(gòu):SET * key -- voted:articleId * value -- user * 記錄每篇文章的投票用戶 */ public static final String KEY_VOTE_ARTICLE_PREFIX = "votedSet:"; /** * 數(shù)據(jù)結(jié)構(gòu):map * key -- articleMap:id * value -- article map */ public static final String KEY_ARTICLE_PREFIX = "articleMap:"; /** * 數(shù)據(jù)結(jié)構(gòu):zset * key -- scoreZSet * value -- 得分 articleMap:id */ public static final String KEY_SCORE = "scoreZSet"; /** * 數(shù)據(jù)結(jié)構(gòu):zset * key -- timeZSet * value -- 得分 articleMap:id */ public static final String KEY_TIME = "timeZSet"; /** * 文章標(biāo)簽前綴 * 數(shù)據(jù)結(jié)構(gòu) set * key -- tagSet:tag * value -- articleMap:id */ public static final String KEY_TAG_PREFIX = "tagSet:"; /** * 文章用戶投票記錄的過期時間 */ public static final int ARTICLE_USER_VOTE_EXPIRE_DAY = 7; /** * 文章用戶投票記錄的過期時間 * 秒為單位 */ public static final int ONE_WEEK_IN_SECONDS = 7 * 86400; /** * 投票得分 */ public static final int VOTE_SCORE = 432; /** * 每頁多少條記錄 */ public static final int ARTICLES_PER_PAGE = 25;主要功能 添加文章
/** * 添加文章 * @param user * @param title * @param link * @return 文章的自增id */ public Long postArticle(String user,String title,String link){ ValueOperations給文章投票intOps = redisTemplate.opsForValue(); Long id = intOps.increment(KEY_ARTICLE_ID_SEQ,1L); //本人發(fā)布的文章,自動添加到已投票set中 voteInternal(id,user); Map articleData = new HashMap (); articleData.put("title", title); articleData.put("link", link); articleData.put("user", user); long nowInSecs = System.currentTimeMillis() / 1000; articleData.put("now", String.valueOf(nowInSecs)); articleData.put("votes", "1"); //主要投票數(shù)的計數(shù)器 //保存文章 String articleKey = formArticleKey(id); redisTemplate.opsForHash().putAll(articleKey, articleData); //記錄得分和時間 redisTemplate.boundZSetOps(KEY_SCORE).add(articleKey,nowInSecs + VOTE_SCORE); redisTemplate.boundZSetOps(KEY_TIME).add(articleKey,nowInSecs); return id; }
/** * 用戶給文章投票 * 嚴格一點需要加事務(wù) * @param user * @param id */ public void voteArticle(String user,Long id){ long now = System.currentTimeMillis() / 1000; String articleKey = formArticleKey(id); Double score = redisTemplate.boundZSetOps(KEY_SCORE).score(articleKey); //文章發(fā)布超過一周,不能投票 if(score.longValue() + ONE_WEEK_IN_SECONDS < now){ return; } //判斷用戶是否可以投票 //若已經(jīng)投票則返回,未投票則投票,并增加投票記錄 Long tryVote = voteInternal(id,user); if(tryVote == 0){ return; } //給文章增加投票 redisTemplate.opsForHash().increment(articleKey,"votes",1L); //增加文章的得分 redisTemplate.boundZSetOps(KEY_SCORE).incrementScore(articleKey,VOTE_SCORE); }根據(jù)id獲取文章
/** * 根據(jù)id獲取文章內(nèi)容 * @param id * @return */ public ArticleBean getArticleById(Long id){ Map給文章打標(biāo)簽data = redisTemplate.opsForHash().entries(formArticleKey(id)); ArticleBean bean = new ArticleBean(); bean.setId(id); try { BeanUtils.populate(bean,data); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return bean; }
/** * 給文章打標(biāo)簽 * @param id * @param tags */ public void tagArticle(Long id,String[] tags){ String articleKey = formArticleKey(id); for(String tag:tags){ String tagKey = formTagKey(tag); redisTemplate.opsForSet().add(tagKey,articleKey); } }獲取排行具體實現(xiàn)
/** * 根據(jù)排序及頁數(shù)獲取文章 * @param page * @param zrangeKey * @return * @throws InvocationTargetException * @throws IllegalAccessException */ private List獲取各種排行getArticleRank(int page,String zrangeKey){ int start = (page - 1) * ARTICLES_PER_PAGE; int end = start + ARTICLES_PER_PAGE - 1; BoundZSetOperations ops = redisTemplate.boundZSetOps(zrangeKey); //根據(jù)得分從大到小 Set ids = ops.reverseRange(start, end); List rs = ids.stream().map(new Function () { @Override public ArticleBean apply(String id) { HashOperations hashOps = redisTemplate.opsForHash(); Map map = hashOps.entries(id); ArticleBean bean = new ArticleBean(); bean.setId(Long.valueOf(id.substring(id.indexOf(":") + 1))); try { BeanUtils.populate(bean, map); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return bean; } }).collect(Collectors.toList()); return rs; }
/** * 根據(jù)標(biāo)簽獲取文章排名 * @param page * @param zrangeKey * @param tag * @return */ public Listjunit測試getArticleRankByTag(int page,String zrangeKey,String tag){ String scoreTagKey = formScoreTagKey(zrangeKey, tag); Boolean exist = redisTemplate.hasKey(scoreTagKey); if(!exist){ Long rs = redisTemplate.opsForZSet().intersectAndStore(formTagKey(tag),zrangeKey,scoreTagKey); if(rs == 1){ redisTemplate.expire(scoreTagKey,1,TimeUnit.MINUTES); } } return getArticleRank(page,scoreTagKey); } /** * 根據(jù)得分排序 * @param page * @return */ public List getArticleRankByScore(int page){ return getArticleRank(page,KEY_SCORE); } /** * 根據(jù)時間排序 * @param page * @return */ public List getArticleRankByTime(int page){ return getArticleRank(page,KEY_TIME); }
/** * Created by codecraft on 2016-02-11. */ public class VoteServiceTest extends RedisdemoApplicationTests{ @Autowired VoteService voteService; @Autowired RedisTemplate redisTemplate; @Test public void incrMap(){ //template.setHashValueSerializer(new StringRedisSerializer(StandardCharsets.UTF_8)); //這里得用string寫進去 redisTemplate.opsForHash().put("user-abcde", "count", "1"); redisTemplate.opsForHash().increment("user-abcde", "count", 5); //error java.lang.ClassCastException: java.lang.Long cannot be cast to java.lang.String redisTemplate. opsForHash().put("user-abcde", "now", System.currentTimeMillis()); System.out.println(redisTemplate.opsForHash().get("user-abcde", "now")); } @Test public void delete(){ for(int i=0;i<100;i++){ voteService.delete(i+1L); } redisTemplate.delete("articleIdSeq"); } @Test public void post() throws InterruptedException { for(int i=0;i<100;i++){ voteService.postArticle("user" + i, "title" + i, "link" + i); Thread.sleep(1000); } for(int i=0;i<100;i++){ ArticleBean bean = voteService.getArticleById(i + 1L); System.out.println(ToStringBuilder.reflectionToString(bean)); } } @Test public void vote(){ Random random = new Random(); IntStream.range(1,31).forEach(x -> { Long articleId = random.nextInt(100) + 1L; String user = "user" + (random.nextInt(100) + 1); voteService.voteArticle(user,articleId); }); } @Test public void addTag(){ Random random = new Random(); IntStream.range(1,31).forEach(x -> { Long articleId = random.nextInt(100) + 1L; String tag = "tag" + (random.nextInt(5) + 1); voteService.tagArticle(articleId, new String[]{tag}); }); } @Test public void getByScore(){ List data = voteService.getArticleRankByScore(1); data.stream().forEach(System.out::println); } @Test public void getByTime(){ List data = voteService.getArticleRankByTime(1); data.stream().forEach(System.out::println); } @Test public void getByTag(){ List data = voteService.getArticleRankByTag(1, VoteService.KEY_SCORE,"tag1"); data.stream().forEach(System.out::println); } }
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/65864.html
摘要:前言我們一起回顧上一篇文章平臺的微服務(wù)架構(gòu)和,一共通過構(gòu)建了三個鏡像數(shù)據(jù)庫,部署前端頁面的,和接口。最近阿里云產(chǎn)品春節(jié)大促銷,我一時沒忍住又買了一臺服務(wù)器,打完折扣還是很貴。是一個非常穩(wěn)定的,可移植的網(wǎng)絡(luò)文件系統(tǒng)。 前言 我們一起回顧上一篇文章《Bees平臺的微服務(wù)架構(gòu)(1)docker和docker-compose》,一共通過Dockerfile構(gòu)建了三個docker鏡像:mysql...
閱讀 2395·2021-11-11 16:54
閱讀 1204·2021-09-22 15:23
閱讀 3645·2021-09-07 09:59
閱讀 1990·2021-09-02 15:41
閱讀 3283·2021-08-17 10:13
閱讀 3037·2019-08-30 15:53
閱讀 1235·2019-08-30 13:57
閱讀 1210·2019-08-29 15:16