10-3-查看文章详情

文章详情包括评论,之前写的ArticleMapper已经实现根据id查询文章详情,现在补充评论功能。

一、创建评论的数据访问层接口CommentMapper

在该接口上添加@Mapper,接口内添加如下方法:   

    // 分页展示某个文章的评论
    @Select("SELECT * FROM t_comment WHERE article_id=#{aid} ORDER BY id DESC")
    public List<Comment> selectCommentWithPage(Integer aid);

    // 后台查询最新几条评论
    @Select("SELECT * FROM t_comment ORDER BY id DESC")
    public List<Comment> selectNewComment();

    // 发表评论
    @Insert("INSERT INTO t_comment (article_id,created,author,ip,content)" +
            " VALUES (#{articleId}, #{created},#{author},#{ip},#{content})")
    public void pushComment(Comment comment);

    // 站点服务统计,统计评论数量
    @Select("SELECT COUNT(1) FROM t_comment")
    public Integer countComment();

    // 通过文章id删除评论信息
    @Delete("DELETE FROM t_comment WHERE article_id=#{aid}")
    public void deleteCommentWithId(Integer aid);

二、业务处理层实现

1、在IArticleService添加查询文章详情的方法

// 根据文章id查询单个文章详情
public Article selectArticleWithId(Integer id);

2.创建评论业务处理接口ICommentService

//文章评论业务处理接口
public interface ICommentService {

    // 获取文章下的评论
    public PageInfo<Comment> getComments(Integer aid, int page, int count);

}

3.创建博客站点业务处理接口 ISiteService

//博客站点统计服务
public interface ISiteService {

    // 最新收到的评论
    public List<Comment> recentComments(int count);

    // 最新发表的文章
    public List<Article> recentArticles(int count);

    // 获取后台统计数据
    public StaticticsBo getStatistics();

    // 更新某个文章的统计数据
    public void updateStatistics(Article article);

}

4.打开ArticleServiceImpl,实现查询文章详情,嵌入Redis缓存管理

先使用@Autowired注入定制的RedisTemplate类(在config包下定制的配置类),

然后在文章查询过程中先从Redis缓存中进行查询,如果为空再进行数据库查询,并将结果进行缓存处理。

其中,此处缓存管理的文章详情数据的key为“article_” + id的形式。

    @Autowired
    private RedisTemplate redisTemplate;

    // 根据id查询单个文章详情,并使用Redis进行缓存管理
    public Article selectArticleWithId(Integer id){
        Article article = null;
        Object o = redisTemplate.opsForValue().get("article_" + id);
        if(o!=null){
            article=(Article)o;
        }else{
            article = articleMapper.selectArticleWithId(id);
            if(article!=null){
                redisTemplate.opsForValue().set("article_" + id,article);
            }
        }
        return article;
    }

5.实现ICommentService和ISiteService接口

@Service
@Transactional
public class CommentServiceImpl implements ICommentService {
    @Autowired
    private CommentMapper commentMapper;
    // 根据文章id分页查询评论
    @Override
    public PageInfo<Comment> getComments(Integer aid, int page, int count) {
        PageHelper.startPage(page,count);
        List<Comment> commentList = commentMapper.selectCommentWithPage(aid);
        PageInfo<Comment> commentInfo = new PageInfo<>(commentList);
        return commentInfo;
    }
}
@Service
@Transactional
public class SiteServiceImpl implements ISiteService {

    @Autowired
    private CommentMapper commentMapper;
    @Autowired
    private ArticleMapper articleMapper;
    @Autowired
    private StatisticMapper statisticMapper;

    @Override
    public void updateStatistics(Article article) {

        Statistic statistic =
                    statisticMapper.selectStatisticWithArticleId(article.getId());
        statistic.setHits(statistic.getHits()+1);
        statisticMapper.updateArticleHitsWithId(statistic);
    }

    @Override
    public List<Comment> recentComments(int limit) {
        PageHelper.startPage(1, limit>10 || limit<1 ? 10:limit);
        List<Comment> byPage = commentMapper.selectNewComment();
        return byPage;
    }

    @Override
    public List<Article> recentArticles(int limit) {
        PageHelper.startPage(1, limit>10 || limit<1 ? 10:limit);
        List<Article> list = articleMapper.selectArticleWithPage();
        // 封装文章统计数据
        for (int i = 0; i < list.size(); i++) {
            Article article = list.get(i);
            Statistic statistic =
                        statisticMapper.selectStatisticWithArticleId(article.getId());
            article.setHits(statistic.getHits());
            article.setCommentsNum(statistic.getCommentsNum());
        }
        return list;
    }

