第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)

学习目标:

8-1 保存留言功能开发
8-2 查询留言列表分页接口
8-3 留言列表分页前后端联调
8-4 评论回复sql设计与查询
8-5 页显示回复评论
8-6 评论回复功能开发


学习内容:

8-1 保存留言功能开发

1、在VideoController.java中编写保存留言的接口saveComment

	@PostMapping("/saveComment")
	public IMoocJSONResult saveComment(@RequestBody Comments comment, 
			String fatherCommentId, String toUserId) throws Exception {
     
		
		comment.setFatherCommentId(fatherCommentId);
		comment.setToUserId(toUserId);
		
		videoService.saveComment(comment);
		return IMoocJSONResult.ok();
	}

2、添加拦截器第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第1张图片
3、在VideoService.java中定义saveComment的方法:

	/**
	 * @Description: 用户留言
	 */
	public void saveComment(Comments comment);

4、在VideoServiceImpl.java中对上面的方法进行实现:

	@Transactional(propagation = Propagation.REQUIRED)
	@Override
	public void saveComment(Comments comment) {
     
		String id = sid.nextShort();
		comment.setId(id);
		comment.setCreateTime(new Date());
		commentMapper.insert(comment);
	}
	

5、前端:在videoinfo.wxml中编写前端页面代码:

<view class="saySthView">
<input name="commentContent" class="saySth" placeholder="说点什么吧。。。" confirm-type="send" bindconfirm="saveComment" focus='{
     {commentFocus}}' value='{
     {contentValue}}'
data-replyFatherCommentId='{
     {replyFatherCommentId}}'
data-replyToUserId='{
     {replyToUserId}}'
/>
</view>

显示如下:
第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第2张图片

6、在videoinfo.js中编写前端逻辑代码:

使得点击留言按钮,可以跳出最下方的弹框,进行编写留言:


  leaveComment:function(){
     
    this.setData({
     
      commentFocus:true
    });
  }

保存留言到数据库的代码:

 saveComment:function(e){
     
    var me = this;
    var content = e.detail.value;

    var user = app.getGlobalUserInfo();
    var videoInfo = JSON.stringify(me.data.videoInfo);
    var realUrl = '../videoinfo/videoinfo#videoInfo@' + videoInfo;

    if (user == null || user == undefined || user == '') {
     
      wx.navigateTo({
     
        url: '../userLogin/login?redirectUrl=' + realUrl,
      })
    } else {
     
      wx.showLoading({
     
        title: '请稍后...',
      })
      wx.request({
     
        url: app.serverUrl + '/video/saveComment',
        method: 'POST',
        header: {
     
          'content-type': 'application/json', // 默认值
          'userId':user.id,//用于安全验证的信息
          'userToken':user.userToken
        },
        data: {
     
          fromUserId: user.id,
          videoId: me.data.videoInfo.id,
          comment: content
        },
        success: function(res) {
     
          console.log(res.data)
          wx.hideLoading();

          me.setData({
     
            contentValue: ""
          });
        }
      })
    }
  }

8-2 查询留言列表分页接口和8-3留言列表分页前后端联调

1、在VideoController.java中编写保存留言的接口getVideoComments

	@PostMapping("/getVideoComments")
	public IMoocJSONResult getVideoComments(String videoId, Integer page, Integer pageSize) throws Exception {
     
		
		if (StringUtils.isBlank(videoId)) {
     
			return IMoocJSONResult.ok();
		}
		
		// 分页查询视频列表,时间顺序倒序排序
		if (page == null) {
     
			page = 1;
		}

		if (pageSize == null) {
     
			pageSize = 10;
		}
		
		PagedResult list = videoService.getAllComments(videoId, page, pageSize);
		
		return IMoocJSONResult.ok(list);
	}

2、添加拦截器

这个接口是不需要被拦截的,所以不用加;

3、在VideoService.java中定义getAllComments的方法:

	/**
	 * @Description: 留言分页
	 */
	public PagedResult getAllComments(String videoId, Integer page, Integer pageSize);

4、在VideoServiceImpl.java中对上面的方法进行实现:

@Transactional(propagation = Propagation.SUPPORTS)
	@Override
	public PagedResult getAllComments(String videoId, Integer page, Integer pageSize) {
     
		
		PageHelper.startPage(page, pageSize);
		
		List<CommentsVO> list = commentMapperCustom.queryComments(videoId);
		
			for (CommentsVO c : list) {
     
				String timeAgo = TimeAgoUtils.format(c.getCreateTime());
				c.setTimeAgoStr(timeAgo);
			}
		
		PageInfo<CommentsVO> pageList = new PageInfo<>(list);
		
		PagedResult grid = new PagedResult();
		grid.setTotal(pageList.getPages());
		grid.setRows(list);
		grid.setPage(page);
		grid.setRecords(pageList.getTotal());
		
		return grid;
	}
	

