以下代码为实现文章分页展示:
1.数据访问层实现
ArticleMapper 接口类
package com.itheima.dao;
import com.itheima.model.domain.Article;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 简单sql语句使用注解实现
* 复杂sql语句使用xml配置文件实现
*
* @author FXQ
* @date 2024/01/08
*/
@Mapper
public interface ArticleMapper {
// 根据id查询文章信息
@Select("SELECT * FROM t_article WHERE id=#{id}")
public Article selectArticleWithId(Integer id);
// 发表文章,同时使用@Options注解获取自动生成的主键id
@Insert("INSERT INTO t_article (title,created,modified,tags,categories," +
" allow_comment, thumbnail, content)" +
" VALUES (#{title},#{created}, #{modified}, #{tags}, #{categories}," +
" #{allowComment}, #{thumbnail}, #{content})")
@Options(useGeneratedKeys=true, keyProperty="id", keyColumn="id")
public Integer publishArticle(Article article);
// 文章发分页查询
@Select("SELECT * FROM t_article ORDER BY id DESC")
public List<Article> selectArticleWithPage();
// 通过id删除文章
@Delete("DELETE FROM t_article WHERE id=#{id}")
public void deleteArticleWithId(int id);
// 站点服务统计,统计文章数量
@Select("SELECT COUNT(1) FROM t_article")
public Integer countArticle();
// 通过id更新文章
public Integer updateArticleWithId(Article article);
}
StatisticMapper 接口类
package com.itheima.dao;
import com.itheima.model.domain.Article;
import com.itheima.model.domain.Statistic;
import org.apache.ibatis.annotations.*;
import java.util.List;
/**
* 简单sql语句使用注解实现
* 复杂sql语句使用xml配置文件实现
*
* @author FXQ
* @date 2024/01/08
*/
@Mapper
public interface StatisticMapper {
// 新增文章对应的统计信息
@Insert("INSERT INTO t_statistic(article_id,hits,comments_num) values (#{id},0,0)")
public void addStatistic(Article article);
// 根据文章id查询点击量和评论量相关信息
@Select("SELECT * FROM t_statistic WHERE article_id=#{articleId}")
public Statistic selectStatisticWithArticleId(Integer articleId);
// 通过文章id更新点击量
@Update("UPDATE t_statistic SET hits=#{hits} " +
"WHERE article_id=#{articleId}")
public void updateArticleHitsWithId(Statistic statistic);
// 通过文章id更新评论量
@Update("UPDATE t_statistic SET comments_num=#{commentsNum} " +
"WHERE article_id=#{articleId}")
public void updateArticleCommentsWithId(Statistic statistic);
// 根据文章id删除统计数据
@Delete("DELETE FROM t_statistic WHERE article_id=#{aid}")
public void deleteStatisticWithId(int aid);
// 统计文章热度信息
@Select("SELECT * FROM t_statistic WHERE hits !='0' " +
"ORDER BY hits DESC, comments_num DESC")
public List<Statistic> getStatistic();
// 统计博客文章总访问量
@Select("SELECT SUM(hits) FROM t_statistic")
public long getTotalVisit();
// 统计博客文章总评论量
@Select("SELECT SUM(comments_num) FROM t_statistic")
public long getTotalComment();
}
2.业务处理实现层
IArticleService 接口类
package com.itheima.service;
import com.github.pagehelper.PageInfo;
import com.itheima.model.domain.Article;
import java.util.List;
/**
* @author FXQ
* @date 2024/01/08
*/
public interface IArticleService {
// 分页查询文章列表
public PageInfo<Article> selectArticleWithPage(Integer page, Integer count);
// 统计前10的热度文章信息
public List<Article> getHeatArticles();
// 根据文章id查询单个文章详情
public Article selectArticleWithId(Integer id);
// 发布文章
public void publish(Article article);
// 根据主键更新文章
public void updateArticleWithId(Article article);
// 根据主键删除文章
public void deleteArticleWithId(int id);
}
ArticleServiceImpl 接口实现类
package com.itheima.service.impl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.itheima.dao.ArticleMapper;
import com.itheima.dao.CommentMapper;
import com.itheima.dao.StatisticMapper;
import com.itheima.model.domain.Article;
import com.itheima.model.domain.Statistic;
import com.itheima.service.IArticleService;
import com.vdurmont.emoji.EmojiParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* Service包,业务层,用来处理逻辑上的业务,不考虑具体实现
*/
@Service
@Transactional
public class ArticleServiceImpl implements IArticleService {
@Autowired
private ArticleMapper articleMapper;
@Autowired
private StatisticMapper statisticMapper;
@Autowired
private RedisTemplate redisTemplate;
@Autowired
private CommentMapper commentMapper;
// 分页查询文章列表
@Override
public PageInfo<Article> selectArticleWithPage(Integer page, Integer count) {
PageHelper.startPage(page, count);
List<Article> articleList = articleMapper.selectArticleWithPage();
// 封装文章统计数据
for (int i = 0; i < articleList.size(); i++) {
Article article = articleList.get(i);
Statistic statistic = statisticMapper.selectStatisticWithArticleId(article.getId());
article.setHits(statistic.getHits());
article.setCommentsNum(statistic.getCommentsNum());
}
PageInfo<Article> pageInfo=new PageInfo<>(articleList);
return pageInfo;
}
// 统计前10的热度文章信息
@Override
public List<Article> getHeatArticles( ) {
List<Statistic> list = statisticMapper.getStatistic();
List<Article> articlelist=new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
Article article = articleMapper.selectArticleWithId(list.get(i).getArticleId());
article.setHits(list.get(i).getHits());
article.setCommentsNum(list.get(i).getCommentsNum());
articlelist.add(article);
if(i>=9){
break;
}
}
return articlelist;
}
// 根据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;
}
// 发布文章
@Override
public void publish(Article article) {
// 去除表情
article.setContent(EmojiParser.parseToAliases(article.getContent()));
article.setCreated(new Date());
article.setHits(0);
article.setCommentsNum(0);
// 插入文章,同时插入文章统计数据
articleMapper.publishArticle(article);
statisticMapper.addStatistic(article);
}
// 更新文章
@Override
public void updateArticleWithId(Article article) {
article.setModified(new Date());
articleMapper.updateArticleWithId(article);
redisTemplate.delete("article_" + article.getId());
}
// 删除文章
@Override
public void deleteArticleWithId(int id) {
// 删除文章的同时,删除对应的缓存
articleMapper.deleteArticleWithId(id);
redisTemplate.delete("article_" + id);
// 同时删除对应文章的统计数据
statisticMapper.deleteStatisticWithId(id);
// 同时删除对应文章的评论数据
commentMapper.deleteCommentWithId(id);
}
}
3.请求处理层实现
IndexController 控制层处理类
package com.itheima.web.client;
import com.github.pagehelper.PageInfo;
import com.itheima.model.domain.Article;
import com.itheima.model.domain.Comment;
import com.itheima.service.IArticleService;
import com.itheima.service.ICommentService;
import com.itheima.service.ISiteService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
@Controller
public class IndexController {
private static final Logger logger = LoggerFactory.getLogger(IndexController.class);
@Autowired
private IArticleService articleServiceImpl;
// 博客首页,会自动跳转到文章页
@GetMapping(value = "/")
private String index(HttpServletRequest request) {
return this.index(request, 1, 5);
}
// 文章页
@GetMapping(value = "/page/{p}")
public String index(HttpServletRequest request, @PathVariable("p") int page, @RequestParam(value = "count", defaultValue = "5") int count) {
PageInfo<Article> articles = articleServiceImpl.selectArticleWithPage(page, count);
// 获取文章热度统计信息
List<Article> articleList = articleServiceImpl.getHeatArticles();
request.setAttribute("articles", articles);
request.setAttribute("articleList", articleList);
logger.info("分页获取文章信息: 页码 "+page+",条数 "+count);
return "client/index";
}
@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);
}
}
}
BaseInterceptor 自定义拦截器类
package com.itheima.web.interceptor;
import com.itheima.utils.Commons;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义的Interceptor拦截器类,用于封装请求后的数据类到request域中,供html页面使用
* 注意:自定义Mvc的Interceptor拦截器类
* 1、使用@Configuration注解声明
* 2、自定义注册类将自定义的Interceptor拦截器类进行注册使用
*/
@Configuration
public class BaseInterceptor implements HandlerInterceptor {
@Autowired
private Commons commons;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 用户将封装的Commons工具返回页面
request.setAttribute("commons",commons);
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
}
}
WebMvcConfig 类
package com.itheima.web.interceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private BaseInterceptor baseInterceptor;
@Override
// 重写addInterceptors()方法,注册自定义拦截器
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(baseInterceptor);
}
}
注意,导包创建请严格按照书上要求进行,避免导包出现错误
该代码为完整代码,后面功能可用,若不需要请自行注释,避免报错
项目资源,完整代码可私聊
运行结果如下: