springboot+thymeleaf+mybatisplus实现【动态分页】

准备工作

使用idea创建springboot项目

  • 此处跳过(有不会的小伙伴私聊我)

导入相关坐标依赖

<!--web相关依赖-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!--热部署-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-devtools</artifactId>
	<scope>runtime</scope>
	<optional>true</optional>
</dependency>

<!--thymeleaf模板引擎-->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

<!--thymeleaf中支持java8的时间类型(LocalDate和LocalDateTime)-->
<dependency>
   <groupId>org.thymeleaf.extras</groupId>
   <artifactId>thymeleaf-extras-java8time</artifactId>
</dependency>

<!--mybatisplus依赖-->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.5.2</version>
</dependency>

<!--mybatisplus代码生成器-->
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-generator</artifactId>
	<version>3.5.2</version>
</dependency>

<!--MySQL数据库-->
<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.40</version>
	<scope>runtime</scope>
</dependency>

<!--Druid数据源-->
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid-spring-boot-starter</artifactId>
	<version>1.2.8</version>
</dependency>

<!--lombok插件依赖-->
<dependency>
	<groupId>org.projectlombok</groupId>
	<artifactId>lombok</artifactId>
	<optional>true</optional>
</dependency>

使用mybatisplus代码生成器快速生成代码

  • 此处跳过(需要的小伙伴私聊我)

页面部分效果

  • 文章分页

在这里插入图片描述

  • 文章对应评论分页

在这里插入图片描述

代码实现

编写分页插件

@Configuration
public class MybatisPlusPageConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));  //添加分页插件
        return interceptor;
    }
}

编写thymeleaf分页模板

<!DOCTYPE html>
<!--
    th:fragment="page(pageInfo, prevText, nextText, prefix1,prefix2,prefix3)
        page:片段名称(类似方法名)
        pageInfo:分页数据的对象名称
        prefix1:父映射名称
        prefix2:子映射名称
        prefix3:评论对应文章的id(动态获取)
-->
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org" th:fragment="page(pageInfo,prefix1,prefix2,prefix3)">
<head>
    <meta charset="UTF-8">
    <title>分页模板</title>
    <link th:href="@{/bootstrap/css/bootstrap.min.css}" rel="stylesheet">
</head>
<style>
    .pagination {
        display: inline-block;
        padding-left: 0;
        margin: 20px 0;
        border-radius: 5px;
    }

    .pagination a {
        display: inline;
        border-radius: 3px;
    }
</style>
<body>
<nav>
    <ul class="pagination pagination-lg">

        <!--首页-->
        <th:block th:if="${pageInfo.pages>0}">
            <li>
                <a th:if="${pageInfo.current>1 && #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+1}" th:text="首页"></a>
                <a th:if="${pageInfo.current>1 && not #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+1}" th:text="首页"></a>
            </li>
        </th:block>

        <!--上一页-->
        <th:block th:if="${pageInfo.hasPrevious()}">
            <li>
                <a th:if="${pageInfo.current>1 && #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${(pageInfo.current)-1}}" th:text="上一页"
                   aria-label="Previous">
                </a>
                <a th:if="${pageInfo.current>1 && not #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${(pageInfo.current)-1}}"
                   th:text="上一页"
                   aria-label="Previous">
                </a>
            </li>
        </th:block>

        <!--页码数动态显示-->
        <th:block th:each="pageNum :${#numbers.sequence(1, pageInfo.pages)}">
            <th:block th:if="${pageInfo.pages>0 && pageInfo.pages<=5}">
                <li th:class="${pageInfo.current ==pageNum ? 'active':''}">
                    <a th:if="${#strings.isEmpty(prefix3)}" th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                    <a th:if="${not #strings.isEmpty(prefix3)}"
                       th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                </li>
            </th:block>

            <th:block th:if="${pageInfo.pages>5}">
                <li th:if="${pageInfo.current<=3 && pageNum<=5}"
                    th:class="${pageInfo.current ==pageNum ? 'active':''}">
                    <a th:if="${#strings.isEmpty(prefix3)}" th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                    <a th:if="${not #strings.isEmpty(prefix3)}"
                       th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                </li>

                <li th:if="${pageInfo.current>=(pageInfo.pages)-2 && pageNum>(pageInfo.pages)-5}"
                    th:class="${pageInfo.current ==pageNum ? 'active':''}">
                    <a th:if="${#strings.isEmpty(prefix3)}" th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                    <a th:if="${not #strings.isEmpty(prefix3)}"
                       th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                </li>

                <li th:if="${pageInfo.current>=4 && pageInfo.current<=(pageInfo.pages)-3 && pageNum>=(pageInfo.current)-2 && pageNum<=(pageInfo.current)+2}"
                    th:class="${pageInfo.current ==pageNum ? 'active':''}">
                    <a th:if="${#strings.isEmpty(prefix3)}" th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                    <a th:if="${not #strings.isEmpty(prefix3)}"
                       th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${pageNum}}"
                       th:text="${pageNum}">
                    </a>
                </li>
            </th:block>
        </th:block>

        <!--下一页-->
        <th:block th:if="${pageInfo.hasNext()}">
            <li>
                <a th:if="${pageInfo.current<pageInfo.pages && #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${(pageInfo.current)+1}}"
                   th:text="下一页" aria-label="Next">
                </a>
                <a th:if="${pageInfo.current<pageInfo.pages && not #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${(pageInfo.current)+1}}"
                   th:text="下一页" aria-label="Next">
                </a>
            </li>
        </th:block>

        <!--尾页-->
        <th:block th:if="${pageInfo.pages>0}">
            <li>
                <a th:if="${pageInfo.current < pageInfo.pages && #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${pageInfo.pages}}"
                   th:text="尾页">
                </a>
                <a th:if="${pageInfo.current < pageInfo.pages && not #strings.isEmpty(prefix3)}"
                   th:href="@{'/'+${prefix1}+'/'+${prefix2}+'/'+${prefix3}+'/'+${pageInfo.pages}}"
                   th:text="尾页">
                </a>
            </li>
        </th:block>
    </ul>