5、新建自定义mapper方法:

1)首先新建pojo类:在com.asayi.pojo.vo包中新建CommentsVO.java自定义pojo对象:

package com.asayi.pojo.vo;

import java.util.Date;
import javax.persistence.*;

import org.springframework.format.annotation.DateTimeFormat;

public class CommentsVO {
     
    private String id;

    /**
     * 视频id
     */
    private String videoId;

    /**
     * 留言者,评论的用户id
     */
    private String fromUserId;

    private Date createTime;

    /**
     * 评论内容
     */
    private String comment;
    
    private String faceImage;
    private String nickname;
    private String toNickname;
    private String timeAgoStr;
    

    public String getTimeAgoStr() {
     
		return timeAgoStr;
	}

	public void setTimeAgoStr(String timeAgoStr) {
     
		this.timeAgoStr = timeAgoStr;
	}

	public String getNickname() {
     
		return nickname;
	}

	public void setNickname(String nickname) {
     
		this.nickname = nickname;
	}

	public String getFaceImage() {
     
		return faceImage;
	}

	public void setFaceImage(String faceImage) {
     
		this.faceImage = faceImage;
	}

	/**
     * @return id
     */
    public String getId() {
     
        return id;
    }

    /**
     * @param id
     */
    public void setId(String id) {
     
        this.id = id;
    }

    /**
     * 获取视频id
     *
     * @return video_id - 视频id
     */
    public String getVideoId() {
     
        return videoId;
    }

    /**
     * 设置视频id
     *
     * @param videoId 视频id
     */
    public void setVideoId(String videoId) {
     
        this.videoId = videoId;
    }

    /**
     * 获取留言者,评论的用户id
     *
     * @return from_user_id - 留言者,评论的用户id
     */
    public String getFromUserId() {
     
        return fromUserId;
    }

    /**
     * 设置留言者,评论的用户id
     *
     * @param fromUserId 留言者,评论的用户id
     */
    public void setFromUserId(String fromUserId) {
     
        this.fromUserId = fromUserId;
    }

    /**
     * @return create_time
     */
    public Date getCreateTime() {
     
        return createTime;
    }

    /**
     * @param createTime
     */
    public void setCreateTime(Date createTime) {
     
        this.createTime = createTime;
    }

    /**
     * 获取评论内容
     *
     * @return comment - 评论内容
     */
    public String getComment() {
     
        return comment;
    }

    /**
     * 设置评论内容
     *
     * @param comment 评论内容
     */
    public void setComment(String comment) {
     
        this.comment = comment;
    }

	public String getToNickname() {
     
		return toNickname;
	}

	public void setToNickname(String toNickname) {
     
		this.toNickname = toNickname;
	}
}

2)新建VideosMapperCustom.java的mapper对象:

package com.asayi.mapper;

import java.util.List;

import com.asayi.pojo.Comments;
import com.asayi.pojo.vo.CommentsVO;
import com.asayi.utils.MyMapper;

public interface CommentsMapperCustom extends MyMapper<Comments> {
     
	
	public List<CommentsVO> queryComments(String videoId);
}

3)在VideosMapperCustom.xml中实现mapper的sql语句编写:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.asayi.mapper.CommentsMapperCustom" >
  <resultMap id="BaseResultMap" type="com.asayi.pojo.vo.CommentsVO" >
    <!--
      WARNING - @mbg.generated
    -->
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="video_id" property="videoId" jdbcType="VARCHAR" />
    <result column="from_user_id" property="fromUserId" jdbcType="VARCHAR" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="comment" property="comment" jdbcType="LONGVARCHAR" />
    <result column="face_image" property="faceImage" jdbcType="VARCHAR" />
    <result column="nickname" property="nickname" jdbcType="VARCHAR" />
    <result column="toNickname" property="toNickname" jdbcType="VARCHAR" />
  </resultMap>
  
select c.*,u.face_image as face_image,u.nickname from comments c left join asayi_users u on c.from_user_id = u.id 
	where c.video_id = #{
     videoId} order by c.create_time desc 
  
</mapper>

6、开源工具类:

第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第3张图片
TimeAgoUtils的代码如下:展示时间:

package com.asayi.utils;

import java.text.SimpleDateFormat;
import java.util.Date;

public class TimeAgoUtils {
     

	private static final long ONE_MINUTE = 60000L;
	private static final long ONE_HOUR = 3600000L;
	private static final long ONE_DAY = 86400000L;
	private static final long ONE_WEEK = 604800000L;

	private static final String ONE_SECOND_AGO = "秒前";
	private static final String ONE_MINUTE_AGO = "分钟前";
	private static final String ONE_HOUR_AGO = "小时前";
	private static final String ONE_DAY_AGO = "天前";
	private static final String ONE_MONTH_AGO = "月前";
	private static final String ONE_YEAR_AGO = "年前";

