网易云音乐功能分析
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     }

 

结果