文章分页和搜索

master
barney 2 years ago
parent 2e5b012cac
commit 55667fe45c
  1. 2
      .gitignore
  2. 31
      src/main/java/cc/bnblogs/common/ArticleSearch.java
  3. 23
      src/main/java/cc/bnblogs/common/PageHelper.java
  4. 16
      src/main/java/cc/bnblogs/controller/ArticleController.java
  5. 3
      src/main/java/cc/bnblogs/mapper/ArticleMapper.java
  6. 63
      src/main/java/cc/bnblogs/service/ArticleService.java
  7. 69
      src/main/resources/templates/admin/article.html
  8. 2
      src/main/resources/templates/admin/index.html

2
.gitignore vendored

@ -2,6 +2,8 @@
target/
# 忽略上传图片的文件夹
upload/
# 忽略日志文件夹
logs/
# Compiled class file
*.class

@ -0,0 +1,31 @@
package cc.bnblogs.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class ArticleSearch {
// 4种查询条件和两个分页参数
//分类id
private Integer cid;
//状态
private Integer status;
//标题
private String title;
//文章类型
private Integer type;
//页码
private Integer pageNum;
//页大小
private Integer pageSize;
}

@ -0,0 +1,23 @@
package cc.bnblogs.common;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/19
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PageHelper<T> {
// 数据列表
private List<T> rows;
// 总记录数
private Long total;
}

@ -1,5 +1,7 @@
package cc.bnblogs.controller;
import cc.bnblogs.common.ArticleSearch;
import cc.bnblogs.common.PageHelper;
import cc.bnblogs.common.Result;
import cc.bnblogs.enums.ResultEnum;
import cc.bnblogs.pojo.Article;
@ -68,4 +70,18 @@ public class ArticleController {
articleService.delete(id);
return Result.success();
}
/**
* 根据搜索条件返回搜索到的文章列表
* @param search 搜索参数
* @return 搜索到的文章列表
*/
@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 = articleService.search(search);
return Result.success(pageHelper);
}
}