</nav>
</body>
</html>

文章分页

1. controller层代码

@Controller
@RequestMapping("/article")
public class ArticleController {
	@Autowired
    private ArticleService articleService;

	@RequestMapping("/page/{pageNum}")
    public String page(@PathVariable("pageNum") Integer pageNum, @RequestParam(defaultValue = "5") Integer pageSize, Model model) {
        Page<Article> articles = articleService.findPage(pageNum, pageSize);
        model.addAttribute("articles", articles);  
       
        return "client/index";        
    }
}

2. service接口层代码

public interface ArticleService extends IService<Article> {

    Page<Article> findPage(Integer pageNum, Integer pageSize);
}    

3. service实现类层代码

@Service
public class ArticleServiceImpl extends ServiceImpl<ArticleMapper, Article> implements ArticleService {

    @Autowired
    private ArticleMapper articleMapper;

    QueryWrapper<Article> wrapper = new QueryWrapper<>();

    @Override
    public Page<Article> findPage(Integer pageNum, Integer pageSize) {
        Page<Article> page = new Page<>(pageNum, pageSize);
        //按照文章发布时间降序
        wrapper.orderByDesc("created");
        return articleMapper.selectPage(page, wrapper);
    }
}

4. mapper层代码

@Mapper
public interface ArticleMapper extends BaseMapper<Article> {

}

5. 文章部分页面

