(十)文章管理的多条件分页查询
说明
至此,我们已经将文章的新增及修改功能完成了,删除功能也由代码生成器给我们生成了,所以我们只剩下多条件分页查询功能了
上节遗留问题
- 我们上节课保存文章的时候有个问题就是我们查询对象使用了
getOne
方法,这个getOne
方法是一个延迟查询,它不会立即查询数据库,只有当我们用到属性时才会进行查询, 查数据库看到我们的created
及views
字段还是null
,所以我们应该用findById
的方法查询对象再进行非空拷贝
Article one = detail(article.getId());
UpdateUtil.copyNullProperties(article, one);
mapper.save(one);
- 还有就是一个小细节我们忘了设置图片在
input
中的回显
<input type="hidden" th:value="${article.cover}" name="cover" class="form-control">
服务端分页查询
定义条件查询参数
- 类名:ArticleSearch
属性 | 类型 | 备注 |
---|---|---|
cid | 整数 | 分类id |
status | 整数 | 状态 |
title | 字符串 | 标题关键字 |
type | 整数 | 文章类型 |
pageNum | 整数 | 页码 |
pageSize | 整数 | 页大小 |
package cn.kevinlu98.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* Author: Mr丶冷文
* Date: 2022/10/9 21:13
* Email: kevinlu98@qq.com
* Description:
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ArticleSearch {
//分类id
private Integer cid;
//状态
private Integer status;
//标题
private String title;
//文章类型
private Integer type;
//页码
private Integer pageNum;
//页大小
private Integer pageSize;
}
定义分页返回对象
- 类名:PageHelper
属性 | 类型 | 备注 |
---|---|---|
rows | 数组 | 数据列表 |
total | 整数 | 总记录数 |
package cn.kevinlu98.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* Author: Mr丶冷文
* Date: 2022/10/9 21:15
* Email: kevinlu98@qq.com
* Description:
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PageHelper<T> {
// 数据列表
private List<T> rows;
// 总记录数
private Long total;
}
Controller层逻辑
- 定义
search
接口 - 修改错误或未填写的
pageNum
及pageSize
- 调用
service
层的搜索接口 - 返回数据
@GetMapping("/search")
public Result<PageHelper<Article>> search(ArticleSearch search) {
search.setPageNum(Objects.isNull(search.getPageNum()) || search.getPageNum() < 1 ? 1 : search.getPageNum());
search.setPageSize(Objects.isNull(search.getPageSize()) || search.getPageSize() < 1 ? 1 : search.getPageSize());
PageHelper<Article> pageHelper = service.search(search);
return Result.success(pageHelper);
}
Service及Mapper的逻辑
- 构建
Pageable
对象添加分页信息及排序信息 - 让
Mapper
去继承JpaSpecificationExecutor
复杂查询的查询使其具有复杂查询的功能
public interface ArticleMapper extends JpaRepository<Article, Integer>, JpaSpecificationExecutor<Article> {
}
- 调用
findAll
方法传一个匿名内部类Specification
的子类并重载toPredicate
方法 - 在
toPredicate
方法中创建predicateList
条件数组来保存所有条件 - 构建条件对象并加到
predicateList
数组中 - 用
and
的方法拼接条件并返回 - 构建出
PageHelper
对象
public PageHelper<Article> search(ArticleSearch search) {
//构建分页参数
Pageable pageable = PageRequest.of(search.getPageNum() - 1, search.getPageSize(), Sort.by(Sort.Direction.DESC, "created"));
Page<Article> articlePage = mapper.findAll((Specification<Article>) (root, query, builder) -> {
List<Predicate> predicateList = new ArrayList<>();
if (Objects.nonNull(search.getCid())) {
predicateList.add(builder.equal(root.get("category"), Category.builder().id(search.getCid()).build()));
}
if (Objects.nonNull(search.getStatus())) {
predicateList.add(builder.equal(root.get("status"), search.getStatus()));
}
if (Objects.nonNull(search.getType())) {
predicateList.add(builder.equal(root.get("type"), search.getType()));
}
if (!StringUtils.isEmptyOrWhitespace(search.getTitle())) {
predicateList.add(builder.like(root.get("title"), "%" + search.getTitle() + "%"));
}
return builder.and(predicateList.toArray(new Predicate[predicateList.size()]));
}, pageable);
return PageHelper.<Article>builder().rows(articlePage.getContent()).total(articlePage.getTotalElements()).build();
}
BSTable的分页
我们可以通过设置如下属性来实现分页功能 https://bootstrap-table.com/docs/api/table-options/#sidepagination
$('#table').bootstrapTable({
pageNumber: 1, //指定默认页码
pagination: true, //开启分页
sidePagination: 'server', //使用服务端分页
pageSize: 10,//默认页大小
pageList: [10, 20, 30], //可选页大小
//bootstrap-table的分页数据是一个json,rows保存数据列表,total保存数据总数
responseHandler: function (res) {
return {
rows: res.data.rows,
total: res.data.total
}
},
//这个是查询参数,就是bootstrap-table请求后端时携带的参数
queryParams: function (params) {
return {
pageNum: (params.offset / params.limit) + 1,
pageSize: params.limit,
}
})
- 为搜索栏加上id
<form id="lw-search-form" class="form-inline" style="float:right;">
<div class="form-group">
<label>分类</label>
<select id="lw-article-category" class="form-control" style="width: 100px;">
<option value="">全部</option>
<option th:each="category:${categories}" th:value="${category.id}" th:text="${category.name}"></option>
</select>
</div>
<div class="form-group">
<label>状态</label>
<select id="lw-article-status" class="form-control" style="width: 100px;">
<option value="">全部</option>
<option value="1">发布</option>
<option value="2">草稿</option>
</select>
</div>
<div class="form-group">
<label>类型</label>
<select id="lw-article-type" class="form-control" style="width: 100px;">
<option value="">全部</option>
<option value="1">文章</option>
<option value="2">页面</option>
</select>
</div>
<div class="form-group">
<label>关键字</label>
<input type="text" id="lw-keywords" class="form-control" placeholder="请输入关键字...">
</div>
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
</form>
- 修改bootstraptable的配置使其可以分页
$('#data-table').bootstrapTable({
url: '/admin/article/search',
pagination: true,
pageNumber: 1,
sidePagination: 'server',
pageSize: 10,
pageList: [10, 20, 40],
responseHandler: function (res) {
return res.data
},
queryParams: function (params) {
return {
pageNum: (params.offset / params.limit) + 1,
pageSize: params.limit,
title: $('#lw-keywords').val(),
type: $('#lw-article-type').val(),
status: $('#lw-article-status').val(),
cid: $('#lw-article-category').val()
}
},
columns: [
{
title: '序号',
width: 50,
align: 'center',
formatter: function (value, row, index) {
return index + 1
}
},
{
title: '标题',
field: 'title',
formatter: function (value, row) {
return `<a href="/admin/write.html?id=${row.id}">${value}</a>`
}
},
{
title: '状态',
field: 'status',
formatter: function (value) {
return value === 1 ? '发布' : '草稿'
}
},
{
title: '分类',
field: 'category',
formatter: function (value) {
return value.name
}
},
{
title: '浏览量',
field: 'views'
},
{
title: '创建时间',
field: 'created'
},
{
field: 'id',
title: '操作',
width: 100,
formatter: function (value) {
return `<button type="button" data-id="${value}" class="btn btn-danger btn-sm lw-del-btn"><i class="fa fa-trash"></i> 删除</button>`
}
},
]
})
- 阻止搜索表单提交,在其提交时重载表格
$('#lw-search-form').on('submit', function () {
$('#data-table').bootstrapTable('refresh', {silent: true, pageNumber: 1});
return false;
})
点击文章列表的分类实现展示该分类下的文章
- 修改分类的展示样式
{
title: '分类',
field: 'category',
formatter: function (value) {
return `<a class="lw-category-table" href="javascript:void(0)" data-id="${value.id}">${value.name}</a>`
}
}
- 点击文章分类时将表单的值置为空
- 将分类的选择框的值置为点击的值
- 重载表格
$("#data-table").on('click', '.lw-category-table', function () {
let cid = $(this).data('id')
$('#lw-reset').click()
$('#lw-article-category').val(cid)
$('#data-table').bootstrapTable('refresh', {silent: true, pageNumber: 1});
})
看看
多谢大佬分享
强强强
感谢作者!
感谢!