4.发布帖子,评论帖子
目录
一:发布帖子
二:帖子详情
三:查看评论
四:评论帖子
一:发布帖子
用到的表:DiscussPost
方法:用到AJAX,网页能将增量更新呈现在页面上,而不需要刷新整个页面
异步通信技术,虽然X代表XML,但目前JSON使用的比XML更加普遍
思路
- 在首页点击 “我要发布”,填写标题和正文,点击发布,会执行index.js中的publish()方法,触发ajax异步发送帖子请求,映射到DiscussPostController(/discuss)层的 /add 路径。执行控制器类 DiscussPostController 的 addDiscussPost()方法。里面调用 discussPostService.addDiscussPost 方法,将post 中的 title,content 转义HTML标记,,然后调用 discussPostMapper.insertDiscussPost(post) 存入数据。通过其对应的SQL语句将帖子内容插进 discuss_post表中。
- 简单来说就是 用post方式提交接json格式数据给目标URL,controller层接收到请求后,处理/add请求,前端根据返回的状态码以及提示信息判断是否添加成功。
开发流程
1.我们从最简单的工具类开始,在里面写上了我们需要的一些工具方法;
在util.CommunityUtil类中添加新的工具方法,用于转换json字符串:返回状态码,在贴子发布后,显示发布成功。
//得到JSON格式的字符串//输入为:编号、提示、业务数据public static String getJSONString(int code, String msg, Map<String, Object> map){JSONObject json = new JSONObject();json.put("code",code);json.put("msg",msg);if (map!=null){for (String key: map.keySet()) {json.put(key, map.get(key));}}return json.toJSONString();}//得到JSON格式的字符串(重载1:无业务数据)public static String getJSONString(int code, String msg){return getJSONString(code, msg, null);}//得到JSON格式的字符串(重载2:无提示、业务数据)public static String getJSONString(int code){return getJSONString(code, null, null);}
2. 在数据层dao中的DiscussPostMapper接口新添加方法,并在对应的discusspost-mapper添加对应的SQL语句
//添加帖子
int insertDiscussPost(DiscussPost discussPost);//SQL语句<insert id="insertDiscussPost" parameterType="DiscussPost">insert into discuss_post(<include refid="insertFields"></include>)values (#{userId},#{title},#{content},#{type},#{status},#{createTime},#{commentCount},#{score})</insert>
3. 业务的核心逻辑都在Service层,在service类中编写了一些需要的业务逻辑,业务层需要定义一个对帖子进行保存的方法,最后调用dao里的方法,实现对数据层的更新。
在service.DiscussPostService类下新建方法:addDiscussPost()。
@Autowiredprivate SensitiveFilter sensitiveFilter;public int addDiscussPost(DiscussPost post){if(post==null){throw new IllegalArgumentException("参数不能为空!");}//转义HTML标记:防止人家发布的内容中包含html的标签,导致破坏页面//只用对主题、评论进行转义、过滤操作post.setTitle(HtmlUtils.htmlEscape(post.getTitle()));post.setContent(HtmlUtils.htmlEscape(post.getContent()));//过滤敏感词post.setTitle(sensitiveFilter.filter(post.getTitle()));post.setContent(sensitiveFilter.filter(post.getContent()));return discussPostMapper.insertDiscussPost(post);}
4. Service之后,最后就是视图层的编写,分为两个部分:控制器 + 页面。
在controller目录下新建:DiscussPostController,实现增加帖子的功能,以后所有与发帖相关的请求都在这里处理。
package com.nowcoder.mycommunity.controller;//处理所有与发帖相关的请求
@Controller
@RequestMapping("/discuss")
public class DiscussPostController {@Autowiredprivate DiscussPostService discussPostService;@Autowired //获取当前用户private HostHolder hostHolder;@RequestMapping(path = "/add", method = RequestMethod.POST)@ResponseBodypublic String addDiscussPost(String title, String content) {User user = hostHolder.getUser();if (user == null){// 403表示没有权限return CommunityUtil.getJSONString(403, "你还没有登录哦!");}DiscussPost post = new DiscussPost();post.setUserId(user.getId());post.setTitle(title);post.setContent(content);post.setCreateTime(new Date());discussPostService.addDiscussPost(post);return CommunityUtil.getJSONString(0, "发布成功");}
}
再完成JS部分的编写,index.html中101行的【发布按钮】绑定了一个函数publish(),可以在Index.js中查看(双击shift搜索)。
$(function(){$("#publishBtn").click(publish);
});function publish() {$("#publishModal").modal("hide");// 获取标题和内容var title = $("#recipient-name").val();var content = $("#message-text").val();// 发送异步请求(POST)$.post(CONTEXT_PATH + "/discuss/add",{"title":title,"content":content},function(data) {data = $.parseJSON(data);// 在提示框中显示返回消息$("#hintBody").text(data.msg);// 显示提示框$("#hintModal").modal("show");// 2秒后,自动隐藏提示框setTimeout(function(){$("#hintModal").modal("hide");// 刷新页面if(data.code == 0) {window.location.reload();}}, 2000);});}
二:帖子详情
比较简单,就是标准的开发流程
1. 大体思路
点击帖子,会打开一个链接,把帖子的内容显示完整。
按照正常的开发流程:数据层 - 服务层 - 页面。
① 在 index 页面点击帖子,映射到DiscussPostController(/discuss)层的 /detail/{discussPostId} 路径,并将帖子的 id 传入。
② 根据 id 利用 discussPostService.findDiscussPostById 方法查出 post。根据userService.findUserById 方法查出 User。将 post帖子,user发帖人 加入model。
(③ 后序新增:将点赞数量和状态查询处理加入model。)
④ 返回 /site/discuss-detail 页面。在 /site/discuss-detail 页面显示帖子和发布帖子的用户信息。
2. 过程
①在 dao.DiscussPostMapper类下添加增删改查方法:
selectDiscussPostById 根据主键查询帖子。
//根据主键查询帖子
DiscussPost selectDiscussPostById(int id);
②在 resources.mapper.discusspoat-mapper.xml 下添加上面Mapper对应的SQL语句
<select id="selectDiscussPostById" resultType="DiscussPost">select <include refid="selectFields"></include>from discuss_postwhere id = #{id}</select>
③在service.DiscussPostService 添加方法:
//根据ID查询帖子public DiscussPost findDiscussPostById(int id){return discussPostMapper.selectDiscussPostById(id);}
④在controller.DiscussPostController 控制器类中添加控制器方法,用来处理点击帖子查看详情时的页面跳转。
@RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model){//查询得到帖子DiscussPost post = discussPostService.findDiscussPostById(discussPostId);//将帖子传给模板model.addAttribute("post",post);//查询出发帖人User user = userService.findUserById(post.getUserId());model.addAttribute("user", user);return "/site/discuss-detail";}
三:查看评论
继 帖子详情后显示帖子的评论。同样在 DiscussPostController(/discuss)层的 /detail/{discussPostId} 映射中。我们将 comment 表中的 entity_type 属性在 CommunityConstant 工具类中设置了两个实体常量,(帖子1,评论2),便于分页查询时使用。
新表:评论表Comment,至此已经出现DiscussPost帖子表,User用户表
1.开发思路
这个功能也是比较常规的功能,按照常规流程三层进行开发。
①数据层:
- 根据实体查询一页评论数据;
- 根据实体查询评论的数量。
②业务层:
- 处理查询评论的业务;
- 处理查询评论数量的业务。
③表现层:
- 显示帖子详情数据时,同时显示该帖子所有的评论数据。
2.具体过程
评论是显示在帖子详情页面,所以改造DiscussPostController的getDiscussPost方法。同时还给comment帖子表设置了两个常量。(帖子1,评论2),便于分页查询时使用。
1)首先设置评论分页信息。设置为每页显示5条,设置page的路径(/disscuss/detail/ + )和总的评论数。
2)设置完后就可以进行分页查询了。根据该帖子的 id 和类型利用 commentService.findCommentsByEntity 方法查询得到当前帖子的所有评论放到一个集合中。还要呈现其它信息,将该帖子的评论和该评论的作者加入到Map中,当然不仅帖子有评论,评论也有回复的评论,所以也要把它的评论查到显示,这里比较绕,我们称普通评论为评论,评论的评论为回复。3)刚刚Map封装的是一个评论,这会继续查回复,这里就不用分页了,从第一行开始查,还是在该Map中嵌套插入一个包括该评论的所有回复reply,回复作者和回复目标(target)。再commentService.findCommentCount将回复数量插入Map(因为前端也会展示总的评论数)。完成以后最后将每个评论的Map传入模板Model。(难点)
3)整个逻辑就是查出当前帖子下的所有评论,遍历所有评论,处理用户名等信息,查询评论下的回复,遍历每个回复,处理用户名等信息。最后返回 /site/discuss-detail 页面。
①在entity包下新建实体类:Comment,对应评论的表。
package com.nowcoder.mycommunity.entity;import java.util.Date;//对应于【评论】表
public class Comment {private int id;private int userId;private int entityType; //评论类型,1代表帖子,2代表评论private int entityId; //对应回复实体的ID,如帖子id 228,或帖子id 229private int targetId; //回复的对象,即向某个人的评论private String content;private int status;private Date createTime;// get()、set()// toString()
}
②数据层:在dao包下,创建接口CommentMapper,主要有两个方法,一个是查询评论,一个是查询评论数量,这里也需要用到分页查询,用了offeset和limit.
由于涉及到分页,需要用到两个方法:查询某页有多少数据、查询一共有多少条数据
package com.nowcoder.mycommunity.dao;import com.nowcoder.mycommunity.entity.Comment;
import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapper
public interface CommentMapper {//查询评论时,进行分页的两个方法List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset, int limit);int selectCountByEntity(int entityType, int entityId);
}
在resources.mapper下创建comment-mapper.xml,用来实现上面接口中的SQL语句。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.mycommunity.dao.CommentMapper"><sql id="selectFields">id, user_id, entity_type, entity_id, target_id, content, status, create_time</sql><select id="selectCommentsByEntity" resultType="Comment">select <include refid="selectFields"></include>from commentwhere status = 0and entity_type = #{entityType}and entity_id = #{entityId}order by create_time asclimit #{offset}, #{limit}</select><select id="selectCountByEntity" resultType="int">select count(id)from commentwhere status = 0and entity_type = #{entityType}and entity_id = #{entityId}</select>
</mapper>
③在service目录下创建:CommentService,业务层也比较简单,没有什么需要处理的,直接返回查询结果
package com.nowcoder.mycommunity.service;import com.nowcoder.mycommunity.dao.CommentMapper;
import com.nowcoder.mycommunity.entity.Comment;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import java.util.List;@Service
public class CommentService {@Autowiredprivate CommentMapper commentMapper;public List<Comment> findCommentsByEntity(int entityType, int entityId, int offset, int limit){return commentMapper.selectCommentsByEntity(entityType, entityId, offset, limit);}public int findCommentCount(int entityType, int entityId){return commentMapper.selectCountByEntity(entityType, entityId);}
}
④在controller.DiscussPostController中添加方法
评论是显示在帖子详情页面,所以改造DiscussPostController的getDiscussPost方法。
- 注入CommentService
- 借助分页,参数添加page
- 设置评论分页信息,每页显示5条,设置page的路径和总的评论数。
- 得到当前帖子的所有评论
- 遍历评论集合,创建评论VO列表,并放入map封装数据
整个逻辑就是查出当前帖子下的所有评论,遍历所有评论,处理用户名等信息,查询评论下的回复,遍历每个回复,处理用户名等信息。
@RequestMapping(path = "/detail/{discussPostId}", method = RequestMethod.GET)public String getDiscussPost(@PathVariable("discussPostId") int discussPostId, Model model, Page page){//查询得到帖子DiscussPost post = discussPostService.findDiscussPostById(discussPostId);//将帖子传给模板model.addAttribute("post",post);//查询出发帖人User user = userService.findUserById(post.getUserId());model.addAttribute("user", user);//评论的分页信息page.setLimit(5);page.setPath("/discuss/detail/" + discussPostId);page.setRows(post.getCommentCount()); //帖子中的评论数量//评论:给帖子的评论(楼主)//回复:给评论的评论(楼内的互相评论)//评论列表List<Comment> commentList =commentService.findCommentsByEntity(ENTITY_TYPE_POST, post.getId(), page.getOffset(), page.getLimit());//评论VO列表(显示列表)List<Map<String, Object>> commentVoList = new ArrayList<>();if(commentList != null){for (Comment comment : commentList){//评论VOMap<String, Object> commentVo = new HashMap<>();commentVo.put("comment", comment); //向VO中添加评论commentVo.put("user", userService.findUserById(comment.getUserId())); //向VO中添加评论作者//评论的回复:不分页List<Comment> replyList = commentService.findCommentsByEntity(ENTITY_TYPE_COMMENT, comment.getId(), 0, Integer.MAX_VALUE);//回复的VO列表List<Map<String, Object>> replyVoList = new ArrayList<>();if(replyList != null){for (Comment reply : replyList){Map<String, Object> replyVo = new HashMap<>();//存回复replyVo.put("reply", reply);//作者replyVo.put("user", userService.findUserById(reply.getUserId()));User target = reply.getTargetId() == 0 ? null : userService.findUserById(reply.getTargetId());replyVo.put("target", target);replyVoList.add(replyVo);}}//目前包含楼主的评论,以及回复楼主的评论commentVo.put("replys", replyVoList);//楼中的评论数量int replyCount = commentService.findCommentCount(ENTITY_TYPE_COMMENT, comment.getId());commentVo.put("replyCount", replyCount);//里面装有所有楼层,以及楼层中的回复、数量信息commentVoList.add(commentVo);}}model.addAttribute("comments", commentVoList);return "/site/discuss-detail";}
注:由于用到新的常量,在util.CommunityConstant中添加
//帖子的实体类型int ENTITY_TYPE_POST = 1;//评论的实体类型int ENTITY_TYPE_COMMENT = 2;
四:评论帖子
添加评论的功能也是比较基础的,按照数据层业务层和表现层进行开发,比较特别的就是会用到前面提到的事务管理。
为了效率,在帖子的字段里设计了一个评论数量,那么我们添加评论的时候就要同时更新评论数量。
添加 评论分为三种:①回帖 ②回评论 ③回某人评论
- 在 discuss-detail 页面点击最下方的回帖,映射到 CommentController 层的 /add/{discussPostId}。addComment方法里声明一个实体来知道给帖子评论的还是给某人回复的,① 传入了 entityType = 1 和 entityId = post.id 。② 在评论下方回复,与①映射相同,传入entityType = 2 和 entityId = comment.id。③ 对某人的评论回复,与①映射相同,传入entityType = 2 和 entityId = comment.id 和 targetId。
- 对传入的 comment 进一步设置userId,Status,CreateTime。然后调用commentService.addComment(comment) 方法插入数据库。commentService.addComment 使用了事务注解。该方法对 comment 的 content 进行转义HTML标记。然后使用 commentMapper.insertComment 插入评论。然后通过 commentMapper.selectCountByEntity 查询帖子的评论数量,再使用 discussPostService.updateCommentCount 方法将评论数量插入帖子详情表。
- 重定向 return “redirect:/discuss/detail/” + 帖子discussPostId。 刷新帖子详情页面。
①DiscussPostMapper中添加方法UpdatecommentCount:
帖子表因为有一个冗余的显示帖子数量的一个字段,所以帖子更新后,帖子表也要进行一个更新。
//插入评论后,更新对应帖子的评论数量
int updateCommentCount(int id, int commentCount);
对应的discusspost-mapper.xml的SQL语句:<update id="updateCommentCount">update discuss_post set comment_count = #{commentCount} where id = #{id}</update>
②CommentMapper里新增 添加评论的方法insertcomment
package com.nowcoder.mycommunity.dao;
import com.nowcoder.mycommunity.entity.Comment;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;@Mapper
public interface CommentMapper {//查询评论时,进行分页的两个方法List<Comment> selectCommentsByEntity(int entityType, int entityId, int offset, int limit);int selectCountByEntity(int entityType, int entityId);//增加评论int insertComment(Comment comment);
}
在resources.mapper创建对应的comment-mapper.xml:<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.nowcoder.mycommunity.dao.CommentMapper"><!--查询字段--><sql id="selectFields">id, user_id, entity_type, entity_id, target_id, content, status, create_time</sql><!--插入字段:比查询少一个id(主键自增)--><sql id="insertFields">user_id, entity_type, entity_id, target_id, content, status, create_time</sql><select id="selectCommentsByEntity" resultType="Comment">select <include refid="selectFields"></include>from commentwhere status = 0and entity_type = #{entityType}and entity_id = #{entityId}order by create_time asclimit #{offset}, #{limit}</select><select id="selectCountByEntity" resultType="int">select count(id)from commentwhere status = 0and entity_type = #{entityType}and entity_id = #{entityId}</select><!--添加评论--><insert id="insertComment" parameterType="Comment">insert into comment (<include refid="insertFields"></include>)values (#{userId}, #{entityType}, #{entityId}, #{targetId}, #{content}, #{status}, #{createTime})</insert></mapper>
3. 业务层
①DiscussPostService中添加刚才增删改查的业务方法updateCommentCount
//业务:插入评论后,更新对应帖子的评论数量public int updateCommentCount(int id, int commentCount){return discussPostMapper.updateCommentCount(id, commentCount);}
②创建CommentService,处理增加评论的核心操作,当前都在一个事务之内所以用声明式事务,加上 @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)注解,隔离级别,传播机制;只有更新为帖子的评论时,才更新其数量。
@Service
public class CommentService implements CommunityConstant {@Autowiredprivate CommentMapper commentMapper;@Autowiredprivate SensitiveFilter sensitiveFilter;@Autowiredprivate DiscussPostService discussPostService;public List<Comment> findCommentsByEntity(int entityType, int entityId, int offset, int limit){return commentMapper.selectCommentsByEntity(entityType, entityId, offset, limit);}public int findCommentCount(int entityType, int entityId){return commentMapper.selectCountByEntity(entityType, entityId);}//增加评论@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED)public int addComment(Comment comment){if(comment == null){throw new IllegalArgumentException("参数不能为空!");}//评论的敏感词过滤comment.setContent(HtmlUtils.htmlEscape(comment.getContent()));comment.setContent(sensitiveFilter.filter(comment.getContent()));int rows = commentMapper.insertComment(comment);//更新对应帖子的评论数量if(comment.getEntityType() == ENTITY_TYPE_POST){//int count = commentMapper.selectCountByEntity(comment.getEntityType(), comment.getEntityId());discussPostService.updateCommentCount(comment.getEntityId(), count);}return rows;}
}
4. 表现层
新建一个CommentController,从地址里获取当前帖子的id,方便评论完重定向,前端传来的评论需要完善数据。
@Controller
@RequestMapping("/comment")
public class CommentController {@Autowiredprivate CommentService commentService;@Autowiredprivate HostHolder hostHolder;//插入评论@RequestMapping(path = "/add/{discussPostId}", method = RequestMethod.POST)public String addComment(@PathVariable("discussPostId") int discussPostId, Comment comment){comment.setUserId(hostHolder.getUser().getId());comment.setStatus(0);comment.setCreateTime(new Date());commentService.addComment(comment);return "redirect:/discuss/detail/" + discussPostId;}
}
4.发布帖子,评论帖子相关推荐
- 微信小程序云开发-树洞小程序Treehole(评论帖子/发布话题实现)
这一节介绍的是评论帖子,还有发布话题功能的实现. 首先说说评论帖子的功能. 先看一下效果图: 从上一节可知,进行评论跳转的时候需要带来一些关于帖子的数据. 这一个页面对于布局来说,也是十分的重要.评论 ...
- python爬虫——豆瓣小组,查询某用户在小组中发布的所有帖子
我学习的思路,一般就是技术根据技术贴,技术视频学习,而经验要从实战中获得.在生活中,常常动脑筋,把问题用自己掌握的技能来解决,既能巩固自己的技术,学习经验,又能有成就感,一举两得. 最近出去玩,经常翻 ...
- Flask项目实战——12—(帖子评论和阅读数功能、帖子分类功能实现、项目完善、引入Celery异步发送邮件)
1.帖子评论和阅读数功能 添加阅读数量字段:前台模型文件 apps/front/models.py # 帖子编辑提交模型 class PostModel(db.Model):__tablename__ ...
- 3.2 AJAX发布帖子 显示帖子详情
文章目录 AJAX发布帖子 显示帖子详情 1.引入fastjson包 2.编写方法获取JSON字符串 增加插入帖子的方法 编写DiscussPostMapper 编写DiscussPostServic ...
- [附源码]java毕业设计新闻发布和评论管理系统
项目运行 环境配置: Jdk1.8 + Tomcat7.0 + Mysql + HBuilderX(Webstorm也行)+ Eclispe(IntelliJ IDEA,Eclispe,MyEclis ...
- android楼层评论,看中兴小鲜2发布直播 评论互动赢新机
2014年10月,中兴联手中国电信推出4G互联网手机--中兴小鲜.这款产品结合主流性能与亲民价位,主打性价比电信机路线.时隔半年之后,中兴小鲜2又将登场,同样的电信4G机型,将带来怎样出色的年轻鲜享体 ...
- 系统集成Facebook授权发布帖子以及获取帖子评论等功能
公司的业务和海外贸易紧密连接,项目中需要对接Facebook.Google.Twitter相关API,下面详细描述一下我们对接Facebook中遇到的问题 1,注册Facebook账户,Faceboo ...
- 常用的评论/帖子/文章排序算法一(Delicious和Hacker News)
背景 最近在做评论排序的需求,之前都是按照评论的点赞数来倒排.但是用的很多其它的app并不是这么简单的排序方式,所以本次决定好好研究一下,就有了这几篇 文章的转载.本文转载于阮一峰的网络日志http: ...
- Java 社区平台 Sym 2.6.0 发布,增加帖子列表渲染方式
新增特性 568 帖子列表显示方式 592 帖子锁定 596 领域可设置是否渲染导航 细节改进 588 数据库使用 utf8mb4 字符集 591 默认使用中文初始化 602 性能优化 607 用户可 ...
最新文章
- Oracle 11g服务器与客户端卸载、安装
- 求高光谱图像相关系数矩阵
- 快搜浏览器_opera、Google、firefox三个浏览器的选择
- 2019\Province_C_C++_B\试题G-完全二叉树的权值
- 使用windows的小技巧
- Building Seam 2.0 Application with NetBeans 6.1
- php动态添加查询,php动态添加url查询参数的方法,php动态url参数_PHP教程
- 关于c语言的英文论文,C语言论文外文翻译.doc
- Leedcode1-求树的最小高度
- eigrp hello报文格式
- Eclipse-class文件中文乱码
- WPF与输入法冲突研究之三:韩文输入法在不同平台,WinForm/WPF下的区别
- 13. PHP 表数据入口(table data gateway)
- linux vi编译显示行号,Linux系统vi或者vim编辑器中如何显示行号
- 那么多北漂程序员,到了35岁以后该怎么选择往后的路?
- AD603+MCP4725+STM32-----自动增益控制电路
- jadx-gui-1.4.4 反编译工具使用教程
- 【整理分享】2019年▪尔雅通识课▪《移动互联网时代的信息安全与防护》▪期末考试答案
- 【报告分享】 2020年汽车产销数据及汽车工业运行情况-中国汽车工业协会(附下载)
- HTML5新特性知识点总结