网易云音乐功能分析
1.存储所有歌曲(评论数)
2.一首歌对应多个评论
3.每个评论可以点赞 根据点赞数排序
4.歌单 歌单中的歌曲已热度排序(评论数*432 + 喜欢这首歌的人*432 (比例还可以调整) + 发布时间)
5.我喜欢的歌
解决方案
1.使用Hash存储歌的具体信息 使用String存储ID
2.使用Set存储每首歌对应的评论ID
3.使用ZSet
4.使用Set存储歌曲ID
5.使用java反射
pojo:
评论实体类
1 public class Comment { 2 3 private String id; 4 5 private String comment; 6 7 private String time; 8 9 private String good; 10 11 public Comment() { 12 } 13 14 public String getId() { 15 return id; 16 } 17 18 public void setId(String id) { 19 this.id = id; 20 } 21 22 public String getComment() { 23 return comment; 24 } 25 26 public void setComment(String comment) { 27 this.comment = comment; 28 } 29 30 public String getTime() { 31 return time; 32 } 33 34 public void setTime(String time) { 35 this.time = time; 36 } 37 38 public String getGood() { 39 return good; 40 } 41 42 public void setGood(String good) { 43 this.good = good; 44 } 45 }
歌曲实体类
1 public class Song { 2 3 private String id; 4 5 private String name; 6 7 private String singer; 8 9 private String comments; 10 11 private List<Comment> commentList; 12 13 public Song() { 14 } 15 16 public Song(String name, String singer) { 17 this.name = name; 18 this.singer = singer; 19 this.comments = "0"; 20 } 21 22 public String getId() { 23 return id; 24 } 25 26 public void setId(String id) { 27 this.id = id; 28 } 29 30 public String getName() { 31 return name; 32 } 33 34 public void setName(String name) { 35 this.name = name; 36 } 37 38 public String getSinger() { 39 return singer; 40 } 41 42 public void setSinger(String singer) { 43 this.singer = singer; 44 } 45 46 public String getComments() { 47 return comments; 48 } 49 50 public void setComments(String comments) { 51 this.comments = comments; 52 } 53 54 public List<Comment> getCommentList() { 55 return commentList; 56 } 57 58 public void setCommentList(List<Comment> commentList) { 59 this.commentList = commentList; 60 } 61 }
新增歌曲
1 // 新增歌曲 2 private String addSong(Jedis conn, Song song) { 3 // 获取歌曲ID 4 // ID不存在会创建一个(1) 存在则会自增 5 String id = String.valueOf(conn.incr("song:")); 6 7 //将歌曲存入hash中 8 String key = "song:" + id; 9 HashMap<String, String> map = new HashMap<String, String>(); 10 map.put("id", id); 11 map.put("name", song.getName()); 12 map.put("singer", song.getSinger()); 13 map.put("comments", String.valueOf(song.getComments())); 14 conn.hmset(key, map); 15 16 //记录热度 初始化成当前时间 17 conn.zadd("hot:", now(), key); 18 return id; 19 }
增加评论
1 // 增加评论 2 private void addComment(Jedis conn, String id, String comment) { 3 String songKey = "song:" + id; 4 //歌曲信息中评论还是加1 5 conn.hincrBy(songKey, "comments", 1); 6 //增加热度 7 conn.zincrby("hot:", VOTE_SCORE, songKey); 8 9 String commentKey = "song:" + id + " comments:"; 10 11 //获取评论id 12 String commentID = String.valueOf(conn.incr(commentKey)); 13 14 commentKey += commentID; 15 16 HashMap<String, String> map = new HashMap<String, String>(); 17 map.put("id", commentID); 18 map.put("comment", comment); 19 map.put("time", time()); 20 map.put("good", "0"); 21 22 conn.hmset(commentKey, map); 23 24 //默认给自己点个赞 25 conn.zadd("song:" + id + " score:", 1, "comments:" + commentID); 26 }
评论点赞
1 //点赞 2 private void good(Jedis conn, String song, String comment) { 3 //增加点赞数(排名) 4 conn.zincrby("song:" + song + " score:", 1, "comments:" + comment); 5 //hash中记录 6 conn.hincrBy("song:" + song + " comments:" + comment, "good", 1); 7 //增加歌曲热度 8 conn.zincrby("hot:", VOTE_SCORE, "song:" + song); 9 }
查询歌曲
1 //按照热度获取歌曲 2 private List<Song> song(Jedis conn) { 3 Set<String> set = conn.zrevrange("hot:", 0, -1); 4 List<Song> list = new ArrayList<>(); 5 for (String str : set) { 6 list.add(get(conn.hgetAll(str), conn)); 7 } 8 return list; 9 } 10 11 private Song get(Map<String, String> map, Jedis conn) { 12 Class<Song> clazz = Song.class; 13 Song song = null; 14 try { 15 song = clazz.newInstance(); 16 } catch (InstantiationException | IllegalAccessException e) { 17 e.printStackTrace(); 18 } 19 for (Map.Entry<String, String> entry : map.entrySet()) { 20 try { 21 Field field = clazz.getDeclaredField(entry.getKey()); 22 if (entry.getKey().equals("id")) { 23 String key = "song:" + entry.getValue() + " score:"; 24 Set<String> set = conn.zrevrange(key, 0, -1); 25 List<Comment> list = new ArrayList<>(); 26 for (String str : set) { 27 list.add(getComment(conn.hgetAll("song:" + entry.getValue() + " " + str))); 28 } 29 Field commentList = clazz.getDeclaredField("commentList"); 30 commentList.setAccessible(true); 31 commentList.set(song, list); 32 } 33 field.setAccessible(true); 34 field.set(song, entry.getValue()); 35 } catch (IllegalAccessException | NoSuchFieldException e) { 36 e.printStackTrace(); 37 } 38 } 39 return song; 40 } 41 42 private Comment getComment(Map<String, String> map) { 43 Class<Comment> clazz = Comment.class; 44 Comment comment = null; 45 try { 46 comment = clazz.newInstance(); 47 } catch (InstantiationException | IllegalAccessException e) { 48 e.printStackTrace(); 49 } 50 for (Map.Entry<String, String> entry : map.entrySet()) { 51 try { 52 Field field = clazz.getDeclaredField(entry.getKey()); 53 field.setAccessible(true); 54 field.set(comment, entry.getValue()); 55 } catch (IllegalAccessException | NoSuchFieldException e) { 56 e.printStackTrace(); 57 } 58 } 59 return comment; 60 }
工具方法
1 private long now() { 2 return System.currentTimeMillis() / 1000; 3 } 4 5 private String time() { 6 SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 7 return df.format(new Date()); 8 }
实验
1 private static final int VOTE_SCORE = 432; 2 3 private static Song[] songs = new Song[5]; 4 5 static { 6 for (int i = 0; i < songs.length; i++) { 7 songs[i] = new Song("1989" + i, "Taylor Swift" + i); 8 } 9 } 10 11 public static void main(String[] args) { 12 MyChapter01 chapter01 = new MyChapter01(); 13 14 Jedis conn = new Jedis("localhost"); 15 conn.select(10); 16 17 // for (Song song : songs) { 18 // chapter01.addSong(conn, song); 19 // } 20 21 // chapter01.addComment(conn, "6", "霉霉好棒"); 22 // chapter01.addComment(conn, "6", "女神加油"); 23 24 //少写一个点赞验证的set hhh 25 chapter01.good(conn, "6", "1"); 26 27 List<Song> list = chapter01.song(conn); 28 for (Song song : list) { 29 System.out.println(song); 30 } 31 }
结果