    @Override
    public StaticticsBo getStatistics() {
        StaticticsBo staticticsBo = new StaticticsBo();
        Integer articles = articleMapper.countArticle();
        Integer comments = commentMapper.countComment();
        staticticsBo.setArticles(articles);
        staticticsBo.setComments(comments);
        return staticticsBo;
    }
}

三、请求处理层实现

打开用户首页请求处理类IndexController,注入评论服务对象和站点服务对象,并添加文章详情查询方法,用来处理请求路径为“/article/{id}”的请求。

方法实现过程:

        先查询出对应的文章信息,然后对文章的评论信息进行查询封装,

        同时更新了文章的点击量统计信息。

        在完成文章数据的查询后,如果文章不为空,跳转到client文件夹下的articleDetails.html文件;

        如果文件为空,跳转到自定义的comm文件夹下的error_404.html错误页面。

    @Autowired
    private ICommentService commentServiceImpl;
    @Autowired
    private ISiteService siteServiceImpl;
    
    // 文章详情查询
    @GetMapping(value = "/article/{id}")
    public String getArticleById(@PathVariable("id") Integer id, HttpServletRequest request){
        Article article = articleServiceImpl.selectArticleWithId(id);
        if(article!=null){
            // 查询封装评论相关数据
            getArticleComments(request, article);
            // 更新文章点击量
            siteServiceImpl.updateStatistics(article);
            request.setAttribute("article",article);
            return "client/articleDetails";
        }else {
            logger.warn("查询文章详情结果为空,查询文章id: "+id);
            // 未找到对应文章页面,跳转到提示页
            return "comm/error_404";
        }
    }


    // 查询文章的评论信息,并补充到文章详情里面
    private void getArticleComments(HttpServletRequest request, Article article) {
        if (article.getAllowComment()) {
            // cp表示评论页码,commentPage
            String cp = request.getParameter("cp");
            cp = StringUtils.isBlank(cp) ? "1" : cp;
            request.setAttribute("cp", cp);
            PageInfo<Comment> comments = commentServiceImpl.getComments(article.getId(),Integer.parseInt(cp),3);
            request.setAttribute("cp", cp);
            request.setAttribute("comments", comments);
        }
    }

四、实现前端页面功能

项目类目录下client目录中的文章详情页面articleDetails.html

通过th:*属性获取并展示了后台查询得到的文章及评论详情数据,同时在页面底部的<script>标签中实现了一个图片缩放功能。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <script th:src="@{/assets/js/jquery.min.js}"></script>
    <script th:src="@{/assets/js/layer.js}"></script>
</head>
<div th:replace="client/header::header(${article.title},null)"></div>

<body>
<article class="main-content post-page">
    <div class="post-header">
        <h1 class="post-title" itemprop="name headline" th:text="${article.title}"></h1>
        <div class="post-data">
            <time th:datetime="${commons.dateFormat(article.created)}" itemprop="datePublished" th:text="'发布于 '+ ${commons.dateFormat(article.created)}"></time>
        </div>
    </div>
    <br />
    <div id="post-content" class="post-content content" th:utext="${commons.article(article.content)}"></div>
</article>
<div th:replace="client/comments::comments"></div>
<div th:replace="client/footer::footer"></div>

<!-- 使用layer.js实现图片缩放功能 -->
<script type="text/JavaScript">
    $('.post-content img').on('click', function(){
        var imgurl=$(this).attr('src');
        var w=this.width*2;
        var h=this.height*2+50;
        layer.open({
            type: 1,
            title: false, //不显示标题栏
            area: [w+"px", h+"px"],
            shadeClose: true, //点击遮罩关闭
            content: '\<\div style="padding:20px;">' +
                    '\<\img style="width:'+(w-50)+'px;" src='+imgurl+'\>\<\/div>'
        });
    });
</script>
</body>
</html>

五、Redis服务启动与配置

之前的环节中已经引入了自定义的Redis配置类,同时还引入了Redis服务连接需要的配置文件application-redis.properties,最后需要做的就是启动Redis服务即可。

六、效果展示

启动项目,登录并进入项目首页,在项目首页随机选择一篇文章单击文章名查看文章详情,或者选择阅读排行榜中的一篇文章进行详情查看。

通过Redis客户端可视化管理工具查看缓存的文章详情数据

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值