<div class="am-u-md-8 am-u-sm-12">
        <!-- 文章信息展示 -->
        <div th:each="article: ${articles.records}">
            <article class="am-g blog-entry-article">
                <div class="am-u-lg-6 am-u-md-12 am-u-sm-12 blog-entry-img">
                    <!--文章图片-->
                    <!--
                        ${#numbers.formatInteger(final Number target, final Integer minIntegerDigits)
                            第一个参数:目标数值(结合随机数:[0,1)),四舍五入
                            第二个参数:最小的整数位数(不足会自动补0)
                    -->
                    <!--让每篇文章的图片可以在25张图片中随机显示-->
                    <img width="100%" class="am-u-sm-12"
                         th:src="@{'/client/img/rand/'+${#numbers.formatInteger(T(java.lang.Math).floor(T(java.lang.Math).random()*count)+1,1)}+'.png'}"/>
                </div>
                <div class="am-u-lg-6 am-u-md-12 am-u-sm-12 blog-entry-text">
                    <!-- 文章分类 -->
                    <span class="blog-color" style="font-size: 15px;" th:text="'所属分类 '+${article.categories}"/>
                    <span>&nbsp;&nbsp;&nbsp;</span>
                    <!-- 发布时间 -->
                    <span style="font-size: 15px;" th:text="'发布于 '+${#temporals.format(article.created,'yyyy-MM-dd')}"/>
                    <h2>
                        <div>
                            <!--文章标题(可以点击查询文章详情)-->
                            <a style="color: #0f9ae0;font-size: 20px;" th:text="${article.title}"
                               th:href="@{'/article/articleDetail/'+${article.id}}"/>
                        </div>
                    </h2>
                    <!-- 文章摘要(只显示100个字符)-->
                    <div style="font-size: 16px;" th:utext="${#strings.abbreviate(article.content,100)}"/>
                </div>
            </article>
        </div>

        <!--显示分页信息-->
        <div th:replace="commons/pagination::page(${articles},'article','page','')"></div>
    </div>

评论分页

1. controller层代码

@RequestMapping("/articleDetail/{articleId}/{pageNum}")
public String detail(@PathVariable("articleId") Integer articleId, @PathVariable("pageNum") Integer pageNum, @RequestParam(defaultValue = "3") Integer pageSize, Model model) {
        //根据文章id查询对应的评论
        Page<Comment> comments = commentService.findPageById(articleId, pageNum, pageSize);
        model.addAttribute("comments", comments);

        return "/client/articleDetail";
    }

2. service接口层代码

public interface CommentService extends IService<Comment> {

    Page<Comment> findPageById(Integer articleId, Integer pageNum, Integer pageSize);

}

3. service实现类层代码

@Service
public class CommentServiceImpl extends ServiceImpl<CommentMapper, Comment> implements CommentService {

    @Autowired
    private CommentMapper commentMapper;

    @Override
    public Page<Comment> findPageById(Integer articleId, Integer pageNum, Integer pageSize) {
        Page<Comment> page = new Page<>(pageNum, pageSize);
        QueryWrapper<Comment> wrapper = new QueryWrapper<>();
        //根据文章id(article_id)查询并且以created降序
        wrapper.eq("article_id", articleId);
        wrapper.orderByDesc("created");
        return commentMapper.selectPage(page, wrapper);
    }
}

4. mapper层代码

@Mapper
public interface CommentMapper extends BaseMapper<Comment> {

}

5. 评论部分页面

<!--文章存在-->
<div th:if="${article!=null}">
    <div class="comment-container">
        <div id="comments" class="clearfix">
            <!--文章允许评论-->
            <div th:if="${article.allowComment}">
                <div class="response">
                    <th:block>
                        请先<a th:href="@{/user/toLogin}" data-no-instant="">&nbsp;登录&nbsp;</a>后&nbsp;,发表评论或查看评论!
                    </th:block>
                </div>
                <div>
                    <form id="comment-form" class="comment-form" onsubmit="return publishComment()">
                        <input type="hidden" name="articleId" id="articleId" th:value="${article.id}">
                        <textarea name="content" id="textarea" class="form-control"
                                  placeholder="评论不能为空哦!"
                                  required="required" minlength="5" maxlength="2000"></textarea>
                        <button type="submit" class="submit" id="submit">评论</button>
                    </form>
                </div>
            </div>
            <!-- 显示评论内容 -->
            <div th:if="${comments!=null}">
                <ol class="comment-list">
                    <th:block th:each="comment: ${comments.records}">
                        <li class="comment-body comment-parent comment-odd">
                            <div class="comment-view">
                                <div class="comment-header">
                                    <!--人物头像和名称-->
                                    <img class="avatar" th:src="@{/assets/img/avatars.jpg}" height="50"/>
                                    <span class="comment-author" rel="external nofollow"
                                          th:text="${comment.author}"></span>
                                    <!-- 评论日期 -->
                                    <span class="comment-time"
                                          th:text="${#temporals.format(comment.created,'yyyy-MM-dd')}"></span>
                                </div>
                                <!-- 评论内容 -->
                                <div class="comment-content">
                                        <span class="comment-author-at"
                                              th:utext="${#strings.abbreviate(comment.comment,50)}"></span>
                                </div>
                            </div>
                        </li>
                    </th:block>
                </ol>
                <!-- 评论分页显示 -->
                <div th:replace="commons/pagination::page(${comments},'article','articleDetail',${article.id})"></div>
            </div>
        </div>
    </div>
</div>

总结

thymeleaf模板是本次的重点核心

  • 使用的mybatisplus框架+bootstrap样式
  • 自定义片段函数(pageInfo实际上就是mybatisplus中的Page对象)
  • 在每个block代码块中有两个a标签(文章分页和文章对应的评论分页)
  • 感谢你的阅读,希望对你有所帮助
  • 后面会不断的发表心的文章
  • 有什么好的建议可以在评论区一起讨论
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值