Complete web data statistics function and top posts ranking function
This commit is contained in:
parent
db263d3925
commit
408385002d
99
README.md
99
README.md
@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 🎁 从本项目你能学到什么
|
||||
## 📚 从本项目你能学到什么
|
||||
|
||||
- 学会主流的 Java Web 开发技术和框架
|
||||
- 积累一个真实的 Web 项目开发经验
|
||||
@ -10,19 +10,21 @@
|
||||
|
||||
## 💻 核心技术栈
|
||||
|
||||
后端:
|
||||
后端:
|
||||
|
||||
- Spring
|
||||
- Spring Boot 2.1.5 RELEASE
|
||||
- Spring MVC
|
||||
- ORM:MyBatis
|
||||
- 数据库:MySQL 5.7
|
||||
- 日志:SLF4J(日志接口) + Logback(日志实现)
|
||||
- 缓存:Redis
|
||||
- 消息队列:Kafka 2.13-2.7.0
|
||||
- 搜索引擎:Elasticsearch 6.4.3
|
||||
- 安全:Spring Security
|
||||
- 邮件:Spring Mail
|
||||
- 分布式定时任务:Spring Quartz
|
||||
- 监控:Spring Actuator
|
||||
- 日志:SLF4J(日志接口) + Logback(日志实现)
|
||||
|
||||
前端:
|
||||
|
||||
@ -33,19 +35,23 @@
|
||||
|
||||
## 🔨 开发环境
|
||||
|
||||
- 操作系统:Windows 10
|
||||
- 构建工具:Apache Maven
|
||||
- 集成开发工具:Intellij IDEA
|
||||
- 数据库:MySQL 5.7、Redis
|
||||
- 数据库:MySQL 5.7
|
||||
- 应用服务器:Apache Tomcat
|
||||
- 接口测试工具:Postman
|
||||
- 版本控制工具:Git
|
||||
|
||||
## 🔔 功能列表
|
||||
## 🎨 功能列表
|
||||
|
||||
- [x] **注册**(MySQL)
|
||||
|
||||
- [x] 注册(MySQL)
|
||||
- 用户注册成功,将用户信息存入 MySQL,但此时该用户状态为未激活
|
||||
- 向用户发送激活邮件,用户点击链接则激活账号
|
||||
- 向用户发送激活邮件,用户点击链接则激活账号(Spring Mail)
|
||||
|
||||
- [x] **登录 | 登出**(MySQL、Redis)
|
||||
|
||||
- [x] 登录 | 登出(MySQL、Redis)
|
||||
- 进入登录界面,动态生成验证码,并将验证码短暂存入 Redis(60 秒)
|
||||
|
||||
- 用户登录成功(验证用户名、密码、验证码),生成登录凭证且设置状态为有效,并将登录凭证存入 Redis
|
||||
@ -58,23 +64,34 @@
|
||||
|
||||
- 用户登出,将凭证状态设为无效,并更新 Redis 中该用户的登录凭证信息
|
||||
|
||||
- [x] 账号设置(MySQL)
|
||||
- [x] **账号设置**(MySQL)
|
||||
|
||||
- 修改头像
|
||||
- 修改密码
|
||||
|
||||
- [x] 检查登录状态(禁止未登录用户访问需要登录权限的界面,后续会使用 Spring Security 接管)
|
||||
- [x] **帖子模块**(MySQL)
|
||||
|
||||
- [x] 帖子模块(MySQL)
|
||||
- 发布帖子(过滤敏感词),将其存入 MySQL
|
||||
- 分页显示所有的帖子
|
||||
- 支持按照 “发帖时间” 显示
|
||||
- 支持按照 “热度排行” 显示(Spring Quartz)
|
||||
- 查看帖子详情
|
||||
- 权限管理(Spring Security + Thymeleaf Security)
|
||||
- 未登录用户无法发帖
|
||||
- “版主” 可以看到帖子的置顶和加精按钮并执行相应操作
|
||||
- “管理员” 可以看到帖子的删除按钮并执行相应操作
|
||||
- “普通用户” 无法看到帖子的置顶、加精、删除按钮,也无法执行相应操作
|
||||
|
||||
- [x] **评论模块**(MySQL)
|
||||
|
||||
- [x] 评论模块(MySQL)
|
||||
- 发布对帖子的评论(过滤敏感词),将其存入 MySQL
|
||||
- 分页显示评论
|
||||
- 发布对评论的回复(过滤敏感词)
|
||||
- 权限管理(Spring Security)
|
||||
- 未登录用户无法使用评论功能
|
||||
|
||||
- [x] **私信模块**(MySQL)
|
||||
|
||||
- [x] 私信模块(MySQL)
|
||||
- 发送私信(过滤敏感词)
|
||||
- 私信列表
|
||||
- 查询当前用户的会话列表
|
||||
@ -84,26 +101,34 @@
|
||||
- 查询某个会话所包含的所有私信
|
||||
- 访问私信详情时,将显示的私信设为已读状态
|
||||
- 支持分页显示
|
||||
- 权限管理(Spring Security)
|
||||
- 未登录用户无法使用私信功能
|
||||
|
||||
- [x] **统一处理异常**(404、500)
|
||||
|
||||
- [x] 统一处理异常(404、500)
|
||||
- 普通请求异常
|
||||
- 异步请求异常
|
||||
|
||||
- [x] 统一记录日志
|
||||
- [x] **统一记录日志**
|
||||
|
||||
- [x] **点赞模块**(Redis)
|
||||
|
||||
- [x] 点赞模块(Redis)
|
||||
- 点赞
|
||||
- 获赞
|
||||
- 权限管理(Spring Security)
|
||||
- 未登录用户无法使用点赞相关功能
|
||||
|
||||
- [x] 关注模块(Redis)
|
||||
- [x] **关注模块**(Redis)
|
||||
|
||||
- 关注功能
|
||||
- 取消关注功能
|
||||
- 统计用户的关注数和粉丝数
|
||||
- 关注列表(查询某个用户关注的人),支持分页
|
||||
- 粉丝列表(查询某个用户的粉丝),支持分页
|
||||
- 权限管理(Spring Security)
|
||||
- 未登录用户无法使用关注相关功能
|
||||
|
||||
- [x] 系统通知模块(Kafka)
|
||||
- [x] **系统通知模块**(Kafka)
|
||||
|
||||
- 通知列表
|
||||
- 显示评论、点赞、关注三种类型的通知
|
||||
@ -113,10 +138,11 @@
|
||||
- 未读数量
|
||||
- 分别显示每种类型的系统通知的未读数量
|
||||
- 显示所有系统通知的未读数量
|
||||
- 导航栏显示所有消息的未读数量(未读私信 + 未读系统通知)
|
||||
- 权限管理(Spring Security)
|
||||
- 未登录用户无法使用系统通知功能
|
||||
|
||||
- 导航栏显示所有消息的未读数量(未读私信 + 未读系统通知)
|
||||
|
||||
- [x] 搜索模块(Elasticsearch + Kafka)
|
||||
- [x] **搜索模块**(Elasticsearch + Kafka)
|
||||
|
||||
- 发布事件
|
||||
- 发布帖子时,通过消息队列将帖子异步地提交到 Elasticsearch 服务器
|
||||
@ -126,22 +152,31 @@
|
||||
- 从 Elasticsearch 服务器删除帖子(当帖子从数据库中被删除时)
|
||||
- 显示搜索结果
|
||||
|
||||
- [ ] 权限控制
|
||||
- [x] **网站数据统计**(管理员专属)
|
||||
|
||||
- [ ] 管理员模块
|
||||
- 置顶帖子
|
||||
- 加精帖子
|
||||
- 删除帖子
|
||||
|
||||
- [ ] 网站数据统计
|
||||
|
||||
- [ ] 热帖排行
|
||||
- 独立访客 UV
|
||||
- 存入 Redis 的 HyperLogLog
|
||||
- 支持单日查询和区间日期查询
|
||||
- 日活跃用户 DAU
|
||||
- 存入 Redis 的 Bitmap
|
||||
- 支持单日查询和区间日期查询
|
||||
- 权限管理(Spring Security)
|
||||
- 只有管理员可以查看网站数据统计
|
||||
|
||||
- [ ] 文件上传
|
||||
|
||||
- [ ] 优化网站性能
|
||||
|
||||
## 🎨 界面展示
|
||||
## 🔐 待实现及优化
|
||||
|
||||
- [ ] 修改用户名
|
||||
- [ ] 查询我的帖子
|
||||
- [ ] 查询我的评论
|
||||
- [ ] 查询我的点赞
|
||||
- [ ] 管理员对帖子的二次点击取消置顶功能
|
||||
- [ ] 管理员对已删除帖子的恢复功能
|
||||
|
||||
## 🎀 界面展示
|
||||
|
||||
## 📜 数据库设计
|
||||
|
||||
@ -205,7 +240,7 @@ CREATE TABLE `comment` (
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=247 DEFAULT CHARSET=utf8;
|
||||
```
|
||||
|
||||
登录凭证 `login_ticket`:
|
||||
登录凭证 `login_ticket`(废弃,使用 Redis 存储):
|
||||
|
||||
```sql
|
||||
DROP TABLE IF EXISTS `login_ticket`;
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
---
|
||||
|
||||
## 使用 Redis 存储验证码
|
||||
## 使用 Redis 短暂存储验证码
|
||||
|
||||
- 验证码需要频繁刷新,对性能要求较高
|
||||
- 验证码不需永久保存(设置在 Cookie 和 Redis 中的保留时间为 60 s)
|
||||
@ -107,7 +107,7 @@ public class RedisKeyUtil {
|
||||
}
|
||||
```
|
||||
|
||||
LoginTicket 这张表以及相关操作可以废弃了,不过我们最好不要直接就删除了。在 `LoginMapper` 类上面加上 `@Deprecated` 注解表示不推荐使用就好了。
|
||||
**LoginTicket 这张表以及相关操作可以废弃了**,不过我们最好不要直接就删除了。在 `LoginMapper` 类上面加上 `@Deprecated` 注解表示不推荐使用就好了。
|
||||
|
||||
修改 UserService 中生成/修改/查询登录凭证这三个方法
|
||||
|
||||
|
@ -84,9 +84,10 @@ public String getNoticeList(Model model) {
|
||||
|
||||
// 查询评论类通知
|
||||
Message message = messageService.findLatestNotice(user.getId(), TOPIC_COMMNET);
|
||||
// 封装通知需要用到的数据
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
// 封装通知需要的各种数据
|
||||
if (message != null) {
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
|
||||
messageVO.put("message", message);
|
||||
|
||||
String content = HtmlUtils.htmlUnescape(message.getContent());
|
||||
@ -102,8 +103,9 @@ public String getNoticeList(Model model) {
|
||||
|
||||
int unread = messageService.findNoticeUnReadCount(user.getId(), TOPIC_COMMNET);
|
||||
messageVO.put("unread", unread);
|
||||
|
||||
model.addAttribute("commentNotice", messageVO);
|
||||
}
|
||||
model.addAttribute("commentNotice", messageVO);
|
||||
|
||||
// 查询点赞类通知
|
||||
...........
|
||||
|
166
docs/260-权限控制.md
Normal file
166
docs/260-权限控制.md
Normal file
@ -0,0 +1,166 @@
|
||||
# Spring Security 权限控制
|
||||
|
||||
---
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130143717.png)
|
||||
|
||||
导入 依赖:
|
||||
|
||||
```xml
|
||||
<!--Spring Security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
## 授权配置
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130152216.png)
|
||||
|
||||
管理员能够访问的特殊路径后续再配
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
|
||||
|
||||
/**
|
||||
* 静态资源
|
||||
* @param web
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
// 认证环节我们使用自己的代码 LoginController,绕过 Spring Security 的
|
||||
|
||||
/**
|
||||
* 授权
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers(
|
||||
"/user/setting",
|
||||
"/user/upload",
|
||||
"/discuss/add",
|
||||
"/comment/add",
|
||||
"/letter/**",
|
||||
"/notice/**",
|
||||
"/like",
|
||||
"/follow",
|
||||
"/unfollow"
|
||||
)
|
||||
.hasAnyAuthority(
|
||||
AUTHORITY_USER,
|
||||
AUTHORITY_ADMIN,
|
||||
AUTHORITY_MODERATOR
|
||||
)
|
||||
.anyRequest().permitAll();
|
||||
|
||||
// 权限不够时的处理
|
||||
http.exceptionHandling()
|
||||
// 1. 未登录时的处理
|
||||
.authenticationEntryPoint(new AuthenticationEntryPoint() {
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
|
||||
String xRequestedWith = request.getHeader("x-requested-with");
|
||||
if ("XMLHttpRequest".equals(xRequestedWith)) {
|
||||
// 异步请求
|
||||
response.setContentType("application/plain;charset=utf-8");
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(CommunityUtil.getJSONString(403, "你还没有登录"));
|
||||
}
|
||||
else {
|
||||
// 普通请求
|
||||
response.sendRedirect(request.getContextPath() + "/login");
|
||||
}
|
||||
}
|
||||
})
|
||||
// 2. 权限不够时的处理
|
||||
.accessDeniedHandler(new AccessDeniedHandler() {
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
|
||||
String xRequestedWith = request.getHeader("x-requested-with");
|
||||
if ("XMLHttpRequest".equals(xRequestedWith)) {
|
||||
// 异步请求
|
||||
response.setContentType("application/plain;charset=utf-8");
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(CommunityUtil.getJSONString(403, "你没有访问该功能的权限"));
|
||||
}
|
||||
else {
|
||||
// 普通请求
|
||||
response.sendRedirect(request.getContextPath() + "/denied");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Security 底层会默认拦截 /logout 请求,进行退出处理
|
||||
// 此处赋予它一个根本不存在的退出路径,使得程序能够执行到我们自己编写的退出代码
|
||||
http.logout().logoutUrl("/securitylogout");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Security 底层会默认拦截 /logout 请求,进行退出处理。此处赋予它一个根本不存在的退出路径 /securitylogout(善意的谎言),使得程序能够执行到我们自己编写的退出代码
|
||||
|
||||
## 认证方案
|
||||
|
||||
认证环节我们之前已经写好了,就不用 Security 的了。即绕过 Spring Security 的认证流程,使用我们自己编写的代码。不在下面 Security 提供的认证方法中写:
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
super.configure(auth);
|
||||
}
|
||||
```
|
||||
|
||||
**既然我们需要自己做认证,也就是将认证的结果(用户、密码、权限)存入 SecurityContext**,便于 Security 的授权:
|
||||
|
||||
我们之前利用拦截器 LoginTicketInterceptor 在所有 Controller 执行之前获取了用户信息,所以在此处做如下修改:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130152730.png)
|
||||
|
||||
其中,需要在 UserService 中添加一个获取用户权限的方法:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 获取某个用户的权限
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public Collection<? extends GrantedAuthority> getAuthorities(int userId) {
|
||||
User user = this.findUserById(userId);
|
||||
List<GrantedAuthority> list = new ArrayList<>();
|
||||
list.add(new GrantedAuthority() {
|
||||
@Override
|
||||
public String getAuthority() {
|
||||
switch (user.getType()) {
|
||||
case 1:
|
||||
return AUTHORITY_ADMIN;
|
||||
case 2:
|
||||
return AUTHORITY_MODERATOR;
|
||||
default:
|
||||
return AUTHORITY_USER;
|
||||
}
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
```
|
||||
|
||||
别忘了请求结束后清除相关内容:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130152843.png)
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130152910.png)
|
||||
|
||||
## CSRF 配置
|
||||
|
||||
禁用 csrf 的 token 检查
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130201754.png)
|
177
docs/270-置顶加精删除.md
Normal file
177
docs/270-置顶加精删除.md
Normal file
@ -0,0 +1,177 @@
|
||||
# 置顶、加精、删除
|
||||
|
||||
---
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130202241.png)
|
||||
|
||||
## 功能实现
|
||||
|
||||
service 和 DAO 就不列出来了,比较简单
|
||||
|
||||
### Controller
|
||||
|
||||
置顶、加精帖子同时也需要触发发帖事件,修改 Elasticsearch 服务器的数据
|
||||
|
||||
`DiscusspostController`:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 置顶帖子
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/top")
|
||||
@ResponseBody
|
||||
public String setTop(int id) {
|
||||
discussPostSerivce.updateType(id, 1);
|
||||
|
||||
// 触发发帖事件,通过消息队列将其存入 Elasticsearch 服务器
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_PUBLISH)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
```
|
||||
|
||||
删除帖子时将数据库中的状态修改为拉黑 2(这里我们没有写删除帖子的方法,而是将其状态设置为拉黑,重构的时候考虑一下将这个改为直接删除),并触发删帖事件, 删除 Elasticsearch 服务器中的数据
|
||||
|
||||
EventConsumer:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 消费删帖事件
|
||||
*/
|
||||
@KafkaListener(topics = {TOPIC_DELETE})
|
||||
public void handleDeleteMessage(ConsumerRecord record) {
|
||||
if (record == null || record.value() == null) {
|
||||
logger.error("消息的内容为空");
|
||||
return ;
|
||||
}
|
||||
Event event = JSONObject.parseObject(record.value().toString(), Event.class);
|
||||
if (event == null) {
|
||||
logger.error("消息格式错误");
|
||||
return ;
|
||||
}
|
||||
|
||||
elasticsearchService.deleteDiscusspost(event.getEntityId());
|
||||
}
|
||||
```
|
||||
|
||||
DiscusspostController:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 删除帖子
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
@ResponseBody
|
||||
public String setDelete(int id) {
|
||||
discussPostSerivce.updateStatus(id, 2);
|
||||
|
||||
// 触发删帖事件,通过消息队列更新 Elasticsearch 服务器
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_DELETE)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
```
|
||||
|
||||
### 前端
|
||||
|
||||
input 隐藏框的作用是方便给后端那几个方法传递参数值 post.id
|
||||
|
||||
button 的 id 是方便在 js 中进行调用
|
||||
|
||||
```html
|
||||
<input type="hidden" id="postId" th:value="${post.id}">
|
||||
<button type="button" class="btn btn-danger btn-sm" id="topBtn"
|
||||
th:disabled="${post.type == 1}" >置顶</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" id="wonderfulBtn"
|
||||
th:disabled="${post.status == 1}" >加精</button>
|
||||
<button type="button" class="btn btn-danger btn-sm" id="deleteBtn"
|
||||
th:disabled="${post.status == 2}" >删除</button>
|
||||
```
|
||||
|
||||
对应的 discuss.js:(我发现只是要异步请求就需要在 js 文件中写逻辑,非异步请求不需要,不知道是否正确,后续重构的时候再看)
|
||||
|
||||
```js
|
||||
$(function(){
|
||||
$("#topBtn").click(setTop);
|
||||
$("#wonderfulBtn").click(setWonderful);
|
||||
$("#deleteBtn").click(setDelete);
|
||||
});
|
||||
|
||||
// 置顶
|
||||
function setTop() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/top", // 方法路径
|
||||
{"id":$("#postId").val()}, // 给方法传递参数
|
||||
function (data) { // 方法返回的结果
|
||||
data = $.parseJSON(data); // 方法返回的结果是 json 类型,我们将其转为 object
|
||||
if (data.code == 0) {
|
||||
// 置顶成功后,将置顶按钮设置为不可用
|
||||
$("#topBtn").attr("disabled", "disable")
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 加精(和置顶差不多)
|
||||
|
||||
// 删除
|
||||
function setDelete() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/delete",
|
||||
{"id":$("#postId").val()},
|
||||
function (data) {
|
||||
data = $.parseJSON(data);
|
||||
if (data.code == 0) {
|
||||
// 删除成功后,跳转到首页
|
||||
location.href = CONTEXT_PATH + "/index";
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
## 权限管理
|
||||
|
||||
在 SecurityConfig 中加上这么一段即可:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130215025.png)
|
||||
|
||||
## 按钮显示
|
||||
|
||||
不同的权限显示不同的按钮这个功能,需要通过 Thymeleaf SpringSecurity5 实现,导入依赖:
|
||||
|
||||
```xml
|
||||
<!--thymeleaf springsecurity5-->
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
在文件头添加引用 `xmlns:sec="http://www.thymeleaf.org/extra/spring-security"`:
|
||||
|
||||
```html
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extra/spring-security">
|
||||
```
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210130215201.png)
|
271
docs/280-网站数据统计.md
Normal file
271
docs/280-网站数据统计.md
Normal file
@ -0,0 +1,271 @@
|
||||
# 网站数据统计
|
||||
|
||||
---
|
||||
|
||||
使用 Redis 高级数据类型:
|
||||
|
||||
<img src="https://gitee.com/veal98/images/raw/master/img/20210131104903.png" style="zoom: 33%;" />
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131112124.png)
|
||||
|
||||
DAU 只统计登录用户,UV 兼并访客和登录用户
|
||||
|
||||
DAU:将用户 ID 作为 bitmap 的 key 存入,若该用户当天访问过,则置 value 为 1。一天用一个 bitmap
|
||||
|
||||
计算区间内的 DAU 的时候, 使用 or 运算,就是说这么多天只要这个用户登陆过一次,就算活跃用户
|
||||
|
||||
RedisKeyUtil:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 单日 UV
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static String getUVKey(String date) {
|
||||
return PREFIX_UV + SPLIT + date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 区间 UV
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
public static String getUVKey(String startDate, String endDate) {
|
||||
return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单日 DAU
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static String getDAUKey(String date) {
|
||||
return PREFIX_DAU + SPLIT + date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 区间 DAU
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
public static String getDAUKey(String startDate, String endDate) {
|
||||
return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;
|
||||
}
|
||||
```
|
||||
|
||||
## Service
|
||||
|
||||
```java
|
||||
/**
|
||||
* 网站数据统计(UV / DAU)
|
||||
*/
|
||||
@Service
|
||||
public class DataService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* 将指定的 IP 计入当天的 UV
|
||||
* @param ip
|
||||
*/
|
||||
public void recordUV(String ip) {
|
||||
String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));
|
||||
redisTemplate.opsForHyperLogLog().add(redisKey, ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定日期范围内的 UV
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public long calculateUV(Date start, Date end) {
|
||||
if (start == null || end == null) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
|
||||
// 整理该日期范围内的 key
|
||||
List<String> keyList = new ArrayList<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(start);
|
||||
while (!calendar.getTime().after(end)) {
|
||||
String key = RedisKeyUtil.getUVKey(df.format(calendar.getTime()));
|
||||
keyList.add(key);
|
||||
calendar.add(Calendar.DATE, 1); // 加1天
|
||||
}
|
||||
|
||||
// 合并这些天的 UV
|
||||
String redisKey = RedisKeyUtil.getUVKey(df.format(start), df.format(end));
|
||||
redisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());
|
||||
|
||||
// 返回统计结果
|
||||
return redisTemplate.opsForHyperLogLog().size(redisKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定的 IP 计入当天的 DAU
|
||||
* @param userId
|
||||
*/
|
||||
public void recordDAU(int userId) {
|
||||
String redisKey = RedisKeyUtil.getDAUKey(df.format(new Date()));
|
||||
redisTemplate.opsForValue().setBit(redisKey, userId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定日期范围内的 DAU
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public long calculateDAU(Date start, Date end) {
|
||||
if (start == null || end == null) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
|
||||
// 整理该日期范围内的 key
|
||||
List<byte[]> keyList = new ArrayList<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(start);
|
||||
while (!calendar.getTime().after(end)) {
|
||||
String key = RedisKeyUtil.getDAUKey(df.format(calendar.getTime()));
|
||||
keyList.add(key.getBytes());
|
||||
calendar.add(Calendar.DATE, 1); // 加1天
|
||||
}
|
||||
|
||||
// 进行 or 运算
|
||||
return (long) redisTemplate.execute(new RedisCallback() {
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
|
||||
String redisKey = RedisKeyUtil.getDAUKey(df.format(start), df.format(end));
|
||||
redisConnection.bitOp(RedisStringCommands.BitOperation.OR,
|
||||
redisKey.getBytes(), keyList.toArray(new byte[0][0]));
|
||||
return redisConnection.bitCount(redisKey.getBytes());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 拦截器
|
||||
|
||||
在所有请求执行之前查询 uv 和 dau
|
||||
|
||||
```java
|
||||
@Component
|
||||
public class DataInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
private DataService dataService;
|
||||
|
||||
@Autowired
|
||||
private HostHolder hostHolder;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 统计 UV
|
||||
String ip = request.getRemoteHost();
|
||||
dataService.recordUV(ip);
|
||||
|
||||
// 统计 DAU
|
||||
User user = hostHolder.getUser();
|
||||
if (user != null) {
|
||||
dataService.recordDAU(user.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
别忘记在配置中添加此拦截器
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131130906.png)
|
||||
|
||||
## Controller
|
||||
|
||||
```java
|
||||
/**
|
||||
* 网站数据
|
||||
*/
|
||||
@Controller
|
||||
public class DataController {
|
||||
|
||||
@Autowired
|
||||
private DataService dataService;
|
||||
|
||||
/**
|
||||
* 进入统计界面
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/data", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
public String getDataPage() {
|
||||
return "/site/admin/data";
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计网站 uv
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/data/uv")
|
||||
public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,
|
||||
Model model) {
|
||||
long uv = dataService.calculateUV(start, end);
|
||||
model.addAttribute("uvResult", uv);
|
||||
model.addAttribute("uvStartDate", start);
|
||||
model.addAttribute("uvEndDate", end);
|
||||
return "forward:/data";
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计网站 DAU
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/data/dau")
|
||||
public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,
|
||||
Model model) {
|
||||
long dau = dataService.calculateDAU(start, end);
|
||||
model.addAttribute("dauResult", dau);
|
||||
model.addAttribute("dauStartDate", start);
|
||||
model.addAttribute("dauEndDate", end);
|
||||
return "forward:/data";
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131121136.png)
|
||||
|
||||
|
||||
|
||||
别忘记给管理员赋予权限:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131130739.png)
|
||||
|
||||
## 前端
|
||||
|
||||
data.html
|
||||
|
||||
```html
|
||||
<form method="post" th:action="@{/data/dau}">
|
||||
<input type="date"name="start"
|
||||
th:value="${#dates.format(dauStartDate, 'yyyy-MM-dd')}" />
|
||||
<input type="date" required name="end"
|
||||
th:value="${#dates.format(dauEndDate, 'yyyy-MM-dd')}" />
|
||||
<button type="submit">开始统计</button>
|
||||
</form>
|
||||
统计结果 <span th:text="${dauResult}">
|
||||
```
|
234
docs/290-热帖排行.md
Normal file
234
docs/290-热帖排行.md
Normal file
@ -0,0 +1,234 @@
|
||||
# 热帖排行
|
||||
|
||||
---
|
||||
|
||||
每隔一段时间就计算帖子的分数,需要使用分布式定时任务:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131152028.png)
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131152852.png)
|
||||
|
||||
Spring Quartz 导包
|
||||
|
||||
```xml
|
||||
<!--Spring Quartz-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
由于 Spring Quartz 依赖于数据库,所以我们需要提前在数据库中创建 Quartz 需要的表
|
||||
|
||||
运行 init_quartz.sql 文件
|
||||
|
||||
<img src="https://gitee.com/veal98/images/raw/master/img/20210131155131.png" style="zoom: 67%;" />
|
||||
|
||||
分数计算设计:
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131161518.png)
|
||||
|
||||
|
||||
|
||||
## 分数计算
|
||||
|
||||
每次发生点赞(给帖子点赞)、评论(给帖子评论)、加精的时候,就将这些帖子存入缓存 Redis 中,然后通过分布式的定时任务,每隔一段时间就从缓存中取出这些帖子进行计算分数。
|
||||
|
||||
RedisKeyUtil
|
||||
|
||||
```java
|
||||
/**
|
||||
* 帖子分数
|
||||
* @return
|
||||
*/
|
||||
public static String getPostScoreKey() {
|
||||
return PREFIX_POST + SPLIT + "score";
|
||||
}
|
||||
```
|
||||
|
||||
### Controller
|
||||
|
||||
以点赞操作为例:
|
||||
|
||||
<img src="https://gitee.com/veal98/images/raw/master/img/20210131173755.png" style="zoom: 50%;" />
|
||||
|
||||
### Job
|
||||
|
||||
```java
|
||||
/**
|
||||
* 帖子分数计算刷新
|
||||
*/
|
||||
public class PostScoreRefreshJob implements Job, CommunityConstant {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PostScoreRefreshJob.class);
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private DiscussPostSerivce discussPostSerivce;
|
||||
|
||||
@Autowired
|
||||
private LikeService likeService;
|
||||
|
||||
@Autowired
|
||||
private ElasticsearchService elasticsearchService;
|
||||
|
||||
// Epoch 纪元
|
||||
private static final Date epoch;
|
||||
|
||||
static {
|
||||
try {
|
||||
epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-01-01 00:00:00");
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("初始化 Epoch 纪元失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);
|
||||
|
||||
if (operations.size() == 0) {
|
||||
logger.info("[任务取消] 没有需要刷新的帖子");
|
||||
return ;
|
||||
}
|
||||
|
||||
logger.info("[任务开始] 正在刷新帖子分数: " + operations.size());
|
||||
while (operations.size() > 0) {
|
||||
this.refresh((Integer) operations.pop());
|
||||
}
|
||||
logger.info("[任务结束] 帖子分数刷新完毕");
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新帖子分数
|
||||
* @param postId
|
||||
*/
|
||||
private void refresh(int postId) {
|
||||
DiscussPost post = discussPostSerivce.findDiscussPostById(postId);
|
||||
|
||||
if (post == null) {
|
||||
logger.error("该帖子不存在: id = " + postId);
|
||||
return ;
|
||||
}
|
||||
|
||||
// 是否加精
|
||||
boolean wonderful = post.getStatus() == 1;
|
||||
// 评论数量
|
||||
int commentCount = post.getCommentCount();
|
||||
// 点赞数量
|
||||
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);
|
||||
|
||||
// 计算权重
|
||||
double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
|
||||
// 分数 = 权重 + 发帖距离天数
|
||||
double score = Math.log10(Math.max(w, 1))
|
||||
+ (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);
|
||||
// 更新帖子分数
|
||||
discussPostSerivce.updateScore(postId, score);
|
||||
// 同步更新搜索数据
|
||||
post.setScore(score);
|
||||
elasticsearchService.saveDiscusspost(post);
|
||||
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
注意同步更新一下搜索 Elasticsearch 服务器的数据
|
||||
|
||||
### Quarz Config
|
||||
|
||||
```java
|
||||
/**
|
||||
* Spring Quartz 配置类,用于将数据存入数据库,以后直接从数据库中调用数据
|
||||
*/
|
||||
@Configuration
|
||||
public class QuartzConfig {
|
||||
|
||||
/**
|
||||
* 刷新帖子分数任务
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public JobDetailFactoryBean postScoreRefreshJobDetail() {
|
||||
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
|
||||
factoryBean.setJobClass(PostScoreRefreshJob.class);
|
||||
factoryBean.setName("postScoreRefreshJob");
|
||||
factoryBean.setGroup("communityJobGroup");
|
||||
factoryBean.setDurability(true);
|
||||
factoryBean.setRequestsRecovery(true);
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新帖子分数触发器
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail) {
|
||||
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
|
||||
factoryBean.setJobDetail(postScoreRefreshJobDetail);
|
||||
factoryBean.setName("postScoreRefreshTrigger");
|
||||
factoryBean.setGroup("communityTriggerGroup");
|
||||
factoryBean.setRepeatInterval(1000 * 60 * 5); // 5分钟刷新一次
|
||||
factoryBean.setJobDataMap(new JobDataMap());
|
||||
return factoryBean;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 根据分数进行排行显示
|
||||
|
||||
重构下分页查询帖子的方法:
|
||||
|
||||
```java
|
||||
/**
|
||||
* 分页查询讨论帖信息
|
||||
*
|
||||
* @param userId 当传入的 userId = 0 时查找所有用户的帖子
|
||||
* 当传入的 userId != 0 时,查找该指定用户的帖子
|
||||
* @param offset 每页的起始索引
|
||||
* @param limit 每页显示多少条数据
|
||||
* @param orderMode 排行模式(若传入 1, 则按照热度来排序)
|
||||
* @return
|
||||
*/
|
||||
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);
|
||||
```
|
||||
|
||||
添加一个 orderMode,若传入 1, 则按照热度来排序,传入 0(默认)则按照最新来排序。当然,置顶的帖子不受影响
|
||||
|
||||
对应的 service 也需要做相应修改
|
||||
|
||||
```java
|
||||
/**
|
||||
* 分页查询讨论帖信息
|
||||
*
|
||||
* @param userId 当传入的 userId = 0 时查找所有用户的帖子
|
||||
* 当传入的 userId != 0 时,查找该指定用户的帖子
|
||||
* @param offset 每页的起始索引
|
||||
* @param limit 每页显示多少条数据
|
||||
* @param orderMode 排行模式(若传入 1, 则按照热度来排序)
|
||||
* @return
|
||||
*/
|
||||
public List<DiscussPost> findDiscussPosts (int userId, int offset, int limit, int orderMode) {
|
||||
return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);
|
||||
}
|
||||
```
|
||||
|
||||
在修改对应的 HomeController
|
||||
|
||||
![](https://gitee.com/veal98/images/raw/master/img/20210131175558.png)
|
||||
|
||||
Get 方法:前端是通过 ? 来传递参数的:比如说`/index?1`,前端 `th:href="@{/index(orderMode=0)}"`
|
||||
|
||||
而通过请求体来传递参数使用的是 Post 请求 :比如说`/add/postid`,前端 `th:href="@{|/index/${post.id}|}"`
|
||||
|
||||
修改一下 index.html
|
||||
|
||||
```html
|
||||
<a th:class="|nav-link ${orderMode==0 ? 'active' : ''}|" th:href="@{/index(orderMode=0)}"><i class="bi bi-lightning"></i> 最新</a>
|
||||
|
||||
<a th:class="|nav-link ${orderMode==1 ? 'active' : ''}|" th:href="@{/index(orderMode=1)}"><i class="bi bi-hand-thumbs-up"></i> 最热</a>
|
||||
```
|
1058
log/community/error/log-error-2021-01-29.0.log
Normal file
1058
log/community/error/log-error-2021-01-29.0.log
Normal file
File diff suppressed because it is too large
Load Diff
491
log/community/error/log-error-2021-01-30.0.log
Normal file
491
log/community/error/log-error-2021-01-30.0.log
Normal file
@ -0,0 +1,491 @@
|
||||
2021-01-30 20:17:55,101 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{urF3XrU-TTKMat5FxVJzsA}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 20:48:10,576 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{_7x5-pyRRjeLhgKPXZyO5g}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 20:48:49,671 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = publish, partition = 0, offset = 2, CreateTime = 1612010929618, serialized key size = -1, serialized value size = 89, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":287,"entityType":1,"entityUserId":0,"topic":"publish","userId":153})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handlePublishMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{_7x5-pyRRjeLhgKPXZyO5g}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{_7x5-pyRRjeLhgKPXZyO5g}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{_7x5-pyRRjeLhgKPXZyO5g}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:577)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.saveDiscusspost(ElasticsearchService.java:46)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$3ff8cf63.saveDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handlePublishMessage(EventConsumer.java:94)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 20:53:00,132 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:00:22,380 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = publish, partition = 0, offset = 3, CreateTime = 1612011622333, serialized key size = -1, serialized value size = 89, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":287,"entityType":1,"entityUserId":0,"topic":"publish","userId":153})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handlePublishMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:577)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.saveDiscusspost(ElasticsearchService.java:46)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$5ef3e7ba.saveDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handlePublishMessage(EventConsumer.java:94)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 21:00:29,457 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#0-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = publish, partition = 0, offset = 4, CreateTime = 1612011629453, serialized key size = -1, serialized value size = 89, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":287,"entityType":1,"entityUserId":0,"topic":"publish","userId":153})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handlePublishMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{lvLge7atRL6vM_excftsdQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:577)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy113.save(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.saveDiscusspost(ElasticsearchService.java:46)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$5ef3e7ba.saveDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handlePublishMessage(EventConsumer.java:94)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 21:03:09,130 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{i6eA_yD2Q0ip_jyw1WDgYg}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:05:21,812 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{u_naxn3VTkS9pOfVPqhWqw}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:06:08,199 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{gtASUSTkS3aMiK72cSdx_Q}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:06:22,239 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = delete, partition = 0, offset = 0, CreateTime = 1612011982207, serialized key size = -1, serialized value size = 88, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":287,"entityType":1,"entityUserId":0,"topic":"delete","userId":153})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handleDeleteMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{gtASUSTkS3aMiK72cSdx_Q}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{gtASUSTkS3aMiK72cSdx_Q}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{gtASUSTkS3aMiK72cSdx_Q}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.delete(ElasticsearchTemplate.java:681)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.deleteById(AbstractElasticsearchRepository.java:233)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.deleteById(AbstractElasticsearchRepository.java:60)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.deleteById(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.deleteById(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.deleteDiscusspost(ElasticsearchService.java:54)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$f8675f06.deleteDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handleDeleteMessage(EventConsumer.java:113)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 21:10:29,830 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:12:32,090 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = publish, partition = 0, offset = 5, CreateTime = 1612012352050, serialized key size = -1, serialized value size = 88, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":286,"entityType":1,"entityUserId":0,"topic":"publish","userId":21})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handlePublishMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:577)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.save(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.save(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.saveDiscusspost(ElasticsearchService.java:46)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$e69a288d.saveDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handlePublishMessage(EventConsumer.java:94)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 21:12:32,987 ERROR [org.springframework.kafka.KafkaListenerEndpointContainer#1-0-C-1] o.s.k.l.LoggingErrorHandler [LoggingErrorHandler.java:37] Error while processing: ConsumerRecord(topic = publish, partition = 0, offset = 6, CreateTime = 1612012352982, serialized key size = -1, serialized value size = 88, headers = RecordHeaders(headers = [], isReadOnly = false), key = null, value = {"data":{},"entityId":286,"entityType":1,"entityUserId":0,"topic":"publish","userId":21})
|
||||
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method 'public void com.greate.community.event.EventConsumer.handlePublishMessage(org.apache.kafka.clients.consumer.ConsumerRecord)' threw exception; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]]; nested exception is NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]]
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java:1311)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java:1300)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1227)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java:1198)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java:1118)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java:933)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java:749)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java:698)
|
||||
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
|
||||
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
|
||||
at java.lang.Thread.run(Thread.java:748)
|
||||
Caused by: org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{Abl5laOQR_Oo0VomEKiFGQ}{127.0.0.1}{127.0.0.1:9300}]
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.ensureNodesAreAvailable(TransportClientNodesService.java:349)
|
||||
at org.elasticsearch.client.transport.TransportClientNodesService.execute(TransportClientNodesService.java:247)
|
||||
at org.elasticsearch.client.transport.TransportProxyClient.execute(TransportProxyClient.java:60)
|
||||
at org.elasticsearch.client.transport.TransportClient.doExecute(TransportClient.java:381)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:407)
|
||||
at org.elasticsearch.client.support.AbstractClient.execute(AbstractClient.java:396)
|
||||
at org.elasticsearch.action.ActionRequestBuilder.execute(ActionRequestBuilder.java:46)
|
||||
at org.springframework.data.elasticsearch.core.ElasticsearchTemplate.index(ElasticsearchTemplate.java:577)
|
||||
at org.springframework.data.elasticsearch.repository.support.AbstractElasticsearchRepository.save(AbstractElasticsearchRepository.java:156)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition$RepositoryFragments.invoke(RepositoryComposition.java:359)
|
||||
at org.springframework.data.repository.core.support.RepositoryComposition.invoke(RepositoryComposition.java:200)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$ImplementationMethodExecutionInterceptor.invoke(RepositoryFactorySupport.java:644)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:608)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.lambda$invoke$3(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:595)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:59)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.save(Unknown Source)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:343)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:198)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
|
||||
at com.sun.proxy.$Proxy112.save(Unknown Source)
|
||||
at com.greate.community.service.ElasticsearchService.saveDiscusspost(ElasticsearchService.java:46)
|
||||
at com.greate.community.service.ElasticsearchService$$FastClassBySpringCGLIB$$434a3a5f.invoke(<generated>)
|
||||
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218)
|
||||
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
|
||||
at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:56)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
|
||||
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
|
||||
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688)
|
||||
at com.greate.community.service.ElasticsearchService$$EnhancerBySpringCGLIB$$e69a288d.saveDiscusspost(<generated>)
|
||||
at com.greate.community.event.EventConsumer.handlePublishMessage(EventConsumer.java:94)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
|
||||
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
|
||||
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
|
||||
at java.lang.reflect.Method.invoke(Method.java:498)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:171)
|
||||
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:120)
|
||||
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java:48)
|
||||
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java:283)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:79)
|
||||
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java:50)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java:1263)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java:1256)
|
||||
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java:1217)
|
||||
... 8 common frames omitted
|
||||
2021-01-30 21:24:08,184 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{T4a8QSEZSO-8V3uUzteXHA}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:31:44,905 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{3q2TbAYUSBqRzhArIBtg2Q}{127.0.0.1}{127.0.0.1:9300}]
|
||||
2021-01-30 21:32:32,569 ERROR [restartedMain] o.s.d.e.r.s.AbstractElasticsearchRepository [AbstractElasticsearchRepository.java:91] failed to load elasticsearch nodes : org.elasticsearch.client.transport.NoNodeAvailableException: None of the configured nodes are available: [{#transport#-1}{viuNkqB6QWuahdOnDFbP5A}{127.0.0.1}{127.0.0.1:9300}]
|
4165
log/community/info/log-info-2021-01-29.0.log
Normal file
4165
log/community/info/log-info-2021-01-29.0.log
Normal file
File diff suppressed because it is too large
Load Diff
7188
log/community/info/log-info-2021-01-30.0.log
Normal file
7188
log/community/info/log-info-2021-01-30.0.log
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,23 +1,14 @@
|
||||
2021-01-29 10:47:42,318 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:44,453 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:46,573 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:48,892 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:51,234 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:54,092 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:57,212 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:00,224 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:03,472 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:06,532 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:09,562 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:12,724 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:15,632 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:18,754 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:21,652 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:24,963 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:28,214 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:31,325 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:34,524 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:37,432 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:40,276 WARN [restartedMain] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext [AbstractApplicationContext.java:557] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.kafka.config.internalKafkaListenerEndpointRegistry'; nested exception is org.apache.kafka.common.errors.TimeoutException: Timeout expired while fetching topic metadata
|
||||
2021-01-29 10:52:05,440 WARN [http-nio-8080-exec-10] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379]
|
||||
2021-01-29 11:04:09,393 WARN [http-nio-8080-exec-3] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "my-post.html"]
|
||||
2021-01-31 12:41:08,662 WARN [http-nio-8080-exec-2] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String]
|
||||
2021-01-31 12:41:53,872 WARN [http-nio-8080-exec-8] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String]
|
||||
2021-01-31 12:43:41,269 WARN [http-nio-8080-exec-8] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String]
|
||||
2021-01-31 12:46:47,290 WARN [http-nio-8080-exec-2] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String]
|
||||
2021-01-31 12:50:56,887 WARN [http-nio-8080-exec-8] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [java.lang.ClassCastException: java.util.ArrayList cannot be cast to java.lang.String]
|
||||
2021-01-31 13:00:31,265 WARN [http-nio-8080-exec-4] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "my-reply.html"]
|
||||
2021-01-31 17:00:56,014 WARN [http-nio-8080-exec-3] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:02:14,746 WARN [http-nio-8080-exec-4] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:03:10,083 WARN [http-nio-8080-exec-6] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:03:20,433 WARN [http-nio-8080-exec-10] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:07:07,426 WARN [http-nio-8080-exec-5] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:09:49,019 WARN [http-nio-8080-exec-8] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.greate.community.dao.DiscussPostMapper.updateCommentCount]
|
||||
2021-01-31 17:26:47,312 WARN [http-nio-8080-exec-1] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{GL6pOJCiTqyKMUgG5cRPbg}{127.0.0.1}{127.0.0.1:9300}]]]
|
||||
2021-01-31 17:26:52,632 WARN [http-nio-8080-exec-3] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [NoNodeAvailableException[None of the configured nodes are available: [{#transport#-1}{GL6pOJCiTqyKMUgG5cRPbg}{127.0.0.1}{127.0.0.1:9300}]]]
|
||||
|
23
log/community/warn/log-warn-2021-01-29.0.log
Normal file
23
log/community/warn/log-warn-2021-01-29.0.log
Normal file
@ -0,0 +1,23 @@
|
||||
2021-01-29 10:47:42,318 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:44,453 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:46,573 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:48,892 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:51,234 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:54,092 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:47:57,212 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:00,224 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:03,472 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:06,532 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:09,562 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:12,724 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:15,632 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:18,754 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:21,652 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:24,963 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:28,214 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:31,325 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:34,524 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:37,432 WARN [restartedMain] o.a.k.c.NetworkClient [NetworkClient.java:671] [Consumer clientId=consumer-1, groupId=test-consumer-group] Connection to node -1 could not be established. Broker may not be available.
|
||||
2021-01-29 10:48:40,276 WARN [restartedMain] o.s.b.w.s.c.AnnotationConfigServletWebServerApplicationContext [AbstractApplicationContext.java:557] Exception encountered during context initialization - cancelling refresh attempt: org.springframework.context.ApplicationContextException: Failed to start bean 'org.springframework.kafka.config.internalKafkaListenerEndpointRegistry'; nested exception is org.apache.kafka.common.errors.TimeoutException: Timeout expired while fetching topic metadata
|
||||
2021-01-29 10:52:05,440 WARN [http-nio-8080-exec-10] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.data.redis.RedisConnectionFailureException: Unable to connect to Redis; nested exception is io.lettuce.core.RedisConnectionException: Unable to connect to localhost:6379]
|
||||
2021-01-29 11:04:09,393 WARN [http-nio-8080-exec-3] o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'int'; nested exception is java.lang.NumberFormatException: For input string: "my-post.html"]
|
2
log/community/warn/log-warn-2021-01-30.0.log
Normal file
2
log/community/warn/log-warn-2021-01-30.0.log
Normal file
@ -0,0 +1,2 @@
|
||||
2021-01-30 21:03:16,649 WARN [http-nio-8080-exec-4] o.s.w.s.m.s.DefaultHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
|
||||
2021-01-30 21:03:31,531 WARN [http-nio-8080-exec-8] o.s.w.s.m.s.DefaultHandlerExceptionResolver [AbstractHandlerExceptionResolver.java:198] Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]
|
18
pom.xml
18
pom.xml
@ -109,6 +109,18 @@
|
||||
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--Spring Security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--thymeleaf springsecurity5-->
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf.extras</groupId>
|
||||
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--Fastjson-->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
@ -116,6 +128,12 @@
|
||||
<version>1.2.58</version>
|
||||
</dependency>
|
||||
|
||||
<!--Spring Quartz-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-quartz</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--lombok-->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
|
179
sql/init_quartz.sql
Normal file
179
sql/init_quartz.sql
Normal file
@ -0,0 +1,179 @@
|
||||
#
|
||||
# In your Quartz properties file, you'll need to set
|
||||
# org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
|
||||
#
|
||||
#
|
||||
# By: Ron Cordell - roncordell
|
||||
# I didn't see this anywhere, so I thought I'd post it here. This is the script from Quartz to create the tables in a MySQL database, modified to use INNODB instead of MYISAM.
|
||||
|
||||
DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
|
||||
DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
|
||||
DROP TABLE IF EXISTS QRTZ_LOCKS;
|
||||
DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_TRIGGERS;
|
||||
DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
|
||||
DROP TABLE IF EXISTS QRTZ_CALENDARS;
|
||||
|
||||
CREATE TABLE QRTZ_JOB_DETAILS(
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
JOB_NAME VARCHAR(190) NOT NULL,
|
||||
JOB_GROUP VARCHAR(190) NOT NULL,
|
||||
DESCRIPTION VARCHAR(250) NULL,
|
||||
JOB_CLASS_NAME VARCHAR(250) NOT NULL,
|
||||
IS_DURABLE VARCHAR(1) NOT NULL,
|
||||
IS_NONCONCURRENT VARCHAR(1) NOT NULL,
|
||||
IS_UPDATE_DATA VARCHAR(1) NOT NULL,
|
||||
REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
|
||||
JOB_DATA BLOB NULL,
|
||||
PRIMARY KEY (SCHED_NAME,JOB_NAME,JOB_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
JOB_NAME VARCHAR(190) NOT NULL,
|
||||
JOB_GROUP VARCHAR(190) NOT NULL,
|
||||
DESCRIPTION VARCHAR(250) NULL,
|
||||
NEXT_FIRE_TIME BIGINT(13) NULL,
|
||||
PREV_FIRE_TIME BIGINT(13) NULL,
|
||||
PRIORITY INTEGER NULL,
|
||||
TRIGGER_STATE VARCHAR(16) NOT NULL,
|
||||
TRIGGER_TYPE VARCHAR(8) NOT NULL,
|
||||
START_TIME BIGINT(13) NOT NULL,
|
||||
END_TIME BIGINT(13) NULL,
|
||||
CALENDAR_NAME VARCHAR(190) NULL,
|
||||
MISFIRE_INSTR SMALLINT(2) NULL,
|
||||
JOB_DATA BLOB NULL,
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||
FOREIGN KEY (SCHED_NAME,JOB_NAME,JOB_GROUP)
|
||||
REFERENCES QRTZ_JOB_DETAILS(SCHED_NAME,JOB_NAME,JOB_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
REPEAT_COUNT BIGINT(7) NOT NULL,
|
||||
REPEAT_INTERVAL BIGINT(12) NOT NULL,
|
||||
TIMES_TRIGGERED BIGINT(10) NOT NULL,
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_CRON_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
CRON_EXPRESSION VARCHAR(120) NOT NULL,
|
||||
TIME_ZONE_ID VARCHAR(80),
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_SIMPROP_TRIGGERS
|
||||
(
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
STR_PROP_1 VARCHAR(512) NULL,
|
||||
STR_PROP_2 VARCHAR(512) NULL,
|
||||
STR_PROP_3 VARCHAR(512) NULL,
|
||||
INT_PROP_1 INT NULL,
|
||||
INT_PROP_2 INT NULL,
|
||||
LONG_PROP_1 BIGINT NULL,
|
||||
LONG_PROP_2 BIGINT NULL,
|
||||
DEC_PROP_1 NUMERIC(13,4) NULL,
|
||||
DEC_PROP_2 NUMERIC(13,4) NULL,
|
||||
BOOL_PROP_1 VARCHAR(1) NULL,
|
||||
BOOL_PROP_2 VARCHAR(1) NULL,
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_BLOB_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
BLOB_DATA BLOB NULL,
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP),
|
||||
INDEX (SCHED_NAME,TRIGGER_NAME, TRIGGER_GROUP),
|
||||
FOREIGN KEY (SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP)
|
||||
REFERENCES QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_CALENDARS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
CALENDAR_NAME VARCHAR(190) NOT NULL,
|
||||
CALENDAR BLOB NOT NULL,
|
||||
PRIMARY KEY (SCHED_NAME,CALENDAR_NAME))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
PRIMARY KEY (SCHED_NAME,TRIGGER_GROUP))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_FIRED_TRIGGERS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
ENTRY_ID VARCHAR(95) NOT NULL,
|
||||
TRIGGER_NAME VARCHAR(190) NOT NULL,
|
||||
TRIGGER_GROUP VARCHAR(190) NOT NULL,
|
||||
INSTANCE_NAME VARCHAR(190) NOT NULL,
|
||||
FIRED_TIME BIGINT(13) NOT NULL,
|
||||
SCHED_TIME BIGINT(13) NOT NULL,
|
||||
PRIORITY INTEGER NOT NULL,
|
||||
STATE VARCHAR(16) NOT NULL,
|
||||
JOB_NAME VARCHAR(190) NULL,
|
||||
JOB_GROUP VARCHAR(190) NULL,
|
||||
IS_NONCONCURRENT VARCHAR(1) NULL,
|
||||
REQUESTS_RECOVERY VARCHAR(1) NULL,
|
||||
PRIMARY KEY (SCHED_NAME,ENTRY_ID))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_SCHEDULER_STATE (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
INSTANCE_NAME VARCHAR(190) NOT NULL,
|
||||
LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
|
||||
CHECKIN_INTERVAL BIGINT(13) NOT NULL,
|
||||
PRIMARY KEY (SCHED_NAME,INSTANCE_NAME))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE QRTZ_LOCKS (
|
||||
SCHED_NAME VARCHAR(120) NOT NULL,
|
||||
LOCK_NAME VARCHAR(40) NOT NULL,
|
||||
PRIMARY KEY (SCHED_NAME,LOCK_NAME))
|
||||
ENGINE=InnoDB;
|
||||
|
||||
CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS(SCHED_NAME,REQUESTS_RECOVERY);
|
||||
CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS(SCHED_NAME,JOB_GROUP);
|
||||
|
||||
CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS(SCHED_NAME,JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS(SCHED_NAME,CALENDAR_NAME);
|
||||
CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS(SCHED_NAME,NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS(SCHED_NAME,TRIGGER_STATE,NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_STATE);
|
||||
CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS(SCHED_NAME,MISFIRE_INSTR,NEXT_FIRE_TIME,TRIGGER_GROUP,TRIGGER_STATE);
|
||||
|
||||
CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME);
|
||||
CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,INSTANCE_NAME,REQUESTS_RECOVERY);
|
||||
CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_NAME,JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,JOB_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_NAME,TRIGGER_GROUP);
|
||||
CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS(SCHED_NAME,TRIGGER_GROUP);
|
||||
|
||||
commit;
|
46
src/main/java/com/greate/community/config/QuartzConfig.java
Normal file
46
src/main/java/com/greate/community/config/QuartzConfig.java
Normal file
@ -0,0 +1,46 @@
|
||||
package com.greate.community.config;
|
||||
|
||||
import com.greate.community.quartz.PostScoreRefreshJob;
|
||||
import org.quartz.JobDataMap;
|
||||
import org.quartz.JobDetail;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
|
||||
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
|
||||
|
||||
/**
|
||||
* Spring Quartz 配置类,用于将数据存入数据库,以后直接从数据库中调用数据
|
||||
*/
|
||||
@Configuration
|
||||
public class QuartzConfig {
|
||||
|
||||
/**
|
||||
* 刷新帖子分数任务
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public JobDetailFactoryBean postScoreRefreshJobDetail() {
|
||||
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
|
||||
factoryBean.setJobClass(PostScoreRefreshJob.class);
|
||||
factoryBean.setName("postScoreRefreshJob");
|
||||
factoryBean.setGroup("communityJobGroup");
|
||||
factoryBean.setDurability(true);
|
||||
factoryBean.setRequestsRecovery(true);
|
||||
return factoryBean;
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新帖子分数触发器
|
||||
* @return
|
||||
*/
|
||||
@Bean
|
||||
public SimpleTriggerFactoryBean postScoreRefreshTrigger(JobDetail postScoreRefreshJobDetail) {
|
||||
SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
|
||||
factoryBean.setJobDetail(postScoreRefreshJobDetail);
|
||||
factoryBean.setName("postScoreRefreshTrigger");
|
||||
factoryBean.setGroup("communityTriggerGroup");
|
||||
factoryBean.setRepeatInterval(1000 * 60 * 5); // 5分钟刷新一次
|
||||
factoryBean.setJobDataMap(new JobDataMap());
|
||||
return factoryBean;
|
||||
}
|
||||
}
|
123
src/main/java/com/greate/community/config/SecurityConfig.java
Normal file
123
src/main/java/com/greate/community/config/SecurityConfig.java
Normal file
@ -0,0 +1,123 @@
|
||||
package com.greate.community.config;
|
||||
|
||||
import com.greate.community.util.CommunityConstant;
|
||||
import com.greate.community.util.CommunityUtil;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.access.AccessDeniedHandler;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@Configuration
|
||||
public class SecurityConfig extends WebSecurityConfigurerAdapter implements CommunityConstant {
|
||||
|
||||
/**
|
||||
* 静态资源
|
||||
* @param web
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/resources/**");
|
||||
}
|
||||
|
||||
// 认证环节我们使用自己的代码 LoginController,绕过 Spring Security 的
|
||||
|
||||
|
||||
/**
|
||||
* 授权
|
||||
* @param http
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http.authorizeRequests()
|
||||
.antMatchers(
|
||||
"/user/setting",
|
||||
"/user/upload",
|
||||
"/discuss/add",
|
||||
"/comment/add",
|
||||
"/letter/**",
|
||||
"/notice/**",
|
||||
"/like",
|
||||
"/follow",
|
||||
"/unfollow"
|
||||
)
|
||||
.hasAnyAuthority(
|
||||
AUTHORITY_USER,
|
||||
AUTHORITY_ADMIN,
|
||||
AUTHORITY_MODERATOR
|
||||
)
|
||||
|
||||
.antMatchers(
|
||||
"/discuss/top",
|
||||
"/discuss/wonderful"
|
||||
)
|
||||
.hasAnyAuthority(
|
||||
AUTHORITY_MODERATOR
|
||||
)
|
||||
|
||||
.antMatchers(
|
||||
"/discuss/delete",
|
||||
"/data/**"
|
||||
)
|
||||
.hasAnyAuthority(
|
||||
AUTHORITY_ADMIN
|
||||
)
|
||||
|
||||
.anyRequest().permitAll()
|
||||
|
||||
.and().csrf().disable();
|
||||
|
||||
// 权限不够时的处理
|
||||
http.exceptionHandling()
|
||||
// 1. 未登录时的处理
|
||||
.authenticationEntryPoint(new AuthenticationEntryPoint() {
|
||||
@Override
|
||||
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
|
||||
String xRequestedWith = request.getHeader("x-requested-with");
|
||||
if ("XMLHttpRequest".equals(xRequestedWith)) {
|
||||
// 异步请求
|
||||
response.setContentType("application/plain;charset=utf-8");
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(CommunityUtil.getJSONString(403, "你还没有登录"));
|
||||
}
|
||||
else {
|
||||
// 普通请求
|
||||
response.sendRedirect(request.getContextPath() + "/login");
|
||||
}
|
||||
}
|
||||
})
|
||||
// 2. 权限不够时的处理
|
||||
.accessDeniedHandler(new AccessDeniedHandler() {
|
||||
@Override
|
||||
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
|
||||
String xRequestedWith = request.getHeader("x-requested-with");
|
||||
if ("XMLHttpRequest".equals(xRequestedWith)) {
|
||||
// 异步请求
|
||||
response.setContentType("application/plain;charset=utf-8");
|
||||
PrintWriter writer = response.getWriter();
|
||||
writer.write(CommunityUtil.getJSONString(403, "你没有访问该功能的权限"));
|
||||
}
|
||||
else {
|
||||
// 普通请求
|
||||
response.sendRedirect(request.getContextPath() + "/denied");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Security 底层会默认拦截 /logout 请求,进行退出处理
|
||||
// 此处赋予它一个根本不存在的退出路径,使得程序能够执行到我们自己编写的退出代码
|
||||
http.logout().logoutUrl("/securitylogout");
|
||||
}
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
package com.greate.community.config;
|
||||
|
||||
import com.greate.community.controller.interceptor.DataInterceptor;
|
||||
import com.greate.community.controller.interceptor.LoginRequiredInterceptor;
|
||||
import com.greate.community.controller.interceptor.LoginTicketInterceptor;
|
||||
import com.greate.community.controller.interceptor.MessageInterceptor;
|
||||
@ -17,12 +18,15 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
@Autowired
|
||||
private LoginTicketInterceptor loginTicketInterceptor;
|
||||
|
||||
@Autowired
|
||||
private LoginRequiredInterceptor loginRequiredInterceptor;
|
||||
// @Autowired
|
||||
// private LoginRequiredInterceptor loginRequiredInterceptor;
|
||||
|
||||
@Autowired
|
||||
private MessageInterceptor messageInterceptor;
|
||||
|
||||
@Autowired
|
||||
private DataInterceptor dataInterceptor;
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 对除静态资源外所有路径进行拦截
|
||||
@ -30,11 +34,14 @@ public class WebMvcConfig implements WebMvcConfigurer {
|
||||
.excludePathPatterns("/css/**", "/js/**", "/img/**");
|
||||
|
||||
// 对除静态资源外所有路径进行拦截
|
||||
registry.addInterceptor(loginRequiredInterceptor)
|
||||
.excludePathPatterns("/css/**", "/js/**", "/img/**");
|
||||
// registry.addInterceptor(loginRequiredInterceptor)
|
||||
// .excludePathPatterns("/css/**", "/js/**", "/img/**");
|
||||
|
||||
registry.addInterceptor(messageInterceptor)
|
||||
.excludePathPatterns("/css/**", "/js/**", "/img/**");
|
||||
|
||||
registry.addInterceptor(dataInterceptor)
|
||||
.excludePathPatterns("/css/**", "/js/**", "/img/**");
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,9 @@ import com.greate.community.service.CommentService;
|
||||
import com.greate.community.service.DiscussPostSerivce;
|
||||
import com.greate.community.util.CommunityConstant;
|
||||
import com.greate.community.util.HostHolder;
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -37,6 +39,9 @@ public class CommentController implements CommunityConstant {
|
||||
@Autowired
|
||||
private EventProducer eventProducer;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 添加评论
|
||||
* @param discussPostId
|
||||
@ -75,6 +80,10 @@ public class CommentController implements CommunityConstant {
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(discussPostId);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
// 计算帖子分数
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
redisTemplate.opsForSet().add(redisKey, discussPostId);
|
||||
}
|
||||
|
||||
return "redirect:/discuss/detail/" + discussPostId;
|
||||
|
@ -0,0 +1,67 @@
|
||||
package com.greate.community.controller;
|
||||
|
||||
import com.greate.community.service.DataService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 网站数据
|
||||
*/
|
||||
@Controller
|
||||
public class DataController {
|
||||
|
||||
@Autowired
|
||||
private DataService dataService;
|
||||
|
||||
/**
|
||||
* 进入统计界面
|
||||
* @return
|
||||
*/
|
||||
@RequestMapping(value = "/data", method = {RequestMethod.GET, RequestMethod.POST})
|
||||
public String getDataPage() {
|
||||
return "/site/admin/data";
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计网站 uv
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/data/uv")
|
||||
public String getUV(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,
|
||||
Model model) {
|
||||
long uv = dataService.calculateUV(start, end);
|
||||
model.addAttribute("uvResult", uv);
|
||||
model.addAttribute("uvStartDate", start);
|
||||
model.addAttribute("uvEndDate", end);
|
||||
return "forward:/data";
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计网站 DAU
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/data/dau")
|
||||
public String getDAU(@DateTimeFormat(pattern = "yyyy-MM-dd") Date start,
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd") Date end,
|
||||
Model model) {
|
||||
long dau = dataService.calculateDAU(start, end);
|
||||
model.addAttribute("dauResult", dau);
|
||||
model.addAttribute("dauStartDate", start);
|
||||
model.addAttribute("dauEndDate", end);
|
||||
return "forward:/data";
|
||||
}
|
||||
|
||||
}
|
@ -9,11 +9,14 @@ import com.greate.community.service.UserService;
|
||||
import com.greate.community.util.CommunityConstant;
|
||||
import com.greate.community.util.CommunityUtil;
|
||||
import com.greate.community.util.HostHolder;
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
@ -41,6 +44,9 @@ public class DiscussPostController implements CommunityConstant {
|
||||
@Autowired
|
||||
private EventProducer eventProducer;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 添加帖子(发帖)
|
||||
* @param title
|
||||
@ -71,6 +77,10 @@ public class DiscussPostController implements CommunityConstant {
|
||||
.setEntityId(discussPost.getId());
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
// 计算帖子分数
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
redisTemplate.opsForSet().add(redisKey, discussPost.getId());
|
||||
|
||||
return CommunityUtil.getJSONString(0, "发布成功");
|
||||
}
|
||||
|
||||
@ -156,6 +166,75 @@ public class DiscussPostController implements CommunityConstant {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 置顶帖子
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/top")
|
||||
@ResponseBody
|
||||
public String setTop(int id) {
|
||||
discussPostSerivce.updateType(id, 1);
|
||||
|
||||
// 触发发帖事件,通过消息队列将其存入 Elasticsearch 服务器
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_PUBLISH)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 加精帖子
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/wonderful")
|
||||
@ResponseBody
|
||||
public String setWonderful(int id) {
|
||||
discussPostSerivce.updateStatus(id, 1);
|
||||
|
||||
// 触发发帖事件,通过消息队列将其存入 Elasticsearch 服务器
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_PUBLISH)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
// 计算帖子分数
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
redisTemplate.opsForSet().add(redisKey, id);
|
||||
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除帖子
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/delete")
|
||||
@ResponseBody
|
||||
public String setDelete(int id) {
|
||||
discussPostSerivce.updateStatus(id, 2);
|
||||
|
||||
// 触发删帖事件,通过消息队列更新 Elasticsearch 服务器
|
||||
Event event = new Event()
|
||||
.setTopic(TOPIC_DELETE)
|
||||
.setUserId(hostHolder.getUser().getId())
|
||||
.setEntityType(ENTITY_TYPE_POST)
|
||||
.setEntityId(id);
|
||||
eventProducer.fireEvent(event);
|
||||
|
||||
return CommunityUtil.getJSONString(0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -11,6 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
@ -36,16 +37,17 @@ public class HomeController implements CommunityConstant {
|
||||
* 进入首页
|
||||
* @param model
|
||||
* @param page
|
||||
* @param orderMode 默认是 0(最新)
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/index")
|
||||
public String getIndexPage(Model model, Page page) {
|
||||
public String getIndexPage(Model model, Page page, @RequestParam(name = "orderMode", defaultValue = "0") int orderMode) {
|
||||
// 获取总页数
|
||||
page.setRows(discussPostSerivce.findDiscussPostRows(0));
|
||||
page.setPath("/index");
|
||||
page.setPath("/index?orderMode=" + orderMode);
|
||||
|
||||
// 分页查询
|
||||
List<DiscussPost> list = discussPostSerivce.findDiscussPosts(0, page.getOffset(), page.getLimit());
|
||||
List<DiscussPost> list = discussPostSerivce.findDiscussPosts(0, page.getOffset(), page.getLimit(), orderMode);
|
||||
// 封装帖子和该帖子对应的用户信息
|
||||
List<Map<String, Object>> discussPosts = new ArrayList<>();
|
||||
if (list != null) {
|
||||
@ -61,6 +63,7 @@ public class HomeController implements CommunityConstant {
|
||||
}
|
||||
}
|
||||
model.addAttribute("discussPosts", discussPosts);
|
||||
model.addAttribute("orderMode", orderMode);
|
||||
return "index";
|
||||
}
|
||||
|
||||
@ -73,4 +76,13 @@ public class HomeController implements CommunityConstant {
|
||||
return "/error/500";
|
||||
}
|
||||
|
||||
/**
|
||||
* 没有权限访问时的错误界面(也是 404)
|
||||
* @return
|
||||
*/
|
||||
@GetMapping("/denied")
|
||||
public String getDeniedPage() {
|
||||
return "/error/404";
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -9,7 +9,9 @@ import com.greate.community.service.LikeService;
|
||||
import com.greate.community.util.CommunityConstant;
|
||||
import com.greate.community.util.CommunityUtil;
|
||||
import com.greate.community.util.HostHolder;
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -32,6 +34,9 @@ public class LikeController implements CommunityConstant {
|
||||
@Autowired
|
||||
private EventProducer eventProducer;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
/**
|
||||
* 点赞
|
||||
* @param entityType
|
||||
@ -67,6 +72,12 @@ public class LikeController implements CommunityConstant {
|
||||
eventProducer.fireEvent(event);
|
||||
}
|
||||
|
||||
if (entityType == ENTITY_TYPE_POST) {
|
||||
// 计算帖子分数
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
redisTemplate.opsForSet().add(redisKey, postId);
|
||||
}
|
||||
|
||||
return CommunityUtil.getJSONString(0, null, map);
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@ -207,6 +208,7 @@ public class LoginController implements CommunityConstant {
|
||||
@GetMapping("/logout")
|
||||
public String logout(@CookieValue("ticket") String ticket) {
|
||||
userService.logout(ticket);
|
||||
SecurityContextHolder.clearContext();
|
||||
return "redirect:/login";
|
||||
}
|
||||
|
||||
|
@ -203,8 +203,9 @@ public class MessageController implements CommunityConstant {
|
||||
// 查询评论类通知
|
||||
Message message = messageService.findLatestNotice(user.getId(), TOPIC_COMMNET);
|
||||
// 封装通知需要的各种数据
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
if (message != null) {
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
|
||||
messageVO.put("message", message);
|
||||
|
||||
String content = HtmlUtils.htmlUnescape(message.getContent());
|
||||
@ -220,13 +221,15 @@ public class MessageController implements CommunityConstant {
|
||||
|
||||
int unread = messageService.findNoticeUnReadCount(user.getId(), TOPIC_COMMNET);
|
||||
messageVO.put("unread", unread);
|
||||
|
||||
model.addAttribute("commentNotice", messageVO);
|
||||
}
|
||||
model.addAttribute("commentNotice", messageVO);
|
||||
|
||||
// 查询点赞类通知
|
||||
message = messageService.findLatestNotice(user.getId(), TOPIC_LIKE);
|
||||
messageVO = new HashMap<>();
|
||||
if (message != null) {
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
|
||||
messageVO.put("message", message);
|
||||
|
||||
String content = HtmlUtils.htmlUnescape(message.getContent());
|
||||
@ -242,13 +245,15 @@ public class MessageController implements CommunityConstant {
|
||||
|
||||
int unread = messageService.findNoticeUnReadCount(user.getId(), TOPIC_LIKE);
|
||||
messageVO.put("unread", unread);
|
||||
|
||||
model.addAttribute("likeNotice", messageVO);
|
||||
}
|
||||
model.addAttribute("likeNotice", messageVO);
|
||||
|
||||
// 查询关注类通知
|
||||
message = messageService.findLatestNotice(user.getId(), TOPIC_FOLLOW);
|
||||
messageVO = new HashMap<>();
|
||||
if (message != null) {
|
||||
Map<String, Object> messageVO = new HashMap<>();
|
||||
|
||||
messageVO.put("message", message);
|
||||
|
||||
String content = HtmlUtils.htmlUnescape(message.getContent());
|
||||
@ -263,8 +268,9 @@ public class MessageController implements CommunityConstant {
|
||||
|
||||
int unread = messageService.findNoticeUnReadCount(user.getId(), TOPIC_FOLLOW);
|
||||
messageVO.put("unread", unread);
|
||||
|
||||
model.addAttribute("followNotice", messageVO);
|
||||
}
|
||||
model.addAttribute("followNotice", messageVO);
|
||||
|
||||
// 查询未读消息数量
|
||||
int letterUnreadCount = messageService.findLetterUnreadCount(user.getId(), null);
|
||||
|
@ -12,10 +12,7 @@ import org.springframework.stereotype.Controller;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
|
@ -0,0 +1,36 @@
|
||||
package com.greate.community.controller.interceptor;
|
||||
|
||||
import com.greate.community.entity.User;
|
||||
import com.greate.community.service.DataService;
|
||||
import com.greate.community.util.HostHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
public class DataInterceptor implements HandlerInterceptor {
|
||||
|
||||
@Autowired
|
||||
private DataService dataService;
|
||||
|
||||
@Autowired
|
||||
private HostHolder hostHolder;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 统计 UV
|
||||
String ip = request.getRemoteHost();
|
||||
dataService.recordUV(ip);
|
||||
|
||||
// 统计 DAU
|
||||
User user = hostHolder.getUser();
|
||||
if (user != null) {
|
||||
dataService.recordDAU(user.getId());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -6,6 +6,10 @@ import com.greate.community.service.UserService;
|
||||
import com.greate.community.util.CookieUtil;
|
||||
import com.greate.community.util.HostHolder;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.core.context.SecurityContextImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.ModelAndView;
|
||||
@ -44,6 +48,12 @@ public class LoginTicketInterceptor implements HandlerInterceptor {
|
||||
User user = userService.findUserById(loginTicket.getUserId());
|
||||
// 在本次请求中持有用户信息
|
||||
hostHolder.setUser(user);
|
||||
|
||||
// 构建用户认证的结果,并存入 SecurityContext, 以便于 Spring Security 进行授权
|
||||
Authentication authentication = new UsernamePasswordAuthenticationToken(
|
||||
user, user.getPassword(), userService.getAuthorities(user.getId())
|
||||
);
|
||||
SecurityContextHolder.setContext(new SecurityContextImpl(authentication));
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,5 +87,6 @@ public class LoginTicketInterceptor implements HandlerInterceptor {
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
hostHolder.clear();
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
}
|
||||
|
@ -16,9 +16,10 @@ public interface DiscussPostMapper {
|
||||
* 当传入的 userId != 0 时,查找该指定用户的帖子
|
||||
* @param offset 每页的起始索引
|
||||
* @param limit 每页显示多少条数据
|
||||
* @param orderMode 排行模式(若传入 1, 则按照热度来排序)
|
||||
* @return
|
||||
*/
|
||||
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit);
|
||||
List<DiscussPost> selectDiscussPosts(int userId, int offset, int limit, int orderMode);
|
||||
|
||||
/**
|
||||
* 查询讨论贴的个数
|
||||
@ -42,6 +43,35 @@ public interface DiscussPostMapper {
|
||||
*/
|
||||
DiscussPost selectDiscussPostById(int id);
|
||||
|
||||
// 修改评论数量
|
||||
/**
|
||||
* 修改评论数量
|
||||
* @param id
|
||||
* @param commentCount
|
||||
* @return
|
||||
*/
|
||||
int updateCommentCount(int id, int commentCount);
|
||||
|
||||
/**
|
||||
* 修改帖子类型:0-普通; 1-置顶;
|
||||
* @param id
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
int updateType(int id, int type);
|
||||
|
||||
/**
|
||||
* 修改帖子状态:0-正常; 1-精华; 2-拉黑;
|
||||
* @param id
|
||||
* @param status
|
||||
* @return
|
||||
*/
|
||||
int updateStatus(int id, int status);
|
||||
|
||||
/**
|
||||
* 修改帖子分数
|
||||
* @param id
|
||||
* @param score
|
||||
* @return
|
||||
*/
|
||||
int updateScore(int id, double score);
|
||||
}
|
||||
|
@ -95,4 +95,23 @@ public class EventConsumer implements CommunityConstant {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 消费删帖事件
|
||||
*/
|
||||
@KafkaListener(topics = {TOPIC_DELETE})
|
||||
public void handleDeleteMessage(ConsumerRecord record) {
|
||||
if (record == null || record.value() == null) {
|
||||
logger.error("消息的内容为空");
|
||||
return ;
|
||||
}
|
||||
Event event = JSONObject.parseObject(record.value().toString(), Event.class);
|
||||
if (event == null) {
|
||||
logger.error("消息格式错误");
|
||||
return ;
|
||||
}
|
||||
|
||||
elasticsearchService.deleteDiscusspost(event.getEntityId());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,102 @@
|
||||
package com.greate.community.quartz;
|
||||
|
||||
import com.greate.community.entity.DiscussPost;
|
||||
import com.greate.community.service.DiscussPostSerivce;
|
||||
import com.greate.community.service.ElasticsearchService;
|
||||
import com.greate.community.service.LikeService;
|
||||
import com.greate.community.util.CommunityConstant;
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import io.lettuce.core.RedisURI;
|
||||
import javafx.geometry.Pos;
|
||||
import org.quartz.Job;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.JobExecutionException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.data.redis.core.BoundSetOperations;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 帖子分数计算刷新
|
||||
*/
|
||||
public class PostScoreRefreshJob implements Job, CommunityConstant {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(PostScoreRefreshJob.class);
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
@Autowired
|
||||
private DiscussPostSerivce discussPostSerivce;
|
||||
|
||||
@Autowired
|
||||
private LikeService likeService;
|
||||
|
||||
@Autowired
|
||||
private ElasticsearchService elasticsearchService;
|
||||
|
||||
// Epoch 纪元
|
||||
private static final Date epoch;
|
||||
|
||||
static {
|
||||
try {
|
||||
epoch = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2014-01-01 00:00:00");
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException("初始化 Epoch 纪元失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
|
||||
String redisKey = RedisKeyUtil.getPostScoreKey();
|
||||
BoundSetOperations operations = redisTemplate.boundSetOps(redisKey);
|
||||
|
||||
if (operations.size() == 0) {
|
||||
logger.info("[任务取消] 没有需要刷新的帖子");
|
||||
return ;
|
||||
}
|
||||
|
||||
logger.info("[任务开始] 正在刷新帖子分数: " + operations.size());
|
||||
while (operations.size() > 0) {
|
||||
this.refresh((Integer) operations.pop());
|
||||
}
|
||||
logger.info("[任务结束] 帖子分数刷新完毕");
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新帖子分数
|
||||
* @param postId
|
||||
*/
|
||||
private void refresh(int postId) {
|
||||
DiscussPost post = discussPostSerivce.findDiscussPostById(postId);
|
||||
|
||||
if (post == null) {
|
||||
logger.error("该帖子不存在: id = " + postId);
|
||||
return ;
|
||||
}
|
||||
|
||||
// 是否加精
|
||||
boolean wonderful = post.getStatus() == 1;
|
||||
// 评论数量
|
||||
int commentCount = post.getCommentCount();
|
||||
// 点赞数量
|
||||
long likeCount = likeService.findEntityLikeCount(ENTITY_TYPE_POST, postId);
|
||||
|
||||
// 计算权重
|
||||
double w = (wonderful ? 75 : 0) + commentCount * 10 + likeCount * 2;
|
||||
// 分数 = 权重 + 发帖距离天数
|
||||
double score = Math.log10(Math.max(w, 1))
|
||||
+ (post.getCreateTime().getTime() - epoch.getTime()) / (1000 * 3600 * 24);
|
||||
// 更新帖子分数
|
||||
discussPostSerivce.updateScore(postId, score);
|
||||
// 同步搜索数据
|
||||
post.setScore(score);
|
||||
elasticsearchService.saveDiscusspost(post);
|
||||
|
||||
}
|
||||
}
|
108
src/main/java/com/greate/community/service/DataService.java
Normal file
108
src/main/java/com/greate/community/service/DataService.java
Normal file
@ -0,0 +1,108 @@
|
||||
package com.greate.community.service;
|
||||
|
||||
import com.greate.community.util.RedisKeyUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.data.redis.connection.RedisConnection;
|
||||
import org.springframework.data.redis.connection.RedisStringCommands;
|
||||
import org.springframework.data.redis.core.RedisCallback;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 网站数据统计(UV / DAU)
|
||||
*/
|
||||
@Service
|
||||
public class DataService {
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
private SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
|
||||
|
||||
/**
|
||||
* 将指定的 IP 计入当天的 UV
|
||||
* @param ip
|
||||
*/
|
||||
public void recordUV(String ip) {
|
||||
String redisKey = RedisKeyUtil.getUVKey(df.format(new Date()));
|
||||
redisTemplate.opsForHyperLogLog().add(redisKey, ip);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定日期范围内的 UV
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public long calculateUV(Date start, Date end) {
|
||||
if (start == null || end == null) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
|
||||
// 整理该日期范围内的 key
|
||||
List<String> keyList = new ArrayList<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(start);
|
||||
while (!calendar.getTime().after(end)) {
|
||||
String key = RedisKeyUtil.getUVKey(df.format(calendar.getTime()));
|
||||
keyList.add(key);
|
||||
calendar.add(Calendar.DATE, 1); // 加1天
|
||||
}
|
||||
|
||||
// 合并这些天的 UV
|
||||
String redisKey = RedisKeyUtil.getUVKey(df.format(start), df.format(end));
|
||||
redisTemplate.opsForHyperLogLog().union(redisKey, keyList.toArray());
|
||||
|
||||
// 返回统计结果
|
||||
return redisTemplate.opsForHyperLogLog().size(redisKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将指定的 IP 计入当天的 DAU
|
||||
* @param userId
|
||||
*/
|
||||
public void recordDAU(int userId) {
|
||||
String redisKey = RedisKeyUtil.getDAUKey(df.format(new Date()));
|
||||
redisTemplate.opsForValue().setBit(redisKey, userId, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 统计指定日期范围内的 DAU
|
||||
* @param start
|
||||
* @param end
|
||||
* @return
|
||||
*/
|
||||
public long calculateDAU(Date start, Date end) {
|
||||
if (start == null || end == null) {
|
||||
throw new IllegalArgumentException("参数不能为空");
|
||||
}
|
||||
|
||||
// 整理该日期范围内的 key
|
||||
List<byte[]> keyList = new ArrayList<>();
|
||||
Calendar calendar = Calendar.getInstance();
|
||||
calendar.setTime(start);
|
||||
while (!calendar.getTime().after(end)) {
|
||||
String key = RedisKeyUtil.getDAUKey(df.format(calendar.getTime()));
|
||||
keyList.add(key.getBytes());
|
||||
calendar.add(Calendar.DATE, 1); // 加1天
|
||||
}
|
||||
|
||||
// 进行 or 运算
|
||||
return (long) redisTemplate.execute(new RedisCallback() {
|
||||
@Override
|
||||
public Object doInRedis(RedisConnection redisConnection) throws DataAccessException {
|
||||
String redisKey = RedisKeyUtil.getDAUKey(df.format(start), df.format(end));
|
||||
redisConnection.bitOp(RedisStringCommands.BitOperation.OR,
|
||||
redisKey.getBytes(), keyList.toArray(new byte[0][0]));
|
||||
return redisConnection.bitCount(redisKey.getBytes());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -28,10 +28,11 @@ public class DiscussPostSerivce {
|
||||
* 当传入的 userId != 0 时,查找该指定用户的帖子
|
||||
* @param offset 每页的起始索引
|
||||
* @param limit 每页显示多少条数据
|
||||
* @param orderMode 排行模式(若传入 1, 则按照热度来排序)
|
||||
* @return
|
||||
*/
|
||||
public List<DiscussPost> findDiscussPosts (int userId, int offset, int limit) {
|
||||
return discussPostMapper.selectDiscussPosts(userId, offset, limit);
|
||||
public List<DiscussPost> findDiscussPosts (int userId, int offset, int limit, int orderMode) {
|
||||
return discussPostMapper.selectDiscussPosts(userId, offset, limit, orderMode);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -83,4 +84,34 @@ public class DiscussPostSerivce {
|
||||
public int updateCommentCount(int id, int commentCount) {
|
||||
return discussPostMapper.updateCommentCount(id, commentCount);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改帖子类型:0-普通; 1-置顶;
|
||||
* @param id
|
||||
* @param type
|
||||
* @return
|
||||
*/
|
||||
public int updateType(int id, int type) {
|
||||
return discussPostMapper.updateType(id, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改帖子状态:0-正常; 1-精华; 2-拉黑;
|
||||
* @param id
|
||||
* @param status
|
||||
* @return
|
||||
*/
|
||||
public int updateStatus(int id, int status) {
|
||||
return discussPostMapper.updateStatus(id, status);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改帖子分数
|
||||
* @param id
|
||||
* @param score
|
||||
* @return
|
||||
*/
|
||||
public int updateScore(int id, double score) {
|
||||
return discussPostMapper.updateScore(id, score);
|
||||
}
|
||||
}
|
||||
|
@ -12,15 +12,13 @@ import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.ui.Model;
|
||||
import org.thymeleaf.TemplateEngine;
|
||||
import org.thymeleaf.context.Context;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Random;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
@ -302,4 +300,29 @@ public class UserService implements CommunityConstant {
|
||||
redisTemplate.delete(redisKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个用户的权限
|
||||
* @param userId
|
||||
* @return
|
||||
*/
|
||||
public Collection<? extends GrantedAuthority> getAuthorities(int userId) {
|
||||
User user = this.findUserById(userId);
|
||||
List<GrantedAuthority> list = new ArrayList<>();
|
||||
list.add(new GrantedAuthority() {
|
||||
@Override
|
||||
public String getAuthority() {
|
||||
switch (user.getType()) {
|
||||
case 1:
|
||||
return AUTHORITY_ADMIN;
|
||||
case 2:
|
||||
return AUTHORITY_MODERATOR;
|
||||
default:
|
||||
return AUTHORITY_USER;
|
||||
}
|
||||
}
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -41,7 +41,19 @@ public interface CommunityConstant {
|
||||
// Kafka 主题:发帖
|
||||
String TOPIC_PUBLISH = "publish";
|
||||
|
||||
// Kafka 主题:删帖
|
||||
String TOPIC_DELETE = "delete";
|
||||
|
||||
// 系统用户的 id
|
||||
int SYSTEM_USER_ID = 1;
|
||||
|
||||
// 权限:普通用户
|
||||
String AUTHORITY_USER = "user";
|
||||
|
||||
// 权限:管理员
|
||||
String AUTHORITY_ADMIN = "admin";
|
||||
|
||||
// 权限:版主
|
||||
String AUTHORITY_MODERATOR = "moderator";
|
||||
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ public class RedisKeyUtil {
|
||||
private static final String PREFIX_KAPTCHA = "kaptcha"; // 验证码
|
||||
private static final String PREFIX_TICKET = "ticket"; // 登录凭证
|
||||
private static final String PREFIX_USER = "user"; // 登录凭证
|
||||
private static final String PREFIX_UV = "uv"; // 独立访客
|
||||
private static final String PREFIX_DAU = "dau"; // 日活跃用户
|
||||
private static final String PREFIX_POST = "post"; // 用于统计帖子分数
|
||||
|
||||
|
||||
/**
|
||||
@ -87,4 +90,49 @@ public class RedisKeyUtil {
|
||||
return PREFIX_USER + SPLIT + userId;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单日 UV
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static String getUVKey(String date) {
|
||||
return PREFIX_UV + SPLIT + date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 区间 UV
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
public static String getUVKey(String startDate, String endDate) {
|
||||
return PREFIX_UV + SPLIT + startDate + SPLIT + endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单日 DAU
|
||||
* @param date
|
||||
* @return
|
||||
*/
|
||||
public static String getDAUKey(String date) {
|
||||
return PREFIX_DAU + SPLIT + date;
|
||||
}
|
||||
|
||||
/**
|
||||
* 区间 DAU
|
||||
* @param startDate
|
||||
* @param endDate
|
||||
* @return
|
||||
*/
|
||||
public static String getDAUKey(String startDate, String endDate) {
|
||||
return PREFIX_DAU + SPLIT + startDate + SPLIT + endDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* 帖子分数
|
||||
* @return
|
||||
*/
|
||||
public static String getPostScoreKey() {
|
||||
return PREFIX_POST + SPLIT + "score";
|
||||
}
|
||||
}
|
||||
|
@ -50,3 +50,13 @@ spring.kafka.consumer.auto-commit-interval = 3000
|
||||
# 该字段见 Elasticsearch 安装包中的 elasticsearch.yml,可自行修改
|
||||
spring.data.elasticsearch.cluster-name = community
|
||||
spring.data.elasticsearch.cluster-nodes = 127.0.0.1:9300
|
||||
|
||||
# Quartz
|
||||
spring.quartz.job-store-type = jdbc
|
||||
spring.quartz.scheduler-name = communityScheduler
|
||||
spring.quartz.properties.org.quartz.scheduler.instanceId = AUTO
|
||||
spring.quartz.properties.org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
|
||||
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
|
||||
spring.quartz.properties.org.quartz.jobStore.isClustered = true
|
||||
spring.quartz.properties.org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
|
||||
spring.quartz.properties.org.quartz.threadPool.threadCount = 5
|
@ -21,7 +21,12 @@
|
||||
<if test = "userId!=0">
|
||||
and user_id = #{userId}
|
||||
</if>
|
||||
order by type desc, create_time desc
|
||||
<if test = "orderMode == 0">
|
||||
order by type desc, create_time desc
|
||||
</if>
|
||||
<if test = "orderMode == 1">
|
||||
order by type desc, score desc, create_time desc
|
||||
</if>
|
||||
limit #{offset}, #{limit}
|
||||
</select>
|
||||
|
||||
@ -48,11 +53,31 @@
|
||||
where id = #{id}
|
||||
</select>
|
||||
|
||||
<!--修改帖子的评论数量-->
|
||||
<update id="updateCommentCount">
|
||||
update discuss_post
|
||||
set comment_count = #{commentCount}
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<!--修改帖子类型:0-普通; 1-置顶;-->
|
||||
<update id="updateType">
|
||||
update discuss_post
|
||||
set type = #{type}
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<!--修改帖子状态:0-正常; 1-精华; 2-拉黑;-->
|
||||
<update id="updateStatus">
|
||||
update discuss_post
|
||||
set status = #{status}
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
<!--修改帖子分数-->
|
||||
<update id="updateScore">
|
||||
update discuss_post
|
||||
set score = #{score}
|
||||
where id = #{id}
|
||||
</update>
|
||||
|
||||
</mapper>
|
@ -1,3 +1,10 @@
|
||||
$(function(){
|
||||
$("#topBtn").click(setTop);
|
||||
$("#wonderfulBtn").click(setWonderful);
|
||||
$("#deleteBtn").click(setDelete);
|
||||
});
|
||||
|
||||
// 点赞
|
||||
function like(btn, entityType, entityId, entityUserId, postId) {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/like",
|
||||
@ -15,3 +22,57 @@ function like(btn, entityType, entityId, entityUserId, postId) {
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 置顶
|
||||
function setTop() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/top",
|
||||
{"id":$("#postId").val()},
|
||||
function (data) {
|
||||
data = $.parseJSON(data);
|
||||
if (data.code == 0) {
|
||||
// 置顶成功后,将置顶按钮设置为不可用
|
||||
$("#topBtn").attr("disabled", "disable")
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 加精
|
||||
function setWonderful() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/wonderful",
|
||||
{"id":$("#postId").val()},
|
||||
function (data) {
|
||||
data = $.parseJSON(data);
|
||||
if (data.code == 0) {
|
||||
// 加精成功后,将加精按钮设置为不可用
|
||||
$("#wonderfulBtn").attr("disabled", "disable")
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// 删除
|
||||
function setDelete() {
|
||||
$.post(
|
||||
CONTEXT_PATH + "/discuss/delete",
|
||||
{"id":$("#postId").val()},
|
||||
function (data) {
|
||||
data = $.parseJSON(data);
|
||||
if (data.code == 0) {
|
||||
// 删除成功后,跳转到首页
|
||||
location.href = CONTEXT_PATH + "/index";
|
||||
}
|
||||
else {
|
||||
alert(data.msg);
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extra/spring-security">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
@ -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="@{/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>
|
||||
<span class="dropdown-item text-center text-secondary" th:utext="${loginUser.username}"></span>
|
||||
@ -71,10 +72,10 @@
|
||||
<!-- 筛选条件 -->
|
||||
<ul class="nav nav-tabs mb-3">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" href="#"><i class="bi bi-lightning"></i> 最新</a>
|
||||
<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 class="nav-link" href="#"><i class="bi bi-hand-thumbs-up"></i> 最热</a>
|
||||
<a th:class="|nav-link ${orderMode==1 ? 'active' : ''}|" th:href="@{/index(orderMode=1)}"><i class="bi bi-hand-thumbs-up"></i> 最热</a>
|
||||
</li>
|
||||
</ul>
|
||||
<button type="button" class="btn btn-primary btn-sm position-absolute rt-0"
|
||||
@ -131,8 +132,10 @@
|
||||
<div class="media-body">
|
||||
<h6 class="mt-0 mb-3">
|
||||
<a th:href="@{|/discuss/detail/${map.post.id}|}" th:utext="${map.post.title}"></a>
|
||||
<span class="badge badge-secondary bg-primary" th:if="${map.post.type==1}">置顶</span>
|
||||
<span class="badge badge-secondary bg-danger" th:if="${map.post.status==1}">精华</span>
|
||||
<span class="badge badge-secondary bg-danger" th:if="${map.post.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.post.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="${map.user.username}"></u> 发布于 <b th:text="${#dates.format(map.post.createTime,'yyyy-MM-dd HH:mm:ss')}"></b>
|
||||
|
@ -1,92 +1,52 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<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" href="https://static.nowcoder.com/images/logo_87_87.png"/>
|
||||
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="../../css/global.css" />
|
||||
<title>牛客网-数据统计</title>
|
||||
<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">
|
||||
<div class="container">
|
||||
<!-- 导航 -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark">
|
||||
<!-- logo -->
|
||||
<a class="navbar-brand" href="#"></a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<!-- 功能 -->
|
||||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item ml-3 btn-group-vertical">
|
||||
<a class="nav-link" href="../../index.html">首页</a>
|
||||
</li>
|
||||
<li class="nav-item ml-3 btn-group-vertical">
|
||||
<a class="nav-link position-relative" href="../letter.html">消息<span class="badge badge-danger">12</span></a>
|
||||
</li>
|
||||
<li class="nav-item ml-3 btn-group-vertical">
|
||||
<a class="nav-link" href="../register.html">注册</a>
|
||||
</li>
|
||||
<li class="nav-item ml-3 btn-group-vertical">
|
||||
<a class="nav-link" href="../login.html">登录</a>
|
||||
</li>
|
||||
<li class="nav-item ml-3 btn-group-vertical dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<img src="http://images.nowcoder.com/head/1t.png" class="rounded-circle" style="width:30px;"/>
|
||||
</a>
|
||||
<div class="dropdown-menu" aria-labelledby="navbarDropdown">
|
||||
<a class="dropdown-item text-center" href="../profile.html">个人主页</a>
|
||||
<a class="dropdown-item text-center" href="../setting.html">账号设置</a>
|
||||
<a class="dropdown-item text-center" href="../login.html">退出登录</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<span class="dropdown-item text-center text-secondary">nowcoder</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<!-- 搜索 -->
|
||||
<form class="form-inline my-2 my-lg-0" action="../site/search.html">
|
||||
<input class="form-control mr-sm-2" type="search" aria-label="Search" />
|
||||
<button class="btn btn-outline-light my-2 my-sm-0" type="submit">搜索</button>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
<header class="bg-dark sticky-top" th:replace="index::header"></header>
|
||||
|
||||
<!-- 内容 -->
|
||||
<div class="main">
|
||||
<!-- 网站UV -->
|
||||
<div class="container pl-5 pr-5 pt-3 pb-3 mt-3">
|
||||
<h6 class="mt-3"><b class="square"></b> 网站 UV</h6>
|
||||
<form class="form-inline mt-3">
|
||||
<input type="date" class="form-control" required/>
|
||||
<input type="date" class="form-control ml-3" required/>
|
||||
<button type="button" class="btn btn-primary ml-3">开始统计</button>
|
||||
<form class="form-inline mt-3" method="post" th:action="@{/data/uv}">
|
||||
<input type="date" class="form-control" required name="start"
|
||||
th:value="${#dates.format(uvStartDate, 'yyyy-MM-dd')}" />
|
||||
<input type="date" class="form-control ml-3" required name="end"
|
||||
th:value="${#dates.format(uvEndDate, 'yyyy-MM-dd')}" />
|
||||
<button type="submit" class="btn btn-primary ml-3">开始统计</button>
|
||||
</form>
|
||||
<ul class="list-group mt-3 mb-3">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
统计结果
|
||||
<span class="badge badge-primary badge-danger font-size-14">0</span>
|
||||
<span class="badge badge-primary badge-danger font-size-14" th:text="${uvResult}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- 活跃用户 -->
|
||||
<div class="container pl-5 pr-5 pt-3 pb-3 mt-4">
|
||||
<h6 class="mt-3"><b class="square"></b> 活跃用户</h6>
|
||||
<form class="form-inline mt-3">
|
||||
<input type="date" class="form-control" required/>
|
||||
<input type="date" class="form-control ml-3" required/>
|
||||
<button type="button" class="btn btn-primary ml-3">开始统计</button>
|
||||
<form class="form-inline mt-3" method="post" th:action="@{/data/dau}">
|
||||
<input type="date" class="form-control" required name="start"
|
||||
th:value="${#dates.format(dauStartDate, 'yyyy-MM-dd')}" />
|
||||
<input type="date" class="form-control ml-3" required name="end"
|
||||
th:value="${#dates.format(dauEndDate, 'yyyy-MM-dd')}" />
|
||||
<button type="submit" class="btn btn-primary ml-3">开始统计</button>
|
||||
</form>
|
||||
<ul class="list-group mt-3 mb-3">
|
||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||
统计结果
|
||||
<span class="badge badge-primary badge-danger font-size-14">0</span>
|
||||
<span class="badge badge-primary badge-danger font-size-14" th:text="${dauResult}"></span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@ -155,9 +115,9 @@
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<script src="https://code.jquery.com/jquery-3.3.1.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" crossorigin="anonymous"></script>
|
||||
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" crossorigin="anonymous"></script>
|
||||
<script src="../../js/global.js"></script>
|
||||
<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>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<!doctype html>
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org">
|
||||
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extra/spring-security">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
@ -25,9 +25,13 @@
|
||||
<i class="bi bi-award" style="color: rgb(119, 84, 223)"></i>
|
||||
<span th:utext="${post.title}"></span>
|
||||
<div class="float-right">
|
||||
<button type="button" class="btn btn-danger btn-sm">置顶</button>
|
||||
<button type="button" class="btn btn-danger btn-sm">加精</button>
|
||||
<button type="button" class="btn btn-danger btn-sm">删除</button>
|
||||
<input type="hidden" id="postId" th:value="${post.id}">
|
||||
<button type="button" class="btn btn-danger btn-sm" id="topBtn"
|
||||
th:disabled="${post.type == 1}" sec:authorize="hasAnyAuthority('moderator')">置顶</button>
|
||||
<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>
|
||||
</div>
|
||||
</h5>
|
||||
<!-- 作者 -->
|
||||
|
@ -37,7 +37,7 @@
|
||||
<!-- 通知列表 -->
|
||||
<ul class="list-unstyled">
|
||||
<!--评论类通知-->
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${commentNotice.message!=null}">
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${commentNotice!=null}">
|
||||
<span class="badge badge-danger" th:text="${commentNotice.unread!=0 ? commentNotice.unread : ''}"></span>
|
||||
<img src="http://static.nowcoder.com/images/head/reply.png" class="mr-4 user-header" alt="通知图标">
|
||||
<div class="media-body">
|
||||
@ -61,7 +61,7 @@
|
||||
</div>
|
||||
</li>
|
||||
<!--点赞类通知-->
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${likeNotice.message!=null}">
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${likeNotice!=null}">
|
||||
<span class="badge badge-danger" th:text="${likeNotice.unread!=0 ? likeNotice.unread : ''}"></span>
|
||||
<img src="http://static.nowcoder.com/images/head/like.png" class="mr-4 user-header" alt="通知图标">
|
||||
<div class="media-body">
|
||||
@ -84,7 +84,7 @@
|
||||
</div>
|
||||
</li>
|
||||
<!--关注类通知-->
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${followNotice.message!=null}">
|
||||
<li class="media pb-3 pt-3 mb-3 border-bottom position-relative" th:if="${followNotice!=null}">
|
||||
<span class="badge badge-danger" th:text="${followNotice.unread!=0 ? followNotice.unread : ''}"></span>
|
||||
<img src="http://static.nowcoder.com/images/head/follow.png" class="mr-4 user-header" alt="通知图标">
|
||||
<div class="media-body">
|
||||
|
@ -62,15 +62,15 @@ public class ElasticsearchTests {
|
||||
*/
|
||||
@Test
|
||||
public void testInsetList() {
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(101, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(102, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(103, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(111, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(112, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(131, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(132, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(133, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(134, 0, 100));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(101, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(102, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(103, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(111, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(112, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(131, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(132, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(133, 0, 100, 0));
|
||||
discussPostRepository.saveAll(discussPostMapper.selectDiscussPosts(134, 0, 100, 0));
|
||||
}
|
||||
|
||||
/**
|
||||
|
30
src/test/java/com/greate/community/QuartzTests.java
Normal file
30
src/test/java/com/greate/community/QuartzTests.java
Normal file
@ -0,0 +1,30 @@
|
||||
package com.greate.community;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.quartz.JobKey;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@ContextConfiguration(classes = CommunityApplication.class)
|
||||
@SpringBootTest
|
||||
public class QuartzTests {
|
||||
|
||||
@Autowired
|
||||
private Scheduler scheduler;
|
||||
|
||||
@Test
|
||||
public void deleteJob(){
|
||||
try {
|
||||
boolean result = scheduler.deleteJob(new JobKey("", ""));
|
||||
System.out.println(result);
|
||||
} catch (SchedulerException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
BIN
upload/5d92e80eecab4f1aa5cf5027bdf1a0f8.png
Normal file
BIN
upload/5d92e80eecab4f1aa5cf5027bdf1a0f8.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 7.9 KiB |
BIN
upload/affa0bb05970416592bfadc698389f7d.PNG
Normal file
BIN
upload/affa0bb05970416592bfadc698389f7d.PNG
Normal file
Binary file not shown.
After Width: | Height: | Size: 339 KiB |
BIN
upload/e75f7c8c438c40228fe0389d3780a226.jpg
Normal file
BIN
upload/e75f7c8c438c40228fe0389d3780a226.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
Loading…
Reference in New Issue
Block a user