	public static String format(Date date) {
     
		long delta = new Date().getTime() - date.getTime();
		if (delta < 1L * ONE_MINUTE) {
     
			long seconds = toSeconds(delta);
			return (seconds <= 0 ? 1 : seconds) + ONE_SECOND_AGO;
		}
		if (delta < 45L * ONE_MINUTE) {
     
			long minutes = toMinutes(delta);
			return (minutes <= 0 ? 1 : minutes) + ONE_MINUTE_AGO;
		}
		if (delta < 24L * ONE_HOUR) {
     
			long hours = toHours(delta);
			return (hours <= 0 ? 1 : hours) + ONE_HOUR_AGO;
		}
		if (delta < 48L * ONE_HOUR) {
     
			return "昨天";
		}
		if (delta < 30L * ONE_DAY) {
     
			long days = toDays(delta);
			return (days <= 0 ? 1 : days) + ONE_DAY_AGO;
		}
		if (delta < 12L * 4L * ONE_WEEK) {
     
			long months = toMonths(delta);
			return (months <= 0 ? 1 : months) + ONE_MONTH_AGO;
		} else {
     
			long years = toYears(delta);
			return (years <= 0 ? 1 : years) + ONE_YEAR_AGO;
		}
	}

	private static long toSeconds(long date) {
     
		return date / 1000L;
	}

	private static long toMinutes(long date) {
     
		return toSeconds(date) / 60L;
	}

	private static long toHours(long date) {
     
		return toMinutes(date) / 60L;
	}

	private static long toDays(long date) {
     
		return toHours(date) / 24L;
	}

	private static long toMonths(long date) {
     
		return toDays(date) / 30L;
	}

	private static long toYears(long date) {
     
		return toMonths(date) / 365L;
	}

	public static void main(String[] args) throws Exception {
     
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:m:s");
		Date date = format.parse("2018-05-01 18:35:35");
		System.out.println(format(date));
	}

}

7、前端:wxml

<block wx:for="{
     {commentsList}}">
  <view class='comments-all' bindtap='replyFocus' 
  data-fatherCommentId='{
     {item.id}}'  
  data-toUserId='{
     {item.fromUserId}}' 
  data-toNickname='{
     {item.nickname}}' 
  >
      <view class='container-comments'>
          <image class="face-comments" src='{
     {serverUrl}}{
     {item.faceImage}}' ></image>
          <view class='nickname-comments'>
              <label class='nickname-lbl'>@{
     {
     item.nickname}}</label><label class='date-lbl'>{
     {
     item.timeAgoStr}}</label>
              <!-- 留言: -->
              <block wx:if="{
     {item.toNickname != null}}">
                回复
                <label class='nickname-lbl'>@{
     {
     item.toNickname}}</label>
              </block>
              <block wx:else>
                留言:
              </block>
          </view>
      </view>
      <view class='comments-content'>{
     {
     item.comment}}</view>
  </view>
</block> 

8、在videoinfo.js中编写前端逻辑代码:

从数据库中查询留言:查到后显示到小程序端:



  getCommentsList: function(page) {
     
    var me = this;

    var videoId = me.data.videoInfo.id;

    wx.request({
     
      url: app.serverUrl + '/video/getVideoComments?videoId=' + videoId + "&page=" + page + "&pageSize=5",
      method: "POST",
      success: function(res) {
     
        console.log(res.data);
      }
    })
  }

显示如下:
第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第4张图片

9、完善getCommentsList代码:

getCommentsList: function(page) {
     
    var me = this;

    var videoId = me.data.videoInfo.id;

    wx.request({
     
      url: app.serverUrl + '/video/getVideoComments?videoId=' + videoId + "&page=" + page + "&pageSize=5",
      method: "POST",
      success: function(res) {
     
        console.log(res.data);

        var commentsList = res.data.data.rows;
        var newCommentsList = me.data.commentsList;

          me.setData({
     
            commentsList: newCommentsList.concat(commentsList),//从后面进行拼接
            commentsPage: page,
            commentsTotalPage: res.data.data.total
          });

      }
    })
  },
  //触底响应函数
  onReachBottom: function() {
     
    var me = this;
    var currentPage = me.data.commentsPage;
    var totalPage = me.data.commentsTotalPage;
    if (currentPage === totalPage) {
     
      return;
    }
    var page = currentPage + 1;
    me.getCommentsList(page);
  }

8-4 评论回复sql设计与查询

1、在数据库comments中新建两个数据项:并重新用逆向生成工具生成。