@ -2,10 +2,11 @@ package cc.bnblogs.mapper;
import cc.bnblogs.pojo.Article;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
/**
* @author zfp@bnblogs.cc
* @createTime: 2022/10/17
*/
public interface ArticleMapper extends JpaRepository<Article,Integer> {
public interface ArticleMapper extends JpaRepository<Article,Integer>, JpaSpecificationExecutor<Article>{
}

@ -1,11 +1,24 @@
package cc.bnblogs.service;
import cc.bnblogs.common.ArticleSearch;
import cc.bnblogs.common.PageHelper;
import cc.bnblogs.mapper.ArticleMapper;
import cc.bnblogs.mapper.TagMapper;
import cc.bnblogs.pojo.Article;
import cc.bnblogs.pojo.Category;
import cc.bnblogs.utils.UpdateUtil;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.thymeleaf.util.StringUtils;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
@ -18,7 +31,6 @@ import java.util.stream.Collectors;
@Service
public class ArticleService {
private final TagMapper tagMapper;
private final ArticleMapper articleMapper;
public ArticleService(ArticleMapper articleMapper, TagMapper tagMapper) {
@ -72,18 +84,25 @@ public class ArticleService {
if (Objects.isNull(article.getAllowComment())) {
article.setAllowComment(Article.COMMENT_DISABLE);
}
// 如果文章是新建的,设置创建时间;设置访问量为0
if (Objects.isNull(article.getCreated())) {
article.setCreated(new Date());
article.setViews(0);
}
// 将数据库中不存在的标签插入数据库中
article.setTags(article.getTags().stream().peek(x -> {
if (Objects.isNull(x.getId())) {
x.setId(tagMapper.save(x).getId());
}
}).collect(Collectors.toList()));
articleMapper.save(article);
// 如果该文章不存在则创建它,设置创建时间;设置访问量为0
if (Objects.isNull(article.getId())) {
article.setCreated(new Date());
article.setViews(0);
articleMapper.save(article);
} else {
// 读取该文章,修改其中的非空属性
Article one = detail(article.getId());
UpdateUtil.copyNullProperties(article, one);
articleMapper.save(one);
}
}
/**
@ -93,4 +112,34 @@ public class ArticleService {
public void delete(Integer id) {
articleMapper.deleteById(id);
}
/**
* 多条件分页查询
* @param search 分页参数
* @return 分页对象
*/
public PageHelper<Article> search(ArticleSearch search) {
// 构建分页参数
// 按照创建时间的降序返回结果
Pageable pageable = PageRequest.of(search.getPageNum() - 1, search.getPageSize(), Sort.by(Sort.Direction.DESC,"created"));
Page<Article> articlePage = articleMapper.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();
}
}

@ -12,17 +12,18 @@
<div class="btn-group" role="group" style="margin-bottom: 20px;" aria-label="...">
<a th:href="@{/admin/write.html}" class="btn btn-success"><i class="fa fa-plus"></i> 新增</a>
</div>
<form class="form-inline" style="float:right;">
<form id="search-form" class="form-inline" style="float:right;">
<div class="form-group">
<label>分类</label>
<select class="form-control" style="width: 100px;">
<select id="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 class="form-control" style="width: 100px;">
<select id="article-status" class="form-control" style="width: 100px;">
<option value="">全部</option>
<option value="1">发布</option>
<option value="2">草稿</option>
@ -30,7 +31,7 @@
</div>
<div class="form-group">
<label>类型</label>
<select class="form-control" style="width: 100px;">
<select id="article-types" class="form-control" style="width: 100px;">
<option value="">全部</option>
<option value="1">文章</option>
<option value="2">页面</option>
@ -38,8 +39,9 @@
</div>
<div class="form-group">
<label>关键字</label>
<input type="text" class="form-control" placeholder="请输入关键字...">
<input id="article-keywords" type="text" class="form-control" placeholder="请输入关键字...">
</div>
<button type="reset" class="btn btn-default" id="reset-btn"><i class="fa fa-refresh"></i> 重置</button>
<button type="submit" class="btn btn-primary"><i class="fa fa-search"></i> 搜索</button>
</form>
<table id="data-table" style="user-select: none"></table>
@ -49,8 +51,29 @@
<script>
$(function () {
// 显示表单所有文章数据
// 引入分页和搜索功能
$('#data-table').bootstrapTable({
url: "/admin/article/",
url: "/admin/article/search",
pagination: true, // 开启分页
sidePagination: 'server', // 使用服务端数据
pageNumber: 1, // 默认页码第一页
pageSize: 5, // 每页5条数据
pageList: [5, 10, 15], // 可选页大小
responseHandler: function (res) {
return res.data
},
//这个是查询参数,就是bootstrap-table请求后端时携带的参数
// offset为数据的序号,limit为页大小
queryParams: function (params) {
return {
pageNum: (params.offset / params.limit) + 1,
pageSize: params.limit,
title: $('#article-keywords').val(),
type: $('#article-types').val(),
status: $('#article-status').val(),
cid: $('#article-category').val(),
}
},
columns: [
{
title: '序号',
@ -75,7 +98,7 @@
formatter: value => {
if (value === 1) {
return `<span>已发布</span>`
}else {
} else {
return `<span>草稿</span>`
}
}
@ -86,7 +109,7 @@
field: 'category',
align: 'center',
formatter: value => {
return value.name;
return `<a href="javascript:void(0)" data-id="${value.id}" id="selected-category">${value.name}</a>`;
}
},
{
@ -105,15 +128,19 @@
align: 'center',
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>`
return `<button type="button" data-id="${value}" class="btn btn-danger btn-sm article-delete-btn"><i class="fa fa-trash"></i> 删除</button>`
}
},
],
responseHandler: function (res) {
return res.data
}
]
})
// 点击搜索按钮,阻止表单自动提交
$('#search-form').on('submit', function () {
$('#data-table').bootstrapTable('refresh', {silent: true, pageNumber: 1, pageSize: 5});
return false;
})
// 删除文章
$("#data-table").on("click", ".article-delete-btn", function () {
let id = $(this).data('id')
@ -126,18 +153,24 @@
dataType: 'json',
success: res => {
if (res.code === 200) {
layer.msg("删除成功", { icon: 1, time: 700 })
$('#data-table').bootstrapTable('refresh', { silent: true })
layer.msg("删除成功", {icon: 1, time: 700})
$('#data-table').bootstrapTable('refresh', {silent: true})
} else {
layer.msg(res.message, { icon: 2 })
layer.msg(res.message, {icon: 2})
}
}
})
layer.close(idx); // 关闭提示框
})
}).on('click', '#selected-category', function () {
// 点击文章对分类展示该分类所有文章
let cid = $(this).data('id'); // 分类id
// 设置搜索条件为查询分类
$('#reset-btn').click();
$('#article-category').val(cid);
// 重载查询数据
$('#data-table').bootstrapTable('refresh', {silent: true,pageNumber: 1, pageSize: 5});
})
})
</script>
</body>

@ -5,7 +5,7 @@
</head>
<body>
<th:block th:include="admin/common::nav('article')"></th:block>
<th:block th:include="admin/common::nav('index')"></th:block>
<div class="container lw-main">
<div class="jumbotron">

Loading…
Cancel
Save