仿9GAG制作过程(五)
有话要说:
在做完了数据展示功能之后,就想着完善整个APP。发现现在后台非常的混乱,有好多点都不具备,比方说:图片应该有略缩图和原图,段子、评论、点赞应该联动起来,段子应该有创建时间等。
于是就重新设计了数据库,重新爬取了数据,重新设计了后台接口。
这次主要讲这次重构的主要内容。
数据库设计:
一共设计了六张表,分别为
- 段子表,主要存放每一个段子的图片等信息
- 评论表,主要存放评论信息,评论可以上传图片
- 用户表
- 标签表,每条段子发表之前会自定义标签,该表存放的就是这些标签
- 点赞记录表,因为用户点赞与段子之间是多对多的关系,因此要加一张表用来存放点赞记录
- 段子标签关联表,因为段子和标签是多对多的,因此需要多一张表存放关联关系
接口设计:
橙色的为表,咖啡色为接口。
目前设计了十四个接口,上图写明了各接口和相关的表之间的关系。
后台结构:
bean包下为基本实体类;
implement包下为消息实体类的子类;
dao包为涉及到数据库的具体实现类;
servlet为接口类;
util为过程中用到的工具类。
具体例子:
下面以查询段子接口为例,介绍具体的结构。
bean类:
消息实体类:
1 public class MessageEntity { 2 3 // 返回信息描述 4 private String reason; 5 // 返回码 6 private int errorCode; 7 8 public String getReason() { 9 return reason; 10 } 11 12 public void setReason(String reason) { 13 this.reason = reason; 14 } 15 16 public int getErrorCode() { 17 return errorCode; 18 } 19 20 public void setErrorCode(int errorCode) { 21 this.errorCode = errorCode; 22 } 23 24 }
段子消息实体类:
1 public class TopicMessageEntity extends MessageEntity { 2 3 // 获取段子的结果 4 private List<TopicEntity> result; 5 6 public List<TopicEntity> getResult() { 7 return result; 8 } 9 10 public void setResult(List<TopicEntity> result) { 11 this.result = result; 12 } 13 14 }
段子实体类:
1 public class TopicEntity { 2 3 // 段子标识 4 private int id; 5 // 段子作者 6 private String author = ""; 7 // 段子标题 8 private String title = ""; 9 // 段子点赞数 10 private int upvote; 11 // 段子评论数 12 private int commentCount; 13 // 段子略缩图地址 14 private String thumbNail = ""; 15 // 段子原图地址 16 private String orgPicture = ""; 17 // 段子发表时间 18 private String postTime = ""; 19 20 // 点的是赞还是踩,0代表没点,1代表赞,-1代表踩 21 private int like = 0; 22 23 public int getId() { 24 return id; 25 } 26 27 public void setId(int id) { 28 this.id = id; 29 } 30 31 public String getAuthor() { 32 return author; 33 } 34 35 public void setAuthor(String author) { 36 this.author = author; 37 } 38 39 public String getTitle() { 40 return title; 41 } 42 43 public void setTitle(String title) { 44 this.title = title; 45 } 46 47 public int getUpvote() { 48 return upvote; 49 } 50 51 public void setUpvote(int upvote) { 52 this.upvote = upvote; 53 } 54 55 public int getCommentCount() { 56 return commentCount; 57 } 58 59 public void setCommentCount(int commentCount) { 60 this.commentCount = commentCount; 61 } 62 63 public String getThumbNail() { 64 return thumbNail; 65 } 66 67 public void setThumbNail(String thumbNail) { 68 this.thumbNail = thumbNail; 69 } 70 71 public String getOrgPicture() { 72 return orgPicture; 73 } 74 75 public void setOrgPicture(String orgPicture) { 76 this.orgPicture = orgPicture; 77 } 78 79 public String getPostTime() { 80 return postTime; 81 } 82 83 public void setPostTime(String postTime) { 84 this.postTime = postTime; 85 } 86 87 public int getLike() { 88 return like; 89 } 90 91 public void setLike(int like) { 92 this.like = like; 93 } 94 95 }
这里和数据库表略有不同,主要是like字段。
like字段代表的是当前获取数据的人对该段子是否点了赞。
dao层:
查询段子方法:
1 public List<TopicEntity> query(int topicId, int count, boolean after) { 2 List<TopicEntity> topicList = new ArrayList<TopicEntity>(); 3 4 if (topicId <= 0) { 5 topicId = 0; 6 } 7 8 if (count <= 0) { 9 count = 10; 10 } 11 12 if (after) { 13 queryAfter(topicId, count, topicList); 14 } else { 15 queryBefore(topicId, count, topicList); 16 } 17 18 return topicList; 19 }
1 private void queryAfter(int topicId, int count, List<TopicEntity> topicList) { 2 String queryAfter = "SELECT * FROM 9gag_topics WHERE id > ? LIMIT ?"; 3 4 Connection conn = DatabaseUtil.getConnection(); 5 PreparedStatement pstmt = null; 6 ResultSet rs = null; 7 8 try { 9 pstmt = conn.prepareStatement(queryAfter); 10 pstmt.setInt(1, topicId); 11 pstmt.setInt(2, count); 12 rs = pstmt.executeQuery(); 13 14 while (rs.next()) { 15 TopicEntity topicEntity = new TopicEntity(); 16 topicEntity.setId(rs.getInt("id")); 17 topicEntity.setAuthor(rs.getString("author")); 18 topicEntity.setTitle(rs.getString("title")); 19 topicEntity.setUpvote(rs.getInt("upvote")); 20 topicEntity.setCommentCount(rs.getInt("commentcount")); 21 topicEntity.setThumbNail(rs.getString("thumbnail")); 22 topicEntity.setOrgPicture(rs.getString("orgpicture")); 23 topicEntity.setPostTime(rs.getString("posttime")); 24 topicList.add(topicEntity); 25 } 26 } catch (SQLException e) { 27 e.printStackTrace(); 28 } finally { 29 DatabaseUtil.close(conn, pstmt, rs); 30 } 31 }
1 private void queryBefore(int topicId, int count, List<TopicEntity> topicList) { 2 String queryBefore = "SELECT * FROM 9gag_topics WHERE id < ? ORDER BY id DESC LIMIT ?"; 3 4 Connection conn = DatabaseUtil.getConnection(); 5 PreparedStatement pstmt = null; 6 ResultSet rs = null; 7 8 try { 9 pstmt = conn.prepareStatement(queryBefore); 10 pstmt.setInt(1, topicId); 11 pstmt.setInt(2, count); 12 rs = pstmt.executeQuery(); 13 14 while (rs.next()) { 15 TopicEntity topicEntity = new TopicEntity(); 16 topicEntity.setId(rs.getInt("id")); 17 topicEntity.setAuthor(rs.getString("author")); 18 topicEntity.setTitle(rs.getString("title")); 19 topicEntity.setUpvote(rs.getInt("upvote")); 20 topicEntity.setCommentCount(rs.getInt("commentcount")); 21 topicEntity.setThumbNail(rs.getString("thumbnail")); 22 topicEntity.setOrgPicture(rs.getString("orgpicture")); 23 topicEntity.setPostTime(rs.getString("posttime")); 24 topicList.add(topicEntity); 25 } 26 } catch (SQLException e) { 27 e.printStackTrace(); 28 } finally { 29 DatabaseUtil.close(conn, pstmt, rs); 30 } 31 32 // 获取完数据之后逆序,因为查找的时候是逆序 33 Collections.reverse(topicList); 34 }
这三个方法实现了查询指定段子前(或者后)count条记录。
servlet层:
1 protected void doPost(HttpServletRequest request, HttpServletResponse response) 2 throws ServletException, IOException { 3 response.setContentType("text/json; charset=utf-8"); 4 PrintWriter out = response.getWriter(); 5 6 TopicMessageEntity message = new TopicMessageEntity(); 7 TopicDAO topicDao = new TopicDAO(); 8 UpvoteDAO upvoteDao = new UpvoteDAO(); 9 Gson gson = GsonUtil.getGson(); 10 11 request.setCharacterEncoding("utf-8"); 12 response.setCharacterEncoding("utf-8"); 13 14 int topicId = Integer.parseInt(request.getParameter("topicId")); 15 int count = Integer.parseInt(request.getParameter("count")); 16 boolean after = Boolean.parseBoolean(request.getParameter("after")); 17 String author = request.getParameter("author"); 18 19 if (count <= 0) { 20 message.setErrorCode(-1); 21 message.setReason("count值不能为负数!"); 22 out.print(gson.toJson(message)); 23 return; 24 } 25 26 try { 27 List<TopicEntity> topics = topicDao.query(topicId, count, after); 28 29 // 判断作者是否点过赞 30 if (author != null) { 31 List<UpvoteEntity> upvoteList = upvoteDao.findUpvoteByAuthor(author, true); 32 if (upvoteList != null) { 33 for (TopicEntity topic : topics) { 34 for (UpvoteEntity upvote : upvoteList) { 35 if (upvote.getLikedId() == topic.getId()) { 36 int like = upvote.isLiked() ? 1 : -1; 37 topic.setLike(like); 38 } 39 } 40 } 41 } 42 } 43 44 Collections.reverse(topics); 45 message.setErrorCode(0); 46 message.setReason("success"); 47 message.setResult(topics); 48 } catch (Exception e) { 49 message.setErrorCode(-1); 50 message.setReason(e.getMessage()); 51 } finally { 52 out.print(gson.toJson(message)); 53 } 54 55 }
主要逻辑:查找到需要的段子→遍历段子→如果段子被点过赞或者踩,就把段子相应字段更改为赞或者踩→由于查出来的数据时顺序的,要改为逆序展示。
反思:
这次主要重构了后台的设计逻辑,其实还有好多不完备的地方。
通过这次重构,明白了一个要点。要做一件事情首先要规划好,首先是设计,把一切的流程,框架设计好之后按部就班的做。这样做出来的东西才会比较好。
否则在过程中会很混乱,严重影响效率。
预告:
下一章准备讲述点赞的逻辑,因为点赞的逻辑比较复杂。
大家如果有什么疑问或者建议可以通过评论或者邮件的方式联系我,欢迎大家的评论~