第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第5张图片
2、修改CommentsMapperCustom.xml中的sql语句:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.asayi.mapper.CommentsMapperCustom" >
  <resultMap id="BaseResultMap" type="com.asayi.pojo.vo.CommentsVO" >
    <!--
      WARNING - @mbg.generated
    -->
    <id column="id" property="id" jdbcType="VARCHAR" />
    <result column="video_id" property="videoId" jdbcType="VARCHAR" />
    <result column="from_user_id" property="fromUserId" jdbcType="VARCHAR" />
    <result column="create_time" property="createTime" jdbcType="TIMESTAMP" />
    <result column="comment" property="comment" jdbcType="LONGVARCHAR" />
    <result column="face_image" property="faceImage" jdbcType="VARCHAR" />
    <result column="nickname" property="nickname" jdbcType="VARCHAR" />
    <result column="toNickname" property="toNickname" jdbcType="VARCHAR" />
  </resultMap>
  
  <!--   <select id="queryComments" resultMap="BaseResultMap" parameterType="String">
	select c.*,u.face_image as face_image,u.nickname from comments c left join asayi_users u on c.from_user_id = u.id 
	where c.video_id = #{
     videoId} order by c.create_time desc 
  </select>-->

  <select id="queryComments" resultMap="BaseResultMap" parameterType="String">
	select c.*,u.face_image as face_image,u.nickname,tu.nickname as toNickname 
	from comments c 
	left join asayi_users u on c.from_user_id = u.id
	left join asayi_users tu on c.to_user_id = tu.id
  	where c.video_id = #{
     videoId} order by c.create_time desc
  </select>
  
</mapper>

8-5 页显示回复评论

修改前端显示代码进行页显示回复评论:

 <view class='container-comments'>
          <image class="face-comments" src='{
     {serverUrl}}{
     {item.faceImage}}' ></image>
          <view class='nickname-comments'>
              <label class='nickname-lbl'>@{
     {
     item.nickname}}</label><label class='date-lbl'>{
     {
     item.timeAgoStr}}</label>
              <!-- 留言: -->
              <block wx:if="{
     {item.toNickname != null}}">
                回复
                <label class='nickname-lbl'>@{
     {
     item.toNickname}}</label>
              </block>
              <block wx:else>
                留言:
              </block>
          </view>
      </view>

8-6 评论回复功能开发

1、前端代码:

第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第6张图片
2、js代码:

replyFocus: function(e) {
     
    var fatherCommentId = e.currentTarget.dataset.fathercommentid;
    var toUserId = e.currentTarget.dataset.touserid;
    var toNickname = e.currentTarget.dataset.tonickname;
 
    this.setData({
     
      placeholder: "回复  " + toNickname,
      replyFatherCommentId: fatherCommentId,
      replyToUserId: toUserId,
      commentFocus: true
    });
  },
saveComment:function(e){
     
    var me = this;
    var content = e.detail.value;

    // 获取评论回复的fatherCommentId和toUserId
    var fatherCommentId = e.currentTarget.dataset.replyfathercommentid;
    var toUserId = e.currentTarget.dataset.replytouserid;

    var user = app.getGlobalUserInfo();
    var videoInfo = JSON.stringify(me.data.videoInfo);
    var realUrl = '../videoinfo/videoinfo#videoInfo@' + videoInfo;

    if (user == null || user == undefined || user == '') {
     
      wx.navigateTo({
     
        url: '../userLogin/login?redirectUrl=' + realUrl,
      })
    } else {
     
      wx.showLoading({
     
        title: '请稍后...',
      })
      wx.request({
     
        url: app.serverUrl + '/video/saveComment?fatherCommentId=' + fatherCommentId + "&toUserId=" + toUserId,
        method: 'POST',
        header: {
     
          'content-type': 'application/json', // 默认值
          'userId':user.id,//用于安全验证的信息
          'userToken':user.userToken
        },
        data: {
     
          fromUserId: user.id,
          videoId: me.data.videoInfo.id,
          comment: content
        },
        success: function(res) {
     
          console.log(res.data)
          wx.hideLoading();

          me.setData({
     
            contentValue: "",
            commentsList: [],
            placeholder: "",
            replyFatherCommentId: "",
            replyToUserId: "",
            commentFocus: false


          });
          me.getCommentsList(1);
        }
      })
    }
  },

3、修改后端代码:

@PostMapping("/saveComment")
	public IMoocJSONResult saveComment(@RequestBody Comments comment, 
			String fatherCommentId, String toUserId) throws Exception {
     
		
		comment.setFatherCommentId(fatherCommentId);
		comment.setToUserId(toUserId);
		
		videoService.saveComment(comment);
		return IMoocJSONResult.ok();
	}
	

4、运行测试:
第8章 :开发视频的留言板(8-1 保存留言功能开发 — 8-6 评论回复功能开发)_第7张图片

你可能感兴趣的:(我的小程序搭建之路,数据库,spring,boot,小程序)