开发社区首页
开发流程
分步实现
开发社区首页,显示前10个帖子
开发分页组件,分页显示所有的帖子
我们首先开发社区首页,显示帖子,先查看一下存帖子的表,在navicat右边可以查看DDL(Data Definition Language),也就是建表语句,workbench查看的方法自行百度。根据DDL了解一下表的结构。
然后我们就可以进行开发,根据上图的依赖关系,我们从下往上进行,也就是entity-dao-service-controller的顺序。
实体类 首先是实体类,和上一节的操作一样,比较简单。根据数据库字段写好就行。其实有插件可以自动生成实体类和xml,但是在学习阶段,建议自己敲一遍熟悉一下。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 package com.neu.langsam.community.entity;import java.util.Date;public class DiscussPost { private int id; private int userId; private String title; private String content; private int type; private int status; private Date createTime; private int commentCount; private double score; public int getId () { return id; } public void setId (int id) { this .id = id; } public int getUserId () { return userId; } public void setUserId (int userId) { this .userId = userId; } public String getTitle () { return title; } public void setTitle (String title) { this .title = title; } public String getContent () { return content; } public void setContent (String content) { this .content = content; } public int getType () { return type; } public void setType (int type) { this .type = type; } public int getStatus () { return status; } public void setStatus (int status) { this .status = status; } public Date getCreateTime () { return createTime; } public void setCreateTime (Date createTime) { this .createTime = createTime; } public int getCommentCount () { return commentCount; } public void setCommentCount (int commentCount) { this .commentCount = commentCount; } public double getScore () { return score; } public void setScore (double score) { this .score = score; } @Override public String toString () { return "DiscussPost{" + "id=" + id + ", userId=" + userId + ", title='" + title + '\'' + ", content='" + content + '\'' + ", type=" + type + ", status=" + status + ", createTime=" + createTime + ", commentCount=" + commentCount + ", score=" + score + '}' ; } }
DAO层 实体类写完后,写dao层接口,这里定义了两个方法,一个是查询帖子,另一个是查询帖子数量,可以用来实现后面的分页。需要注意的点在注释里写了。
然后需要写接口对应的mapper配置文件,和上一节内容差不多,有几个需要注意的点
namespace要修改成对应的接口
使用了标签动态拼接sql语句,当满足if的条件时,拼接上if标签里的内容,这样我们就可以根据传入的userId的值,来判断是查询首页帖子还是查询我的帖子。
另外使用了order by来排序,首先按照帖子类型倒序,再按照时间倒叙,这样就实现了精华帖置顶并且新帖在前的功能,后面还会实现按热度排序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 package com.neu.langsam.community.dao;import com.neu.langsam.community.entity.DiscussPost;import org.apache.ibatis.annotations.Mapper;import org.apache.ibatis.annotations.Param;import java.util.List;@Mapper public interface DiscussPostMapper { List selectDiscussPosts (int userId,int offset,int limit) ; int selectDiscussPostRows (@Param("userId" ) int userId) ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" > <mapper namespace ="com.neu.langsam.community.dao.DiscussPostMapper" > <sql id ="selectFields" > id,user_id,title,content,type,status,create_time,comment_count,score sql > <select id ="selectDiscussPosts" resultType ="DiscussPost" > select <include refid ="selectFields" > include > from discuss_post where status!=2 <if test ="userId!=0" > and user_id=#{userId} if > order by type desc,create_time desc limit #{offset},#{limit} select > <select id ="selectDiscussPostRows" resultType ="int" > select count(id) from discuss_post where status!=2 <if test ="userId!=0" > and user_id=#{userId} if > select > mapper >
然后测试一下,可以看到控制台输出没问题。
Service层 我们这个业务比较简单,但是也必须严格遵守层次去编写,便于我们后面的一些维护和安全性的实现。这里还有另一个问题,discusspost表里有userId字段,但是我们不可能直接给用户显示id,需要显示用户名。有两种方案:
写sql的时候用id再查询一下用户名拼接到一起
用之前写好的查询user的方法,和我查询到的discusspost再做一个组合
看起来第二种方法更麻烦一些,但是当我们后面用到redis缓存数据库后,这样的方法就可能效率更高了。那么我们再写一个UserService提供查询用户方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 package com.neu.langsam.community.service;import com.neu.langsam.community.dao.DiscussPostMapper;import com.neu.langsam.community.entity.DiscussPost;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;@Service public class DiscussPostService { @Autowired private DiscussPostMapper discussPostMapper; public List findDiscussPosts (int userId,int offset,int limit) { return discussPostMapper.selectDiscussPosts(userId,offset,limit); } public int findDiscussPostRows (int userId) { return discussPostMapper.selectDiscussPostRows(userId); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 package com.neu.langsam.community.service;import com.neu.langsam.community.dao.UserMapper;import com.neu.langsam.community.entity.User;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Service public class UserService { @Autowired private UserMapper userMapper; public User findUserById (int id) { return userMapper.selectById(id); } }
导入网页 前端的网页我们使用教程模板,在我的gayhub可以找到,把template下的文件复制到项目就行。
gayhub
Controller层 首先在controller包下新建HomeController,使用注解注入Service
1 2 3 4 @Autowired private DiscussPostService discussPostService; @Autowired private UserService userService;
第一个任务 首页上显示10个帖子。这里先写固定值,后续再进行改进。前面提到的显示用户名的方式,采用第二种,利用post里的id去查询对应的user,然后用HashMap装到一起,再用list处理map。
最终我们传给模板引擎的就是一个list,list里是每个帖子对应的map,每个map里有post对象和user对象,每个对象有自己的属性和get、set方法。那么利用thymeleaf的语法,去遍历这些对象,将值赋给相应的标签就行。html已经写好了,有兴趣的可以学一学。我们启动项目,在浏览器里访问。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @RequestMapping (path = "/index" ,method = RequestMethod.GET) public String getIndexPage (Model model) { List list=discussPostService.findDiscussPosts(0 ,0 ,10 ); List> discussPosts=new ArrayList<>(); if (list!=null ){ for (DiscussPost post:list){ Map map=new HashMap<>(); map.put("post" ,post); User user=userService.findUserById(post.getUserId()); map.put("user" ,user); discussPosts.add(map); } } model.addAttribute("discussPosts" ,discussPosts); return "/index" ; }
第二个任务 完成第一个任务后,在这基础上完成分页的功能,我们可以自己封装一个分页类,提高代码的复用。在entity包下创建Page类。使用idea生成get和set方法,这里我们需要修改一下生成的set方法,判断一下传入的数据是否合理。比如setLimit方法,我规定limit必须大于1小于100。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 private int current=1 ;private int limit=10 ;private int rows;private String path;public void setLimit (int limit) { if (limit>=1 &&limit<=100 ){ this .limit = limit;} }
另外,还需要自定义一些方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public int getOffset () { return (current-1 )*limit; } public int getTotal () { if (rows%limit==0 ){ return rows/limit; }else { return rows/limit+1 ; } } public int getFrom () { int from=current-2 ; return from < 1 ? 1 : from; } public int getTo () { int to=current+2 ; int total=getTotal(); return to>total?total:to; }
然后对controller进行一些改造。
1 2 3 4 5 6 7 8 9 10 @RequestMapping (path = "/index" ,method = RequestMethod.GET) public String getIndexPage (Model model, Page page) { page.setRows(discussPostService.findDiscussPostRows(0 )); page.setPath("/index" ); List list=discussPostService.findDiscussPosts(0 ,page.getOffset(),page.getLimit());
那么至此,首页完成了。