美文网首页
评论和关注功能

评论和关注功能

作者: 六年的承诺 | 来源:发表于2019-04-17 19:05 被阅读0次

    1.数据库t_follow的设计:id,from_uid,to_uid1 4代表1号作者关注了4号用户


    t_folow.png
    t_follow.data.png

    2.高频操作?实际项目如何处理?
    点赞,关注,喜欢,统计阅读量
    先把数据存入缓存数据库,然后使用定时任务持久化到底层数据库

    后端

    • entity:1.Follow
    @Data
    public class Follow {
        private Integer id;
        private Integer fromUId;
        private Integer toUId;
    }
    

    2.FollowVO对象视图类

    @Data
    public class FollowVO {
        private Integer toUId;
        private String nickname;
        private String avatar;
    }```
    3.mapper接口设计FollowMapper
    insert方法,删除记录,根据fromID查所以,根据toid查所有,单一查(from,to)
    

    public interface FollowMapper {

    @Results({
            @Result(property = "id", column = "id"),
            @Result(property = "fromUId", column = "from_uid"),
            @Result(property = "toUId", column = "to_uid")
    })
    @Select("SELECT * FROM t_follow WHERE from_uid = #{fromUId} AND to_uid = #{toUId} ")
    Follow getFollow(@Param("fromUId") int fromUId, @Param("toUId") int toUId);
    
    @Results({
            @Result(property = "toUId", column = "to_uid"),
            @Result(property = "nickname", column = "nickname"),
            @Result(property = "avatar", column = "avatar")
    })
    @Select("SELECT a.to_uid,b.nickname,b.avatar FROM t_follow a LEFT JOIN t_user b ON a.to_uid = b.id WHERE a.from_uid = #{fromUId}  ")
    List<FollowVO> getFollowsByUId(int fromUId);
    
    @Insert("INSERT INTO t_follow (from_uid,to_uid) VALUES (#{fromUId},#{toUId}) ")
    void insertFollow(Follow follow);
    
    @Delete("DELETE  FROM t_follow WHERE from_uid = #{fromUId} AND to_uid = #{toUId} ")
    void deleteFollow(@Param("fromUId") int fromUId, @Param("toUId") int toUId);
    

    }

    CommentMapper增加插入方法```
    @Insert("INSERT INTO t_comment(u_id,a_id,content,comment_time) VALUES(#{uId}, #{aId}, #{content},#{commentTime}) ")
    void insert(Comment comment);
    

    4.service

    • FollowService
    public interface FollowService {
        Follow getFollow(int fromUId, int toUId);
    
        List<FollowVO> getFollowsByUId(int fromUId);
    
        void insertFollow(Follow follow);
    
        void deleteFollow(int fromUId, int toUId);
    }
    
    • CommentService
    public interface CommentService {
        List<CommentVO> selectCommentsByAId(int aId);
        void addComment(Comment comment);
    }
    

    5.实现类

    • FollowServiceImpl
    package com.soft1721.jianyue.api.service.impl;
    
    import com.soft1721.jianyue.api.entity.Follow;
    import com.soft1721.jianyue.api.entity.VO.FollowVO;
    import com.soft1721.jianyue.api.mapper.FollowMapper;
    import com.soft1721.jianyue.api.service.FollowService;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    
    @Service
    public class FollowServiceImpl implements FollowService {
        @Resource
        private FollowMapper followMapper;
    
        @Override
        public Follow getFollow(int fromUId, int toUId) {
    
            return followMapper.getFollow(fromUId, toUId);
        }
    
        @Override
        public List<FollowVO> getFollowsByUId(int fromUId) {
            return followMapper.getFollowsByUId(fromUId);
        }
    
        @Override
        public void insertFollow(Follow follow) {
            followMapper.insertFollow(follow);
    
        }
    
        @Override
        public void deleteFollow(int fromUId, int toUId) {
            followMapper.deleteFollow(fromUId,toUId);
        }
    }
    
    • CommentServiceImpl类
    package com.soft1721.jianyue.api.service.impl;
    
    import com.soft1721.jianyue.api.entity.Comment;
    import com.soft1721.jianyue.api.entity.VO.CommentVO;
    import com.soft1721.jianyue.api.mapper.CommentMapper;
    import com.soft1721.jianyue.api.service.CommentService;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.List;
    @Service
    public class CommentServiceImpl implements CommentService {
    
        @Resource
        private CommentMapper commentMapper;
        @Override
        public List<CommentVO> selectCommentsByAId(int aId) {
    
            return commentMapper.selectCommentsByAId(aId);
        }
    
        @Override
        public void addComment(Comment comment) {
            commentMapper.insert(comment);
    
        }
    }
    

    6.单元测试:

    • FollowServiceImplTest类
    package com.soft1721.jianyue.api.service.impl;
    
    import com.soft1721.jianyue.api.entity.Follow;
    import com.soft1721.jianyue.api.entity.VO.FollowVO;
    import com.soft1721.jianyue.api.service.FollowService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    import java.util.List;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class FollowServiceImplTest {
        @Resource
        private FollowService followService;
    
        @Test
        public void getFollow() {
            Follow followVO = followService.getFollow(1,4);
            System.out.println(followVO);
        }
    
        @Test
        public void getFollowsByUId() {
            List<FollowVO> followVO = followService.getFollowsByUId(1);
            System.out.println(followVO);
        }
    
        @Test
        public void insertFollow() {
            Follow follow = new Follow();
            follow.setFromUId(4);
            follow.setToUId(11);
            followService.insertFollow(follow);
        }
    
        @Test
        public void deleteFollow() {
            followService.deleteFollow(1,4);
        }
    }
    
    • CommentService
    package com.soft1721.jianyue.api.service.impl;
    
    import com.soft1721.jianyue.api.entity.Comment;
    import com.soft1721.jianyue.api.entity.VO.CommentVO;
    import com.soft1721.jianyue.api.mapper.CommentMapper;
    import com.soft1721.jianyue.api.service.CommentService;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.annotation.Resource;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import static org.junit.Assert.*;
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class CommentServiceImplTest {
        @Resource
        private CommentMapper commentMapper;
        @Resource
        private CommentService commentService;
    
        @Test
        public void selectCommentsByAId() {
            List<CommentVO> list = new ArrayList<>();
            list = commentMapper.selectCommentsByAId(1);
            System.out.println(list);
        }
        @Test
        public void addComment() {
            Comment comment = new Comment();
            comment.setAId(2);
            comment.setUId(4);
            comment.setContent("very good!");
            /* comment.setCommentTime(new Date(2019,04,10,9,43,35));*/
            commentService.addComment(comment);
        }
    
    }
    

    7.controller接口的获取文章方法,

    • FollowController
    @RestController
    @RequestMapping(value = "/api/follow")
    public class FollowController {
        @Resource
        private FollowService followService;
    
    
        @PostMapping("/add")
        public ResponseResult followUser(@RequestParam("fromUId") int fromUId, @RequestParam("toUId") int toUId) {
            Follow follow = new Follow();
            follow.setFromUId(fromUId);
            follow.setToUId(toUId);
            followService.insertFollow(follow);
            return ResponseResult.success();
        }
    
        @PostMapping("/cancel")
        public ResponseResult cancelFollow(@RequestParam("fromUId") int fromUId, @RequestParam("toUId") int toUId) {
            followService.deleteFollow(fromUId, toUId);
            return ResponseResult.success();
        }
    }
    
    • CommentController类
    @RestController
    @RequestMapping(value = "/api/comment")
    public class CommentController {
        @Resource
        private CommentService commentService;
    
        @PostMapping("/add")
        public ResponseResult addComment(@RequestParam("aId") int aId, @RequestParam("uId") int uId, @RequestParam("content") String content) {
            Comment comment = new Comment();
            comment.setAId(aId);
            comment.setUId(uId);
            comment.setContent(content);
            comment.setCommentTime(new Date());
            commentService.addComment(comment);
            return ResponseResult.success();
        }
    }
    

    修改一下ArticleController接口中的根据id获取文章的方法,增加一个参数:登录用户的id,来判断登录用户是否已经关注了文章作者

    @GetMapping(value = "/{aId}")
    public ResponseResult getArticleById(@PathVariable("aId") int aId,@RequestParam("userId") int userId) {
        ArticleVO article = articleService.getArticleById(aId);
        int toUId = article.getUId();
        Map<String, Object> map = new HashMap<>();
        Follow follow = followService.getFollow(userId, toUId);
        if (follow != null) {
            map.put("followed", MsgConst.FOLLOWED);
        } else {
            map.put("followed", MsgConst.NO_FOLLOWED);
        }
        List<CommentVO> comments = commentService.selectCommentsByAId(aId);
        map.put("article", article);
        map.put("comments", comments);
        return ResponseResult.success(map);
    }
    

    前端代码:

    article_detail.vue

    <template>
        <view class="container">
            <text class="article-title">{{ article.title }}</text>
            <view class="article-info">
                <image :src="article.avatar" class="avatar small"></image>
                <text class="nickname">{{ article.nickname }}</text>
                <!-- <text class="info-text">{{ handleTime(article.createTime) }}</text> -->
                <text>{{article.createTime}}</text>
                <!-- 登录用户和文章作者不是同一个人,就显示关注或取消关注按钮 -->
                <button v-if="userId != article.uId && !followed" class="follow-btn" @tap="follow">关注</button>
                <button v-if="userId != article.uId && followed" class="follow-btn cancel" @tap="cancelFollow">取消</button>
            </view>
    
            <view class="grace-text" style="margin-top: 10px;"><rich-text :nodes="article.content" bindtap="tap"></rich-text>
            <button v-if="userId != article.uId && !liked" class="follow-btn1" @tap="like">
                <image src="../../static/heart1.png"></image>
            </button>
            <button v-if="userId != article.uId && liked" class="follow-btn1 cancel" @tap="cancelLike">
                <image src="../../static/heart.png"></image>
            </button>
            </view>
            <text class="info-text">评论{{ comments.length }}</text>
            <view class="comment-item" v-for="(comment, index) in comments" :key="index">
                <view class="left"><image :src="comment.avatar" class="avatar small"></image></view>
                <view class="right">
                    <text>{{ comment.nickname }}</text>
                    <text>{{ comment.content }}</text>
                    <view>
                        <text style="margin-right: 10px;">{{ comments.length - index }}楼</text>
                        <!-- <text>{{ handleTime(comment.commentTime) }}</text> -->
                        <text>{{comment.commentTime}}</text>
                    </view>
                </view>
            </view>
            <input class="uni-input comment-box" type="text" placeholder="写下你的评论" v-model="content" required="required" />
            <button class="green-btn" @tap="send">提交</button>
        </view>
    </template>
    
    <script>
    export default {
        data() {
            return {
                article: {
                    aId: 0,
                    uId: 0,
                    title: '',
                    content: '',
                    avatar: '',
                    nickname: '',
                    createTime: ''
                },
                comments: [],
                content: '',
                userId: uni.getStorageSync('login_key').userId,
                followed: false,
                liked:false
            };
        },
        onLoad: function(option) {
            //option为object类型,会序列化上个页面传递的参数
            this.article.aId = option.aId;
        },
        onShow: function() {
            this.getArticle();
        },
        onPullDownRefresh: function() {
            this.getArticle();
        },
        methods: {
            getArticle: function() {
                var _this = this;
                uni.request({
                    url: this.apiServer + '/article/' + this.article.aId,
                    method: 'GET',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        userId: this.userId
                    },
                    success: res => {
                        console.log(res.data.data.article);
                        _this.article.aId = res.data.data.article.id;
                        _this.article.uId = res.data.data.article.uid;
                        _this.article.title = res.data.data.article.title;
                        _this.article.content = res.data.data.article.content;
                        _this.article.nickname = res.data.data.article.nickname;
                        _this.article.avatar = res.data.data.article.avatar;
                        _this.article.createTime = res.data.data.article.createTime;
                        _this.comments = res.data.data.comments;
                        if (res.data.data.followed === '已关注') {
                            _this.followed = true;
                            _this.liked=true;
                        }
                    },
                    complete: function() {
                        uni.stopPullDownRefresh();
                    }
                });
            },
            handleTime: function(date) {
                var d = new Date(date);
                var year = d.getFullYear();
                var month = d.getMonth() + 1;
                var day = d.getDate() < 10 ? '0' + d.getDate() : '' + d.getDate();
                var hour = d.getHours() < 10 ? '0' + d.getHours() : '' + d.getHours();
                var minutes = d.getMinutes() < 10 ? '0' + d.getMinutes() : '' + d.getMinutes();
                var seconds = d.getSeconds() < 10 ? '0' + d.getSeconds() : '' + d.getSeconds();
                return year + '-' + month + '-' + day + ' ' + hour + ':' + minutes + ':' + seconds;
            },
            send: function() {
                console.log('评论人编号:' + this.userId + ',文章编号:' + this.article.aId + ',评论内容:' + this.content);
                uni.request({
                    url: this.apiServer + '/comment/add',
                    method: 'POST',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        aId: this.article.aId,
                        uId: this.userId,
                        content: this.content
                    },
                    success: res => {
                        if (res.data.code === 0) {
                            uni.showToast({
                                title: '评论成功'
                            });
                            this.getArticle();
                            this.content = '';
                        }
                    }
                });
            },
            follow:function(){
                uni.request({
                    url: this.apiServer + '/follow/add',
                    method: 'POST',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        fromUId: this.userId,
                        toUId: this.article.uId
                    },
                    success: res => {
                        if (res.data.code === 0) {
                            uni.showToast({
                                title: '关注成功'
                            });
                            this.followed = true;
                        }
                    }
                });
            },
            like:function(){
                uni.request({
                    url: this.apiServer + '/like/add',
                    method: 'POST',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        fromId: this.userId,
                        toId: this.article.uId
                    },
                    success: res => {
                        if (res.data.code === 0) {
                            uni.showToast({
                                title: '喜欢'
                            });
                            this.liked = true;
                        }
                    }
                });
            },
            cancelFollow:function(){
                uni.request({
                    url: this.apiServer + '/follow/cancel',
                    method: 'POST',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        fromUId: this.userId,
                        toUId: this.article.uId
                    },
                    success: res => {
                        if (res.data.code === 0) {
                            uni.showToast({
                                title: '已取消关注'
                            });
                            this.followed = false;
                        }
                    }
                });
            },
            cancelLike:function(){
                uni.request({
                    url: this.apiServer + '/like/cancel',
                    method: 'POST',
                    header: { 'content-type': 'application/x-www-form-urlencoded' },
                    data: {
                        fromId: this.userId,
                        toId: this.article.uId
                    },
                    success: res => {
                        if (res.data.code === 0) {
                            uni.showToast({
                                title: ''
                            });
                            this.liked = false;
                        }
                    }
                });
            }
        }
    };
    </script>
    
    <style>
    .content {
        margin-bottom: 10px;
        margin-top: 10px;
        padding: 5px;
        border-bottom: 1px solid #eee;
    }
    .img-list {
        display: flex;
        flex-direction: column;
    }
    .img-item {
        width: 100%;
        height: 150px;
        margin-bottom: 5px;
    }
    .img-item image {
        width: 100%;
        height: 100%;
        border-radius: 5px;
    }
    .comment-item {
        display: flex;
        align-items: center;
        border-bottom: 1px solid #eee;
        margin-bottom: 10px;
        padding: 5px;
    }
    .comment-item .left {
        flex: 1 1 15%;
    }
    .comment-item .right {
        flex: 1 1 85%;
        display: flex;
        flex-direction: column;
    }
    .comment-box {
        /* border: 1px solid #fff;
        border-radius: 5px;
        background-color: #eee;
        height: 50upx; */
        margin-top: 20upx;
    }
    .follow-btn {
        height: 33px;
        width: 80px;
        font-size: 12pt;
        text-align: center;
        padding-bottom: 20px;
        margin-right: 0px;
        background: #10AEFF;
        color: #fff;
    }
    .cancel{
        background-color: #aaa;
    }
    .green-btn{
        background: #10AEFF;
        color: #fff;
    }
    .article-title{
        font-size: 40upx;
        font-weight: 700;
    }
    .grace-text{
        font-weight: 500;
        font-size: 40upx;
        border-bottom:10px solid #fff;
    }
    .article-info{
        display: flex;
        border-top:70upx solid #FFFFFF;
    }
    .follow-btn1{
        width: 200upx;
        height: 100upx;
        background: #fff;
    }
    .follow-btn1 image{
        width: 100upx;
        height: 50upx;
    }
    </style>
    

    相关文章

      网友评论

          本文标题:评论和关注功能

          本文链接:https://www.haomeiwen.com/subject/rrjgiqtx.html