增加删除文章恢复功能,增加部分常见问题解答
This commit is contained in:
parent
2a29da6e82
commit
cbbc633697
14
docs/Questions.md
Normal file
14
docs/Questions.md
Normal file
@ -0,0 +1,14 @@
|
||||
# 常见问题
|
||||
|
||||
## Elasticsearch相关
|
||||
|
||||
#### 1. none of the configured nodes are available
|
||||
|
||||
通常为es的配置问题,请检查配置文件中es相关的配置设置,是否和本地搭建的环境一致。
|
||||
```yaml
|
||||
# es
|
||||
# 可以通过es的config目录下的配置文件 elasticsearch.yml 获取自己集群配置的cluster-name
|
||||
spring.data.elasticsearch.cluster-name = docker-cluster
|
||||
# 服务器的ip、端口
|
||||
spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300
|
||||
```
|
@ -12,7 +12,11 @@ import com.greate.community.util.HostHolder;
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
@ -293,5 +297,31 @@ public class DiscussPostController implements CommunityConstant {
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
|
||||
@PostMapping("/recover")
|
||||
@ResponseBody
|
||||
@PreAuthorize(AUTHORITY_ADMIN)
|
||||
public String recover(int id){
|
||||
discussPostService.updateStatus(id,0);
|
||||
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_PUBLISH)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
return CommunityUtil.getJSONString(200,"恢复成功");
|
||||
}
|
||||
|
||||
|
||||
@RequestMapping("/onDelete")
|
||||
@PreAuthorize(AUTHORITY_ADMIN)
|
||||
public String onDelete(Model model,
|
||||
@RequestParam(value = "pageIndex", defaultValue = "0") int pageIndex,
|
||||
@RequestParam(value = "pageSize", defaultValue = "10")int size){
|
||||
Pageable page = PageRequest.of(pageIndex,size);
|
||||
PageImpl<DiscussPost> posts = discussPostService.onDelete(page);
|
||||
model.addAttribute("posts",posts);
|
||||
return "site/admin/onDelete";
|
||||
}
|
||||
}
|
||||
|
@ -22,10 +22,11 @@ public class ExceptionAdvice {
|
||||
|
||||
@ExceptionHandler({Exception.class})
|
||||
public void handleException(Exception e, HttpServletRequest request, HttpServletResponse response) throws IOException {
|
||||
logger.error("服务器发生异常:" + e.getMessage());
|
||||
for (StackTraceElement element : e.getStackTrace()) {
|
||||
logger.error(element.toString());
|
||||
}
|
||||
// logger.error("服务器发生异常:" + e.getMessage());
|
||||
logger.error(e.getMessage(), e);
|
||||
// for (StackTraceElement element : e.getStackTrace()) {
|
||||
// logger.error(element.toString());
|
||||
// }
|
||||
// 区分异步请求和普通请求
|
||||
String xRequestedWith = request.getHeader("x-requested-with");
|
||||
if ("XMLHttpRequest".equals(xRequestedWith)) {
|
||||
|
@ -74,4 +74,14 @@ public interface DiscussPostMapper {
|
||||
* @return
|
||||
*/
|
||||
int updateScore(int id, double score);
|
||||
|
||||
/**
|
||||
* 查询已经删除的帖子
|
||||
* @param offset
|
||||
* @param limit
|
||||
* @return
|
||||
*/
|
||||
List<DiscussPost> selectDiscussPostByStatus(long offset, int limit);
|
||||
|
||||
int countDiscussPostByStatus();
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||
import com.greate.community.dao.DiscussPostMapper;
|
||||
import com.greate.community.entity.DiscussPost;
|
||||
import com.greate.community.entity.Page;
|
||||
import com.greate.community.util.SensitiveFilter;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
@ -12,6 +13,8 @@ import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.util.HtmlUtils;
|
||||
|
||||
@ -201,4 +204,15 @@ public class DiscussPostService {
|
||||
return discussPostMapper.updateScore(id, score);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询已经删除的帖子
|
||||
* @param page
|
||||
* @return
|
||||
*/
|
||||
public PageImpl<DiscussPost> onDelete(Pageable page) {
|
||||
List<DiscussPost> discussPosts = discussPostMapper.selectDiscussPostByStatus(page.getOffset(),page.getPageSize());
|
||||
long total = discussPostMapper.countDiscussPostByStatus();
|
||||
return new PageImpl(discussPosts, page, total);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -53,6 +53,19 @@
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<!-- 根据 状态 查询帖子 -->
|
||||
<select id="selectDiscussPostByStatus" resultType="com.greate.community.entity.DiscussPost">
|
||||
select * from discuss_post where status = 2
|
||||
limit #{offset},#{limit}
|
||||
</select>
|
||||
|
||||
<!-- 根据 状态 查询帖子总数 -->
|
||||
<select id="countDiscussPostByStatus" resultType="java.lang.Integer">
|
||||
select count(id)
|
||||
from discuss_post
|
||||
where status = 2
|
||||
</select>
|
||||
|
||||
<update id="updateCommentCount">
|
||||
update discuss_post
|
||||
set comment_count = #{commentCount}
|
||||
|
@ -2,6 +2,7 @@ $(function(){
|
||||
$("#topBtn").click(updateTop);
|
||||
$("#wonderfulBtn").click(setWonderful);
|
||||
$("#deleteBtn").click(setDelete);
|
||||
$("#recoverBtn").click(recover);
|
||||
});
|
||||
|
||||
// 点赞
|
||||
@ -79,4 +80,21 @@ function setDelete() {
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function recover() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/recover",
|
||||
{"id":$("#postId").val()},
|
||||
function (data) {
|
||||
data = $.parseJSON(data);
|
||||
if (data.code == 200) {
|
||||
// 删除成功后,跳转到首页
|
||||
location.href = CONTEXT_PATH + "/index";
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -48,6 +48,7 @@
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item text-center" th:href="@{|/user/profile/${loginUser.id}|}"><i class="bi bi-person-fill"></i> 个人主页</a>
|
||||
<a class="dropdown-item text-center" th:href="@{/user/setting}"><i class="bi bi-gear"></i> 账号设置</a>
|
||||
<a class="dropdown-item text-center" th:href="@{/discuss/onDelete}" sec:authorize="hasAnyAuthority('admin')"><i class="bi bi-bag-x"></i> 文章恢复</a>
|
||||
<a class="dropdown-item text-center" th:href="@{/data}" sec:authorize="hasAnyAuthority('admin')"><i class="bi bi-clipboard-data"></i> 数据统计</a>
|
||||
<a class="dropdown-item text-center" th:href="@{/logout}"><i class="bi bi-box-arrow-right"></i> 退出登录</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
|
102
src/main/resources/templates/site/admin/onDelete.html
Normal file
102
src/main/resources/templates/site/admin/onDelete.html
Normal file
@ -0,0 +1,102 @@
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<link rel="icon" type="shortcut icon" th:href="@{/img/favicon.ico}" />
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/bootstrap.min.css}" />
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/css/global.css}" />
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.3.0/font/bootstrap-icons.css">
|
||||
<title>Echo - 文章管理</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="nk-container">
|
||||
<!-- 头部 -->
|
||||
<header class="bg-dark sticky-top" th:replace="index::header"></header>
|
||||
|
||||
<!-- 内容 -->
|
||||
<div class="main">
|
||||
<div class="container">
|
||||
<div class="position-relative">
|
||||
<!-- 筛选条件 -->
|
||||
<!-- <ul class="nav nav-tabs mb-3">-->
|
||||
<!-- <li class="nav-item">-->
|
||||
<!-- <a th:class="|nav-link ${orderMode==0 ? 'active' : ''}|" th:href="@{/index(orderMode=0)}"><i class="bi bi-lightning"></i> 最新</a>-->
|
||||
<!-- </li>-->
|
||||
<!-- <li class="nav-item">-->
|
||||
<!-- <a th:class="|nav-link ${orderMode==1 ? 'active' : ''}|" th:href="@{/index(orderMode=1)}"><i class="bi bi-hand-thumbs-up"></i> 最热</a>-->
|
||||
<!-- </li>-->
|
||||
<!-- </ul>-->
|
||||
<!-- 提示框 -->
|
||||
<div class="modal fade" id="hintModal" tabindex="-1" role="dialog" aria-labelledby="hintModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="hintModalLabel">提示</h5>
|
||||
</div>
|
||||
<div class="modal-body" id="hintBody"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 帖子列表 -->
|
||||
<ul class="list-unstyled">
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom" th:each="map:${posts.getContent()}">
|
||||
<a th:href="@{|/user/profile/${map.userId}|}">
|
||||
<!-- <img th:src="${}" class="mr-4 rounded-circle" alt="用户头像" style="width:50px;height:50px;">-->
|
||||
</a>
|
||||
<div class="media-body">
|
||||
<h6 class="mt-0 mb-3">
|
||||
<a th:href="@{|/discuss/detail/${map.id}|}" th:utext="${map.title}"></a>
|
||||
<span class="badge badge-secondary bg-danger" th:if="${map.type==1}"
|
||||
style="font-weight: 500; color: #f85959; background-color: rgba(248,89,89,0.1) !important;">顶</span>
|
||||
<span class="badge badge-secondary bg-primary" th:if="${map.status==1}"
|
||||
style="font-weight: 500; color: #3c8cff; background-color: rgba(60,140,255,0.1) !important;">精</span>
|
||||
</h6>
|
||||
<div class="text-muted font-size-12">
|
||||
<u class="mr-3" th:utext="xxx"></u> 发布于 <b th:text="${#dates.format(map.createTime,'yyyy-MM-dd HH:mm:ss')}"></b>
|
||||
<ul class="d-inline float-right">
|
||||
<!-- <li class="d-inline ml-2">赞 <span th:text="${map.likeCount}"></span></li>-->
|
||||
<!-- <li class="d-inline ml-2">|</li>-->
|
||||
<!-- <li class="d-inline ml-2">回帖 <span th:text="${map.post.commentCount}"></span></li>-->
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<!--分页 -->
|
||||
<nav class="mt-5" th:if = "${posts.getTotalPages()>0}" th:fragment="pagination">
|
||||
<ul class="pagination justify-content-center">
|
||||
<li class="page-item">
|
||||
<a class="page-link" th:href="@{/discuss/onDelete}">首页</a>
|
||||
</li>
|
||||
<li th:class="|page-item ${posts.hasPrevious() ? '' : 'disabled'}|">
|
||||
<a class="page-link" th:href="@{/discuss/onDelete(pageIndex=${posts.getNumber() - 1})}">上一页</a>
|
||||
</li>
|
||||
<!--numbers.sequence 生成一个 page.from 到 page.to 的连续整数数组-->
|
||||
<li th:each="i:${#numbers.sequence((posts.getTotalPages() < 5 ? 1 : (posts.getTotalPages() - 5)), posts.getTotalPages())}" th:class="|page-item ${(i - 1) ==posts.number ? 'active' : ''}|" >
|
||||
<a class="page-link" th:href="@{/discuss/onDelete(pageIndex=${i - 1})}" th:text="${i}"></a>
|
||||
</li>
|
||||
<li th:class="|page-item ${posts.hasNext() ? '':'disabled'}|">
|
||||
<a class="page-link" th:href="@{/discuss/onDelete(pageIndex=${posts.getNumber() + 1})}">下一页</a>
|
||||
</li>
|
||||
<li class="page-item">
|
||||
<a class="page-link" th:href="@{/discuss/onDelete(pageIndex=${posts.getTotalPages() - 1})}">末页</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- 尾部 -->
|
||||
<footer class="bg-dark" th:replace="index::footer"></footer>
|
||||
|
||||
</div>
|
||||
|
||||
<script th:src="@{/js/jquery-3.1.0.min.js}"></script>
|
||||
<script th:src="@{/js/popper.min.js}"></script>
|
||||
<script th:src="@{/js/bootstrap.min.js}"></script>
|
||||
<script th:src="@{/js/global.js}"></script>
|
||||
</body>
|
||||
</html>
|
@ -36,7 +36,9 @@
|
||||
<button type="button" class="btn btn-danger btn-sm" id="wonderfulBtn"
|
||||
th:disabled="${post.status == 1}" sec:authorize="hasAnyAuthority('moderator')">加精</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" id="deleteBtn"
|
||||
th:disabled="${post.status == 2}" sec:authorize="hasAnyAuthority('admin')">删除</button>
|
||||
th:if="${post.status != 2}" sec:authorize="hasAnyAuthority('admin')">删除</button>
|
||||
<button type="button" class="btn btn-success btn-sm" id="recoverBtn"
|
||||
th:if="${post.status == 2}" sec:authorize="hasAnyAuthority('admin')">恢复</button>
|
||||
</div>
|
||||
</h5>
|
||||
<!-- 作者 -->
|
||||
|
Loading…
x
Reference in New Issue
Block a user