Merge remote-tracking branch 'origin/lucene-dev' into lucene-dev
# Conflicts: # src/main/java/com/rymcu/forest/web/api/common/CommonApiController.java
This commit is contained in:
commit
35075e62c0
310
README.md
310
README.md
@ -1,5 +1,5 @@
|
|||||||
# forest
|
# forest
|
||||||
|
![forest](src/main/resources/static/logo_size.jpg)
|
||||||
下一代的知识社区系统,为未来而建
|
下一代的知识社区系统,为未来而建
|
||||||
|
|
||||||
## 💡 简介
|
## 💡 简介
|
||||||
@ -8,246 +8,74 @@ forest([ˈfôrəst],n.森林)是一款现代化的知识社区项目,使
|
|||||||
|
|
||||||
## ⚡ 动机
|
## ⚡ 动机
|
||||||
|
|
||||||
在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/RYMCU-J) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。
|
在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/RYMCU-J) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。 forest
|
||||||
forest 在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony) 和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。
|
在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony)
|
||||||
|
和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。
|
||||||
|
|
||||||
## ✨ 特性
|
## ✨ 特性
|
||||||
|
|
||||||
```
|
- 内容编辑器
|
||||||
内容编辑器
|
- Markdown(GFM)
|
||||||
Markdown(GFM)
|
- emoji
|
||||||
Emoji
|
- 上传文件
|
||||||
上传文件
|
- 图片
|
||||||
图片
|
- 文件
|
||||||
文件
|
- 单独渲染 MP3 文件
|
||||||
单独渲染 MP3
|
- 单独渲染视频文件
|
||||||
单独渲染视频
|
- 剪切板处理
|
||||||
剪贴板处理
|
- 粘贴内容处理为 Markdown
|
||||||
粘贴内容处理为 Markdown
|
- 粘贴图片自动重新上传
|
||||||
粘贴图片自动重新上传
|
- 数学公式(LaTeX)、流程图支持
|
||||||
数学公式(LaTeX)、流程图支持
|
- 工具栏
|
||||||
快捷键支持
|
- 表情
|
||||||
工具栏
|
- 粗体
|
||||||
表情
|
- 斜体
|
||||||
粗体
|
- 引用
|
||||||
斜体
|
- 无序列表
|
||||||
引用
|
- 有序列表
|
||||||
无序列表
|
- 链接
|
||||||
有序列表
|
- 上传
|
||||||
链接
|
- 预览
|
||||||
上传
|
- 全屏
|
||||||
预览
|
- 编辑模式
|
||||||
全屏
|
- 传统的 Markdown 分屏编辑预览
|
||||||
编辑模式
|
- 保留 Markdown 标记符的即时渲染
|
||||||
传统的 Markdown 分屏编辑预览
|
- 类富文本编辑器的所见即所得
|
||||||
保留 Markdown 标记符的即时渲染
|
- 注册
|
||||||
类富文本编辑器的所见即所得
|
- 用户名
|
||||||
注册
|
- 邮箱
|
||||||
用户名
|
- 验证码
|
||||||
Email
|
- 登录
|
||||||
验证码
|
- 账户(用户名/邮箱)
|
||||||
邮件验证
|
- 密码
|
||||||
新手向导
|
- 忘记密码
|
||||||
上传头像
|
- 邮箱
|
||||||
关注标签
|
- 邮箱验证
|
||||||
关注用户
|
- 发帖
|
||||||
帮助指引
|
- 帖子类型
|
||||||
登录
|
- 普通帖子
|
||||||
账户(用户名/Email)
|
- 标题
|
||||||
密码
|
- 正文
|
||||||
忘记密码
|
- 内容编辑器
|
||||||
Email
|
- 标签
|
||||||
验证码
|
- 使用已有(选择、自动完成)或创建
|
||||||
发帖
|
- 默认“待分类”
|
||||||
帖子类型
|
- 发布后
|
||||||
普通帖子
|
- 可更新
|
||||||
标题
|
- 可删除
|
||||||
正文
|
- 回帖
|
||||||
内容编辑器
|
- 内容编辑器
|
||||||
本地存储
|
- 回复(回复针对回帖)
|
||||||
标签
|
- 货币
|
||||||
使用已有(选择、自动完成)或创建
|
- 货币规则
|
||||||
过滤
|
- 浏览贴子
|
||||||
黑白名单
|
- 编辑自己的帖子
|
||||||
规范化
|
- 发布时间/浏览数/标签
|
||||||
默认“待分类”
|
- 分享
|
||||||
发布后
|
- 微信
|
||||||
可更新
|
- 分享链接(带用户标识)
|
||||||
可删除
|
|
||||||
回帖
|
|
||||||
内容编辑器
|
|
||||||
本地存储
|
|
||||||
回复(回复针对回帖)
|
|
||||||
货币
|
|
||||||
货币规则
|
|
||||||
浏览帖子
|
|
||||||
实时热度
|
|
||||||
编辑自己的帖子
|
|
||||||
发布时间/浏览数/回帖数/标签
|
|
||||||
上一篇/下一篇
|
|
||||||
分享
|
|
||||||
微信
|
|
||||||
QQ
|
|
||||||
分享链接(带用户标识)
|
|
||||||
相关帖子
|
|
||||||
缩略摘要
|
|
||||||
帖子列表
|
|
||||||
专题
|
|
||||||
相关标签
|
|
||||||
最新
|
|
||||||
优选
|
|
||||||
搜索
|
|
||||||
标签
|
|
||||||
相关标签
|
|
||||||
创建者
|
|
||||||
贡献者
|
|
||||||
关注/引用/回帖数
|
|
||||||
所属专题
|
|
||||||
关注
|
|
||||||
排序
|
|
||||||
默认(按发布时间降序)
|
|
||||||
热议(按回帖数降序)
|
|
||||||
好评(按评分降序)
|
|
||||||
最近回帖(按最近回帖时间降序)
|
|
||||||
首图
|
|
||||||
实时热度
|
|
||||||
最新回复
|
|
||||||
回帖数
|
|
||||||
创建时间
|
|
||||||
后台管理
|
|
||||||
后台首页
|
|
||||||
数据统计
|
|
||||||
当前在线
|
|
||||||
会员在线
|
|
||||||
最高在线
|
|
||||||
会员
|
|
||||||
帖子
|
|
||||||
专题
|
|
||||||
标签
|
|
||||||
回帖
|
|
||||||
用户管理
|
|
||||||
按用户名/邮件搜索
|
|
||||||
添加新用户
|
|
||||||
用户数据维护
|
|
||||||
各字段数据
|
|
||||||
用户状态
|
|
||||||
正常
|
|
||||||
未验证
|
|
||||||
限制登录
|
|
||||||
封禁
|
|
||||||
高级更新
|
|
||||||
用户名
|
|
||||||
邮箱地址
|
|
||||||
帖子管理
|
|
||||||
按 id 搜索帖子
|
|
||||||
重建所有帖子搜索索引
|
|
||||||
添加新帖
|
|
||||||
帖子数据维护
|
|
||||||
锁定帖子
|
|
||||||
删除帖子
|
|
||||||
专题管理
|
|
||||||
按名称搜索专题
|
|
||||||
添加专题
|
|
||||||
专题数据维护
|
|
||||||
添加/移除相关标签
|
|
||||||
名称
|
|
||||||
URI
|
|
||||||
描述
|
|
||||||
图标
|
|
||||||
是否用于导航
|
|
||||||
状态
|
|
||||||
CSS
|
|
||||||
SEO
|
|
||||||
title
|
|
||||||
keywords
|
|
||||||
description
|
|
||||||
删除专题
|
|
||||||
标签管理
|
|
||||||
按名称搜索标签
|
|
||||||
添加标签
|
|
||||||
标签数据维护
|
|
||||||
名称
|
|
||||||
URI
|
|
||||||
描述
|
|
||||||
图标
|
|
||||||
状态
|
|
||||||
CSS
|
|
||||||
SEO
|
|
||||||
title
|
|
||||||
keywords
|
|
||||||
description
|
|
||||||
角色管理
|
|
||||||
内建角色
|
|
||||||
管理员
|
|
||||||
社区管理员
|
|
||||||
作者
|
|
||||||
普通用户
|
|
||||||
创建角色
|
|
||||||
功能权限
|
|
||||||
浏览统计
|
|
||||||
实时统计
|
|
||||||
会员
|
|
||||||
帖子
|
|
||||||
专题
|
|
||||||
标签
|
|
||||||
回帖
|
|
||||||
数据统计
|
|
||||||
最近 30 天
|
|
||||||
历史
|
|
||||||
新发贴数
|
|
||||||
新用户数
|
|
||||||
消息通知
|
|
||||||
消息数
|
|
||||||
标记已读
|
|
||||||
消息类别
|
|
||||||
收到的回帖
|
|
||||||
收到的回复
|
|
||||||
收到的评论
|
|
||||||
提及我的
|
|
||||||
关注
|
|
||||||
我关注的
|
|
||||||
关注的用户发帖
|
|
||||||
个人主页
|
|
||||||
用户统计数据
|
|
||||||
积分
|
|
||||||
关注标签
|
|
||||||
收藏帖子
|
|
||||||
关注者
|
|
||||||
关注用户
|
|
||||||
站点连接
|
|
||||||
首页
|
|
||||||
专题、发帖、通知、个人等入口
|
|
||||||
专题导航列表
|
|
||||||
对搜索引擎爬虫友好
|
|
||||||
用户设置
|
|
||||||
基本信息
|
|
||||||
昵称
|
|
||||||
URL
|
|
||||||
个性签名
|
|
||||||
个人主页背景图
|
|
||||||
个人卡片背景图
|
|
||||||
站点连接
|
|
||||||
GitHub
|
|
||||||
微博
|
|
||||||
QQ
|
|
||||||
微信
|
|
||||||
头像
|
|
||||||
账号
|
|
||||||
绑定邮箱
|
|
||||||
更新密码
|
|
||||||
更新用户名
|
|
||||||
永久停用账号
|
|
||||||
钱包
|
|
||||||
交易记录
|
|
||||||
帮助
|
|
||||||
使用入门
|
|
||||||
基础知识
|
|
||||||
Markdown 教程
|
|
||||||
评论
|
|
||||||
发布评论
|
|
||||||
```
|
|
||||||
|
|
||||||
## 报告缺陷
|
## 报告缺陷
|
||||||
|
|
||||||
> 社区系统可能存在一些潜在的缺陷,大家如果有空的话可以帮助我们一起解决。
|
> 社区系统可能存在一些潜在的缺陷,大家如果有空的话可以帮助我们一起解决。
|
||||||
|
|
||||||
@ -260,4 +88,8 @@ forest 在很多方面受到了 [Symphony](https://github.com/88250/symphony)
|
|||||||
|
|
||||||
欢迎对社区提出功能特性方面的建议,我们一起讨论,如果有可能我们会尽快实现。
|
欢迎对社区提出功能特性方面的建议,我们一起讨论,如果有可能我们会尽快实现。
|
||||||
|
|
||||||
在提功能建议前可以先看一下 [计划表](https://rymcu.com/article/29) ,避免重复提议
|
在提功能建议前可以先看一下 [计划表](https://rymcu.com/article/29) ,避免重复提议
|
||||||
|
|
||||||
|
## 鸣谢
|
||||||
|
- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶
|
||||||
|
![JetBrains](src/main/resources/static/jetbrains.png)
|
17
pom.xml
17
pom.xml
@ -89,19 +89,19 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.pagehelper</groupId>
|
<groupId>com.github.pagehelper</groupId>
|
||||||
<artifactId>pagehelper</artifactId>
|
<artifactId>pagehelper</artifactId>
|
||||||
<version>5.1.10</version>
|
<version>5.2.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- fastjson -->
|
<!-- fastjson -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alibaba</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>fastjson</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>1.2.67</version>
|
<version>1.2.76</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- shiro权限控制框架 -->
|
<!-- shiro权限控制框架 -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.apache.shiro</groupId>
|
<groupId>org.apache.shiro</groupId>
|
||||||
<artifactId>shiro-spring</artifactId>
|
<artifactId>shiro-spring</artifactId>
|
||||||
<version>1.4.1</version>
|
<version>1.7.1</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- shiro-redis -->
|
<!-- shiro-redis -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@ -173,7 +173,7 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.binarywang</groupId>
|
<groupId>com.github.binarywang</groupId>
|
||||||
<artifactId>weixin-java-open</artifactId>
|
<artifactId>weixin-java-open</artifactId>
|
||||||
<version>3.9.0</version>
|
<version>4.0.0</version>
|
||||||
<exclusions>
|
<exclusions>
|
||||||
<exclusion>
|
<exclusion>
|
||||||
<groupId>commons-codec</groupId>
|
<groupId>commons-codec</groupId>
|
||||||
@ -183,8 +183,17 @@
|
|||||||
<groupId>commons-io</groupId>
|
<groupId>commons-io</groupId>
|
||||||
<artifactId>commons-io</artifactId>
|
<artifactId>commons-io</artifactId>
|
||||||
</exclusion>
|
</exclusion>
|
||||||
|
<exclusion>
|
||||||
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
|
<artifactId>xstream</artifactId>
|
||||||
|
</exclusion>
|
||||||
</exclusions>
|
</exclusions>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.thoughtworks.xstream</groupId>
|
||||||
|
<artifactId>xstream</artifactId>
|
||||||
|
<version>1.4.16</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.jedis-lock</groupId>
|
<groupId>com.github.jedis-lock</groupId>
|
||||||
<artifactId>jedis-lock</artifactId>
|
<artifactId>jedis-lock</artifactId>
|
||||||
|
@ -3,6 +3,9 @@ package com.rymcu.forest;
|
|||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
public class ForestApplication {
|
public class ForestApplication {
|
||||||
|
|
||||||
|
@ -2,9 +2,10 @@ package com.rymcu.forest.answer;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
||||||
import com.rymcu.forest.dto.AnswerDTO;
|
import com.rymcu.forest.dto.AnswerDTO;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
import com.rymcu.forest.util.HttpUtils;
|
import com.rymcu.forest.util.HttpUtils;
|
||||||
import com.rymcu.forest.util.UserUtils;
|
import com.rymcu.forest.util.UserUtils;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
@ -30,6 +31,7 @@ public class AnswerController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/answer")
|
@PostMapping("/answer")
|
||||||
|
@TransactionLogger(transactionType = TransactionEnum.Answer)
|
||||||
public GlobalResult answer(@RequestBody AnswerDTO answerDTO) throws BaseApiException {
|
public GlobalResult answer(@RequestBody AnswerDTO answerDTO) throws BaseApiException {
|
||||||
User user = UserUtils.getCurrentUserByToken();
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
Map params = new HashMap<>(3);
|
Map params = new HashMap<>(3);
|
||||||
|
@ -2,8 +2,10 @@ package com.rymcu.forest.config;
|
|||||||
|
|
||||||
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
|
import com.alibaba.fastjson.support.spring.FastJsonJsonView;
|
||||||
import com.rymcu.forest.core.exception.ServiceException;
|
import com.rymcu.forest.core.exception.ServiceException;
|
||||||
|
import com.rymcu.forest.core.exception.TransactionException;
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.ResultCode;
|
import com.rymcu.forest.core.result.ResultCode;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
import com.rymcu.forest.web.api.exception.BaseApiException;
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
import org.apache.shiro.authz.UnauthenticatedException;
|
import org.apache.shiro.authz.UnauthenticatedException;
|
||||||
import org.apache.shiro.authz.UnauthorizedException;
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
@ -25,7 +27,7 @@ import java.util.Map;
|
|||||||
* 全局异常处理器
|
* 全局异常处理器
|
||||||
*
|
*
|
||||||
* @author ronger
|
* @author ronger
|
||||||
* */
|
*/
|
||||||
@RestControllerAdvice
|
@RestControllerAdvice
|
||||||
public class BaseExceptionHandler {
|
public class BaseExceptionHandler {
|
||||||
|
|
||||||
@ -33,10 +35,10 @@ public class BaseExceptionHandler {
|
|||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){
|
public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
|
||||||
if(isAjax(request)){
|
if (isAjax(request)) {
|
||||||
GlobalResult result = new GlobalResult();
|
GlobalResult result = new GlobalResult();
|
||||||
if (ex instanceof BaseApiException){
|
if (ex instanceof BaseApiException) {
|
||||||
result.setCode(401);
|
result.setCode(401);
|
||||||
result.setMessage("用户未登录");
|
result.setMessage("用户未登录");
|
||||||
logger.info("用户未登录");
|
logger.info("用户未登录");
|
||||||
@ -48,7 +50,7 @@ public class BaseExceptionHandler {
|
|||||||
result.setCode(1000002);
|
result.setCode(1000002);
|
||||||
result.setMessage("用户无权限");
|
result.setMessage("用户无权限");
|
||||||
logger.info("用户无权限");
|
logger.info("用户无权限");
|
||||||
}else if (ex instanceof ServiceException) {
|
} else if (ex instanceof ServiceException) {
|
||||||
//业务失败的异常,如“账号或密码错误”
|
//业务失败的异常,如“账号或密码错误”
|
||||||
result.setCode(((ServiceException) ex).getCode());
|
result.setCode(((ServiceException) ex).getCode());
|
||||||
result.setMessage(ex.getMessage());
|
result.setMessage(ex.getMessage());
|
||||||
@ -59,7 +61,10 @@ public class BaseExceptionHandler {
|
|||||||
} else if (ex instanceof ServletException) {
|
} else if (ex instanceof ServletException) {
|
||||||
result.setCode(ResultCode.FAIL.getCode());
|
result.setCode(ResultCode.FAIL.getCode());
|
||||||
result.setMessage(ex.getMessage());
|
result.setMessage(ex.getMessage());
|
||||||
}else {
|
} else if (ex instanceof TransactionException) {
|
||||||
|
result.setCode(TransactionCode.InsufficientBalance.getCode());
|
||||||
|
result.setMessage(ex.getMessage());
|
||||||
|
} else {
|
||||||
//系统内部异常,不返回给客户端,内部记录错误日志
|
//系统内部异常,不返回给客户端,内部记录错误日志
|
||||||
result.setCode(ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
result.setCode(ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
||||||
String message;
|
String message;
|
||||||
@ -78,11 +83,11 @@ public class BaseExceptionHandler {
|
|||||||
}
|
}
|
||||||
result.setSuccess(false);
|
result.setSuccess(false);
|
||||||
return result;
|
return result;
|
||||||
}else {
|
} else {
|
||||||
ModelAndView mv = new ModelAndView();
|
ModelAndView mv = new ModelAndView();
|
||||||
FastJsonJsonView view = new FastJsonJsonView();
|
FastJsonJsonView view = new FastJsonJsonView();
|
||||||
Map<String, Object> attributes = new HashMap(2);
|
Map<String, Object> attributes = new HashMap(2);
|
||||||
if (ex instanceof BaseApiException){
|
if (ex instanceof BaseApiException) {
|
||||||
attributes.put("code", "401");
|
attributes.put("code", "401");
|
||||||
attributes.put("message", "用户未登录");
|
attributes.put("message", "用户未登录");
|
||||||
} else if (ex instanceof UnauthenticatedException) {
|
} else if (ex instanceof UnauthenticatedException) {
|
||||||
@ -93,18 +98,21 @@ public class BaseExceptionHandler {
|
|||||||
attributes.put("message", "用户无权限");
|
attributes.put("message", "用户无权限");
|
||||||
} else if (ex instanceof ServiceException) {
|
} else if (ex instanceof ServiceException) {
|
||||||
//业务失败的异常,如“账号或密码错误”
|
//业务失败的异常,如“账号或密码错误”
|
||||||
attributes.put("code",((ServiceException) ex).getCode());
|
attributes.put("code", ((ServiceException) ex).getCode());
|
||||||
attributes.put("message",ex.getMessage());
|
attributes.put("message", ex.getMessage());
|
||||||
logger.info(ex.getMessage());
|
logger.info(ex.getMessage());
|
||||||
} else if (ex instanceof NoHandlerFoundException) {
|
} else if (ex instanceof NoHandlerFoundException) {
|
||||||
attributes.put("code",ResultCode.NOT_FOUND.getCode());
|
attributes.put("code", ResultCode.NOT_FOUND.getCode());
|
||||||
attributes.put("message",ResultCode.NOT_FOUND.getMessage());
|
attributes.put("message", ResultCode.NOT_FOUND.getMessage());
|
||||||
} else if (ex instanceof ServletException) {
|
} else if (ex instanceof ServletException) {
|
||||||
attributes.put("code",ResultCode.FAIL.getCode());
|
attributes.put("code", ResultCode.FAIL.getCode());
|
||||||
attributes.put("message",ex.getMessage());
|
attributes.put("message", ex.getMessage());
|
||||||
}else {
|
} else if (ex instanceof TransactionException) {
|
||||||
|
attributes.put("code", TransactionCode.InsufficientBalance.getCode());
|
||||||
|
attributes.put("message", ex.getMessage());
|
||||||
|
} else {
|
||||||
//系统内部异常,不返回给客户端,内部记录错误日志
|
//系统内部异常,不返回给客户端,内部记录错误日志
|
||||||
attributes.put("code",ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
attributes.put("code", ResultCode.INTERNAL_SERVER_ERROR.getCode());
|
||||||
String message;
|
String message;
|
||||||
if (handler instanceof HandlerMethod) {
|
if (handler instanceof HandlerMethod) {
|
||||||
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
HandlerMethod handlerMethod = (HandlerMethod) handler;
|
||||||
@ -117,9 +125,9 @@ public class BaseExceptionHandler {
|
|||||||
message = ex.getMessage();
|
message = ex.getMessage();
|
||||||
}
|
}
|
||||||
logger.error(message, ex);
|
logger.error(message, ex);
|
||||||
attributes.put("message","操作失败");
|
attributes.put("message", "操作失败");
|
||||||
}
|
}
|
||||||
attributes.put("success",false);
|
attributes.put("success", false);
|
||||||
view.setAttributesMap(attributes);
|
view.setAttributesMap(attributes);
|
||||||
mv.setView(view);
|
mv.setView(view);
|
||||||
return mv;
|
return mv;
|
||||||
|
@ -29,7 +29,7 @@ import java.util.List;
|
|||||||
* @author ronger
|
* @author ronger
|
||||||
* @since 2018/05/28 11:00
|
* @since 2018/05/28 11:00
|
||||||
* 自定义权限匹配和账号密码匹配
|
* 自定义权限匹配和账号密码匹配
|
||||||
* */
|
*/
|
||||||
public class BaseShiroRealm extends AuthorizingRealm {
|
public class BaseShiroRealm extends AuthorizingRealm {
|
||||||
@Resource
|
@Resource
|
||||||
private RoleService roleService;
|
private RoleService roleService;
|
||||||
@ -43,13 +43,13 @@ public class BaseShiroRealm extends AuthorizingRealm {
|
|||||||
@Override
|
@Override
|
||||||
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
|
||||||
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
|
||||||
Principal principal = (Principal)principals.getPrimaryPrincipal();
|
Principal principal = (Principal) principals.getPrimaryPrincipal();
|
||||||
User user = new User();
|
User user = new User();
|
||||||
user.setIdUser(principal.getId());
|
user.setIdUser(principal.getId());
|
||||||
try {
|
try {
|
||||||
List<Role> roles = roleService.selectRoleByUser(user);
|
List<Role> roles = roleService.selectRoleByUser(user);
|
||||||
for (Role role : roles) {
|
for (Role role : roles) {
|
||||||
if(StringUtils.isNotBlank(role.getInputCode())){
|
if (StringUtils.isNotBlank(role.getInputCode())) {
|
||||||
authorizationInfo.addRole(role.getInputCode());
|
authorizationInfo.addRole(role.getInputCode());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ public class BaseShiroRealm extends AuthorizingRealm {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
|
* 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。
|
||||||
* */
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
|
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
|
||||||
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
|
UsernamePasswordToken token = (UsernamePasswordToken) authcToken;
|
||||||
@ -90,10 +90,11 @@ public class BaseShiroRealm extends AuthorizingRealm {
|
|||||||
if (user == null) {
|
if (user == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (!"0".equals(user.getStatus())) { //账户冻结(是否允许登陆)
|
// 账户冻结(是否允许登陆)
|
||||||
|
if (!"0".equals(user.getStatus())) {
|
||||||
throw new LockedAccountException();
|
throw new LockedAccountException();
|
||||||
}
|
}
|
||||||
byte[] salt = Encodes.decodeHex(user.getPassword().substring(0,16));
|
byte[] salt = Encodes.decodeHex(user.getPassword().substring(0, 16));
|
||||||
return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
|
return new SimpleAuthenticationInfo(new Principal(user, token.isMobileLogin()),
|
||||||
user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
|
user.getPassword().substring(16), ByteSource.Util.bytes(salt), getName());
|
||||||
}
|
}
|
||||||
@ -101,7 +102,7 @@ public class BaseShiroRealm extends AuthorizingRealm {
|
|||||||
/**
|
/**
|
||||||
* 授权用户信息
|
* 授权用户信息
|
||||||
*/
|
*/
|
||||||
public static class Principal implements Serializable {
|
public static class Principal implements Serializable {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@ -139,9 +140,9 @@ public class BaseShiroRealm extends AuthorizingRealm {
|
|||||||
* 获取SESSIONID
|
* 获取SESSIONID
|
||||||
*/
|
*/
|
||||||
public String getSessionid() {
|
public String getSessionid() {
|
||||||
try{
|
try {
|
||||||
return (String) Utils.getSession().getId();
|
return (String) Utils.getSession().getId();
|
||||||
}catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class MybatisConfigurer {
|
|||||||
//添加XML目录
|
//添加XML目录
|
||||||
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
|
||||||
factory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
|
factory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml"));
|
||||||
factory.setTypeHandlersPackage("com.rymcu.forest.util.handlers");
|
// factory.setTypeHandlersPackage("com.rymcu.forest.util.handlers");
|
||||||
return factory.getObject();
|
return factory.getObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +55,7 @@ public class ShiroConfig implements EnvironmentAware {
|
|||||||
|
|
||||||
filterChainDefinitionMap.put("/api/**", "anon");
|
filterChainDefinitionMap.put("/api/**", "anon");
|
||||||
filterChainDefinitionMap.put("/ws/**", "anon");
|
filterChainDefinitionMap.put("/ws/**", "anon");
|
||||||
|
filterChainDefinitionMap.put("/wss/**", "anon");
|
||||||
filterChainDefinitionMap.put("/wx/**", "anon");
|
filterChainDefinitionMap.put("/wx/**", "anon");
|
||||||
filterChainDefinitionMap.put("/**", "auth");
|
filterChainDefinitionMap.put("/**", "auth");
|
||||||
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
|
//配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据
|
||||||
|
@ -20,6 +20,7 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
|
|||||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||||
// 允许使用socketJs方式访问 即可通过http://IP:PORT/ws来和服务端websocket连接
|
// 允许使用socketJs方式访问 即可通过http://IP:PORT/ws来和服务端websocket连接
|
||||||
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
|
registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS();
|
||||||
|
registry.addEndpoint("/wss").setAllowedOrigins("*").withSockJS();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +31,7 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer {
|
|||||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||||
|
|
||||||
// 订阅Broker名称 user点对点 topic广播即群发
|
// 订阅Broker名称 user点对点 topic广播即群发
|
||||||
registry.enableSimpleBroker("/user","/public");
|
registry.enableSimpleBroker("/topic", "/user");
|
||||||
// 全局(客户端)使用的消息前缀
|
// 全局(客户端)使用的消息前缀
|
||||||
registry.setApplicationDestinationPrefixes("/app");
|
registry.setApplicationDestinationPrefixes("/app");
|
||||||
// 点对点使用的前缀 无需配置 默认/user
|
// 点对点使用的前缀 无需配置 默认/user
|
||||||
|
@ -2,10 +2,10 @@ package com.rymcu.forest.core.constant;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Shiro通用常量
|
* Shiro通用常量
|
||||||
*
|
*
|
||||||
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
public interface ShiroConstants
|
public interface ShiroConstants {
|
||||||
{
|
|
||||||
/**
|
/**
|
||||||
* 当前登录的用户
|
* 当前登录的用户
|
||||||
*/
|
*/
|
||||||
@ -54,7 +54,7 @@ public interface ShiroConstants
|
|||||||
/**
|
/**
|
||||||
* 验证码
|
* 验证码
|
||||||
*/
|
*/
|
||||||
public static final String CURRENT_VALIDATECODE = "validateCode";
|
public static final String CURRENT_VALIDATE_CODE = "validateCode";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证码错误
|
* 验证码错误
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
package com.rymcu.forest.core.exception;
|
||||||
|
|
||||||
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public class TransactionException extends Exception {
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
public TransactionException(TransactionCode transactionCode) {
|
||||||
|
super(transactionCode.getMessage());
|
||||||
|
this.code = transactionCode.getCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
}
|
@ -2,18 +2,22 @@ package com.rymcu.forest.core.result;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 响应码枚举,参考HTTP状态码的语义
|
* 响应码枚举,参考HTTP状态码的语义
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
public enum ResultCode {
|
public enum ResultCode {
|
||||||
SUCCESS(1, "SUCCESS"),//成功
|
// 成功
|
||||||
FAIL(400, "访问失败"),//失败
|
SUCCESS(1, "SUCCESS"),
|
||||||
UNAUTHORIZED(401, "签名错误"),//未认证(签名错误)
|
// 失败
|
||||||
NOT_FOUND(404, "此接口不存在"),//接口不存在
|
FAIL(400, "访问失败"),
|
||||||
INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"),//服务器内部错误
|
// 未认证(签名错误)
|
||||||
INVALID_PARAM(10000, "参数错误"),
|
UNAUTHORIZED(401, "签名错误"),
|
||||||
|
// 接口不存在
|
||||||
|
NOT_FOUND(404, "此接口不存在"),
|
||||||
|
// 服务器内部错误
|
||||||
;
|
INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"),
|
||||||
|
// 参数错误
|
||||||
|
INVALID_PARAM(10000, "参数错误");
|
||||||
private int code;
|
private int code;
|
||||||
private String message;
|
private String message;
|
||||||
|
|
||||||
|
@ -13,13 +13,17 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 基于通用MyBatis Mapper插件的Service接口的实现
|
* 基于通用MyBatis Mapper插件的Service接口的实现
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractService<T> implements Service<T> {
|
public abstract class AbstractService<T> implements Service<T> {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected Mapper<T> mapper;
|
protected Mapper<T> mapper;
|
||||||
|
/**
|
||||||
private Class<T> modelClass; // 当前泛型真实类型的Class
|
* 当前泛型真实类型的Class
|
||||||
|
*/
|
||||||
|
private Class<T> modelClass;
|
||||||
|
|
||||||
public AbstractService() {
|
public AbstractService() {
|
||||||
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
|
ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();
|
||||||
|
@ -8,16 +8,85 @@ import java.util.List;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Service 层 基础接口,其他Service 接口 请继承该接口
|
* Service 层 基础接口,其他Service 接口 请继承该接口
|
||||||
|
*
|
||||||
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
public interface Service<T> {
|
public interface Service<T> {
|
||||||
void save(T model);//持久化
|
/**
|
||||||
void save(List<T> models);//批量持久化
|
* 持久化
|
||||||
void deleteById(String id);//通过主鍵刪除
|
*
|
||||||
void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4”
|
* @param model
|
||||||
void update(T model);//更新
|
*/
|
||||||
T findById(String id);//通过ID查找
|
void save(T model);
|
||||||
T findBy(String fieldName, Object value) throws TooManyResultsException, ServiceException; //通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束
|
|
||||||
List<T> findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4”
|
/**
|
||||||
List<T> findByCondition(Condition condition);//根据条件查找
|
* 批量持久化
|
||||||
List<T> findAll();//获取所有
|
*
|
||||||
|
* @param models
|
||||||
|
*/
|
||||||
|
void save(List<T> models);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过主鍵刪除
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
*/
|
||||||
|
void deleteById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 批量刪除 eg:ids -> “1,2,3,4”
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
*/
|
||||||
|
void deleteByIds(String ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新
|
||||||
|
*
|
||||||
|
* @param model
|
||||||
|
*/
|
||||||
|
void update(T model);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过ID查找
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
T findById(String id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束
|
||||||
|
*
|
||||||
|
* @param fieldName
|
||||||
|
* @param value
|
||||||
|
* @return
|
||||||
|
* @throws TooManyResultsException
|
||||||
|
* @throws ServiceException
|
||||||
|
*/
|
||||||
|
T findBy(String fieldName, Object value) throws TooManyResultsException, ServiceException;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 通过多个ID查找//eg:ids -> “1,2,3,4”
|
||||||
|
*
|
||||||
|
* @param ids
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findByIds(String ids);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据条件查找
|
||||||
|
*
|
||||||
|
* @param condition
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findByCondition(Condition condition);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<T> findAll();
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,94 @@
|
|||||||
|
package com.rymcu.forest.core.service.log;
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
|
import com.rymcu.forest.core.service.log.annotation.TransactionLogger;
|
||||||
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
|
import com.rymcu.forest.util.UserUtils;
|
||||||
|
import com.rymcu.forest.web.api.exception.BaseApiException;
|
||||||
|
import org.aspectj.lang.JoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.AfterReturning;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.aspectj.lang.annotation.Pointcut;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class TransactionAspect {
|
||||||
|
|
||||||
|
Logger logger = LoggerFactory.getLogger(TransactionAspect.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private TransactionRecordService transactionRecordService;
|
||||||
|
|
||||||
|
@Pointcut("@annotation(com.rymcu.forest.core.service.log.annotation.TransactionLogger)")
|
||||||
|
public void pointCut() {}
|
||||||
|
/**
|
||||||
|
* 保存交易操作日志
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @return 方法执行结果
|
||||||
|
* @throws Throwable 调用出错
|
||||||
|
*/
|
||||||
|
@AfterReturning(value = "pointCut()", returning="obj")
|
||||||
|
public void save(JoinPoint joinPoint, Object obj) throws Exception {
|
||||||
|
logger.info("保存交易记录 start ...");
|
||||||
|
/**
|
||||||
|
* 解析Log注解
|
||||||
|
*/
|
||||||
|
String methodName = joinPoint.getSignature().getName();
|
||||||
|
Method method = currentMethod(joinPoint, methodName);
|
||||||
|
TransactionLogger log = method.getAnnotation(TransactionLogger.class);
|
||||||
|
if (Objects.nonNull(log)) {
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
GlobalResult globalResult = (GlobalResult) obj;
|
||||||
|
if (globalResult.isSuccess()) {
|
||||||
|
if (TransactionEnum.Answer.equals(log.transactionType())) {
|
||||||
|
if (globalResult.getData().equals(true)) {
|
||||||
|
transactionRecordService.bankTransfer(user.getIdUser(), TransactionEnum.CorrectAnswer);
|
||||||
|
} else {
|
||||||
|
transactionRecordService.bankTransfer(user.getIdUser(), TransactionEnum.Answer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger.info("保存交易记录 end ...");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前执行的方法
|
||||||
|
*
|
||||||
|
* @param joinPoint 连接点
|
||||||
|
* @param methodName 方法名称
|
||||||
|
* @return 方法
|
||||||
|
*/
|
||||||
|
private Method currentMethod(JoinPoint joinPoint, String methodName) {
|
||||||
|
/**
|
||||||
|
* 获取目标类的所有方法,找到当前要执行的方法
|
||||||
|
*/
|
||||||
|
Method[] methods = joinPoint.getTarget().getClass().getMethods();
|
||||||
|
Method resultMethod = null;
|
||||||
|
for (Method method : methods) {
|
||||||
|
if (method.getName().equals(methodName)) {
|
||||||
|
resultMethod = method;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return resultMethod;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package com.rymcu.forest.core.service.log.annotation;
|
||||||
|
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface TransactionLogger {
|
||||||
|
|
||||||
|
TransactionEnum transactionType();
|
||||||
|
|
||||||
|
}
|
@ -12,6 +12,8 @@ public class Author {
|
|||||||
|
|
||||||
private String userNickname;
|
private String userNickname;
|
||||||
|
|
||||||
|
private String userAccount;
|
||||||
|
|
||||||
private String userAvatarURL;
|
private String userAvatarURL;
|
||||||
|
|
||||||
private String userArticleCount;
|
private String userArticleCount;
|
||||||
|
12
src/main/java/com/rymcu/forest/dto/UserSearchDTO.java
Normal file
12
src/main/java/com/rymcu/forest/dto/UserSearchDTO.java
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package com.rymcu.forest.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UserSearchDTO {
|
||||||
|
|
||||||
|
private String nickname;
|
||||||
|
}
|
@ -1,30 +0,0 @@
|
|||||||
package com.rymcu.forest.enumerate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author ronger
|
|
||||||
*/
|
|
||||||
|
|
||||||
public enum SponsorEnum {
|
|
||||||
Article("0", 20);
|
|
||||||
|
|
||||||
private String dataType;
|
|
||||||
|
|
||||||
private Integer money;
|
|
||||||
|
|
||||||
SponsorEnum(String dataType, Integer money) {
|
|
||||||
this.dataType = dataType;
|
|
||||||
this.money = money;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDataType() {
|
|
||||||
return this.dataType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Integer getMoney() {
|
|
||||||
return this.money;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isArticle() {
|
|
||||||
return Article.equals(this);
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,28 @@
|
|||||||
|
package com.rymcu.forest.enumerate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum TransactionCode {
|
||||||
|
|
||||||
|
InsufficientBalance(901, "余额不足");
|
||||||
|
|
||||||
|
private int code;
|
||||||
|
|
||||||
|
private String message;
|
||||||
|
|
||||||
|
TransactionCode(int code, String message) {
|
||||||
|
this.code = code;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public String getMessage() {
|
||||||
|
return this.message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCode() {
|
||||||
|
return this.code;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
package com.rymcu.forest.enumerate;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
|
||||||
|
public enum TransactionEnum {
|
||||||
|
ArticleSponsor("0", 20, "文章赞赏"),
|
||||||
|
Answer("1", 30, "答题奖励"),
|
||||||
|
CorrectAnswer("2", 50, "答题奖励");
|
||||||
|
|
||||||
|
private String dataType;
|
||||||
|
|
||||||
|
private Integer money;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
TransactionEnum(String dataType, Integer money, String description) {
|
||||||
|
this.dataType = dataType;
|
||||||
|
this.money = money;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static TransactionEnum findTransactionEnum(String dataType) {
|
||||||
|
return Arrays.stream(TransactionEnum.values()).filter(transactionEnum -> transactionEnum.getDataType().equals(dataType)).findFirst().orElse(TransactionEnum.ArticleSponsor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDataType() {
|
||||||
|
return this.dataType;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Integer getMoney() {
|
||||||
|
return this.money;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return this.description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isArticleSponsor() {
|
||||||
|
return ArticleSponsor.equals(this);
|
||||||
|
}
|
||||||
|
}
|
@ -184,4 +184,10 @@ public interface ArticleMapper extends Mapper<Article> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
int updatePerfect(@Param("idArticle") Integer idArticle, @Param("articlePerfect") String articlePerfect);
|
int updatePerfect(@Param("idArticle") Integer idArticle, @Param("articlePerfect") String articlePerfect);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除文章关联文章内容表信息
|
||||||
|
* @param idArticle
|
||||||
|
*/
|
||||||
|
void deleteArticleContent(@Param("idArticle") Integer idArticle);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package com.rymcu.forest.mapper;
|
package com.rymcu.forest.mapper;
|
||||||
|
|
||||||
import com.rymcu.forest.core.mapper.Mapper;
|
import com.rymcu.forest.core.mapper.Mapper;
|
||||||
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
import com.rymcu.forest.entity.Notification;
|
import com.rymcu.forest.entity.Notification;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
@ -23,7 +24,7 @@ public interface NotificationMapper extends Mapper<Notification> {
|
|||||||
* @param idUser
|
* @param idUser
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<Notification> selectNotifications(@Param("idUser") Integer idUser);
|
List<NotificationDTO> selectNotifications(@Param("idUser") Integer idUser);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取消息数据
|
* 获取消息数据
|
||||||
|
@ -73,4 +73,10 @@ public interface PortfolioMapper extends Mapper<Portfolio> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Integer unbindArticle(@Param("idPortfolio") Integer idPortfolio, @Param("idArticle") Integer idArticle);
|
Integer unbindArticle(@Param("idPortfolio") Integer idPortfolio, @Param("idArticle") Integer idArticle);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取作品集列表数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<Portfolio> selectPortfolios();
|
||||||
}
|
}
|
||||||
|
@ -27,4 +27,12 @@ public interface TransactionRecordMapper extends Mapper<TransactionRecord> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<TransactionRecordDTO> selectTransactionRecords(@Param("bankAccount") String bankAccount);
|
List<TransactionRecordDTO> selectTransactionRecords(@Param("bankAccount") String bankAccount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验今日是否已发放答题奖励
|
||||||
|
* @param bankAccount
|
||||||
|
* @param funds
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
Boolean existsWithBankAccountAndFunds(@Param("bankAccount") String bankAccount, @Param("funds") String funds);
|
||||||
}
|
}
|
||||||
|
@ -4,9 +4,12 @@ import com.rymcu.forest.core.mapper.Mapper;
|
|||||||
import com.rymcu.forest.dto.Author;
|
import com.rymcu.forest.dto.Author;
|
||||||
import com.rymcu.forest.dto.UserDTO;
|
import com.rymcu.forest.dto.UserDTO;
|
||||||
import com.rymcu.forest.dto.UserInfoDTO;
|
import com.rymcu.forest.dto.UserInfoDTO;
|
||||||
|
import com.rymcu.forest.dto.UserSearchDTO;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import org.apache.ibatis.annotations.Param;
|
import org.apache.ibatis.annotations.Param;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
*/
|
*/
|
||||||
@ -36,10 +39,10 @@ public interface UserMapper extends Mapper<User> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户昵称获取用户信息
|
* 根据用户昵称获取用户信息
|
||||||
* @param nickname
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UserDTO selectUserDTOByNickname(@Param("nickname") String nickname);
|
UserDTO selectUserDTOByAccount(@Param("account") String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改用户密码
|
* 修改用户密码
|
||||||
@ -136,4 +139,11 @@ public interface UserMapper extends Mapper<User> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Integer updatePasswordById(@Param("idUser") Integer idUser, @Param("password") String password);
|
Integer updatePasswordById(@Param("idUser") Integer idUser, @Param("password") String password);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户数据
|
||||||
|
* @param searchDTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<User> selectUsers(@Param("searchDTO") UserSearchDTO searchDTO);
|
||||||
}
|
}
|
@ -67,7 +67,7 @@ public interface ArticleService extends Service<Article> {
|
|||||||
* @param id
|
* @param id
|
||||||
* @return
|
* @return
|
||||||
* */
|
* */
|
||||||
Map delete(Integer id);
|
Map delete(Integer id) throws BaseApiException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 增量文章浏览数
|
* 增量文章浏览数
|
||||||
|
@ -32,4 +32,10 @@ public interface BankAccountService extends Service<BankAccount> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
BankAccount findByBankAccount(String bankAccount);
|
BankAccount findByBankAccount(String bankAccount);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询系统社区银行
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
BankAccount findSystemBankAccount();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package com.rymcu.forest.service;
|
package com.rymcu.forest.service;
|
||||||
|
|
||||||
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
|
|
||||||
import javax.mail.MessagingException;
|
import javax.mail.MessagingException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -12,6 +14,7 @@ public interface JavaMailService {
|
|||||||
* 发送验证码邮件
|
* 发送验证码邮件
|
||||||
* @param email 收件人邮箱
|
* @param email 收件人邮箱
|
||||||
* @return 执行结果 0:失败1:成功
|
* @return 执行结果 0:失败1:成功
|
||||||
|
* @throws MessagingException
|
||||||
* */
|
* */
|
||||||
Integer sendEmailCode(String email) throws MessagingException;
|
Integer sendEmailCode(String email) throws MessagingException;
|
||||||
|
|
||||||
@ -19,6 +22,15 @@ public interface JavaMailService {
|
|||||||
* 发送找回密码邮件
|
* 发送找回密码邮件
|
||||||
* @param email 收件人邮箱
|
* @param email 收件人邮箱
|
||||||
* @return 执行结果 0:失败1:成功
|
* @return 执行结果 0:失败1:成功
|
||||||
|
* @throws MessagingException
|
||||||
* */
|
* */
|
||||||
Integer sendForgetPasswordEmail(String email) throws MessagingException;
|
Integer sendForgetPasswordEmail(String email) throws MessagingException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 发送下消息通知
|
||||||
|
* @param notification
|
||||||
|
* @return
|
||||||
|
* @throws MessagingException
|
||||||
|
*/
|
||||||
|
Integer sendNotification(NotificationDTO notification) throws MessagingException;
|
||||||
}
|
}
|
||||||
|
@ -77,4 +77,10 @@ public interface PortfolioService extends Service<Portfolio> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Map deletePortfolio(Integer idPortfolio);
|
Map deletePortfolio(Integer idPortfolio);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取作品集列表数据
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<Portfolio> findPortfolios();
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,7 @@ package com.rymcu.forest.service;
|
|||||||
import com.rymcu.forest.core.service.Service;
|
import com.rymcu.forest.core.service.Service;
|
||||||
import com.rymcu.forest.dto.TransactionRecordDTO;
|
import com.rymcu.forest.dto.TransactionRecordDTO;
|
||||||
import com.rymcu.forest.entity.TransactionRecord;
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -30,9 +31,18 @@ public interface TransactionRecordService extends Service<TransactionRecord> {
|
|||||||
* 根据用户主键进行交易
|
* 根据用户主键进行交易
|
||||||
* @param toUserId
|
* @param toUserId
|
||||||
* @param formUserId
|
* @param formUserId
|
||||||
* @param money
|
* @param transactionType
|
||||||
* @return
|
* @return
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
TransactionRecord transferByUserId(Integer toUserId, Integer formUserId, BigDecimal money) throws Exception;
|
TransactionRecord userTransfer(Integer toUserId, Integer formUserId, TransactionEnum transactionType) throws Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 社区银行转账/奖励发放
|
||||||
|
* @param idUser
|
||||||
|
* @param transactionType
|
||||||
|
* @return
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
TransactionRecord bankTransfer(Integer idUser, TransactionEnum transactionType) throws Exception;
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import com.rymcu.forest.entity.User;
|
|||||||
import com.rymcu.forest.entity.UserExtend;
|
import com.rymcu.forest.entity.UserExtend;
|
||||||
import org.apache.ibatis.exceptions.TooManyResultsException;
|
import org.apache.ibatis.exceptions.TooManyResultsException;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
@ -42,11 +43,11 @@ public interface UserService extends Service<User> {
|
|||||||
Map login(String account, String password);
|
Map login(String account, String password);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 通过 nickname 获取用户信息接口
|
* 通过 account 获取用户信息接口
|
||||||
* @param nickname 昵称
|
* @param account 昵称
|
||||||
* @return UserDTO
|
* @return UserDTO
|
||||||
* */
|
* */
|
||||||
UserDTO findUserDTOByNickname(String nickname);
|
UserDTO findUserDTOByAccount(String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 找回密码接口
|
* 找回密码接口
|
||||||
@ -117,10 +118,10 @@ public interface UserService extends Service<User> {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取用户扩展信息
|
* 获取用户扩展信息
|
||||||
* @param nickname
|
* @param account
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
UserExtend selectUserExtendByNickname(String nickname);
|
UserExtend selectUserExtendByAccount(String account);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更换邮箱
|
* 更换邮箱
|
||||||
@ -135,4 +136,11 @@ public interface UserService extends Service<User> {
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
Map updatePassword(UpdatePasswordDTO updatePasswordDTO);
|
Map updatePassword(UpdatePasswordDTO updatePasswordDTO);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询用户列表
|
||||||
|
* @param searchDTO
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
List<User> findUsers(UserSearchDTO searchDTO);
|
||||||
}
|
}
|
||||||
|
@ -203,9 +203,14 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (StringUtils.isNotBlank(articleContentHtml)) {
|
if (StringUtils.isNotBlank(articleContentHtml)) {
|
||||||
String previewContent = BaiDuAipUtils.getNewsSummary(newArticle.getArticleTitle(), articleContentHtml, MAX_PREVIEW);
|
String previewContent;
|
||||||
if (previewContent.length() > MAX_PREVIEW) {
|
if (articleContentHtml.length() > MAX_PREVIEW) {
|
||||||
previewContent = previewContent.substring(0, MAX_PREVIEW);
|
previewContent = BaiDuAipUtils.getNewsSummary(newArticle.getArticleTitle(), articleContentHtml, MAX_PREVIEW);
|
||||||
|
if (previewContent.length() > MAX_PREVIEW) {
|
||||||
|
previewContent = previewContent.substring(0, MAX_PREVIEW);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
previewContent = Html2TextUtil.getContent(articleContentHtml);
|
||||||
}
|
}
|
||||||
newArticle.setArticlePreviewContent(previewContent);
|
newArticle.setArticlePreviewContent(previewContent);
|
||||||
}
|
}
|
||||||
@ -260,8 +265,18 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public Map delete(Integer id) {
|
public Map delete(Integer id) throws BaseApiException {
|
||||||
Map<String, String> map = new HashMap(1);
|
Map<String, String> map = new HashMap(1);
|
||||||
|
// 鉴权
|
||||||
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
|
Integer roleWeights = userService.findRoleWeightsByUser(user.getIdUser());
|
||||||
|
if (roleWeights > 2) {
|
||||||
|
Article article = articleMapper.selectByPrimaryKey(id);
|
||||||
|
if (!user.getIdUser().equals(article.getArticleAuthorId())) {
|
||||||
|
map.put("message", "非法访问!");
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
}
|
||||||
Integer result;
|
Integer result;
|
||||||
// 判断是否有评论
|
// 判断是否有评论
|
||||||
boolean isHavComment = articleMapper.existsCommentWithPrimaryKey(id);
|
boolean isHavComment = articleMapper.existsCommentWithPrimaryKey(id);
|
||||||
@ -285,6 +300,8 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
articleMapper.deleteLinkedPortfolioData(id);
|
articleMapper.deleteLinkedPortfolioData(id);
|
||||||
// 删除引用标签记录
|
// 删除引用标签记录
|
||||||
articleMapper.deleteTagArticle(id);
|
articleMapper.deleteTagArticle(id);
|
||||||
|
// 删除文章内容表
|
||||||
|
articleMapper.deleteArticleContent(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -398,9 +415,11 @@ public class ArticleServiceImpl extends AbstractService<Article> implements Arti
|
|||||||
|
|
||||||
private Author genAuthor(ArticleDTO article) {
|
private Author genAuthor(ArticleDTO article) {
|
||||||
Author author = new Author();
|
Author author = new Author();
|
||||||
|
User user = userService.findById(String.valueOf(article.getArticleAuthorId()));
|
||||||
author.setUserNickname(article.getArticleAuthorName());
|
author.setUserNickname(article.getArticleAuthorName());
|
||||||
author.setUserAvatarURL(article.getArticleAuthorAvatarUrl());
|
author.setUserAvatarURL(article.getArticleAuthorAvatarUrl());
|
||||||
author.setIdUser(article.getArticleAuthorId());
|
author.setIdUser(article.getArticleAuthorId());
|
||||||
|
author.setUserAccount(user.getAccount());
|
||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,6 +67,15 @@ public class BankAccountServiceImpl extends AbstractService<BankAccount> impleme
|
|||||||
return bankAccountMapper.selectOne(searchBankAccount);
|
return bankAccountMapper.selectOne(searchBankAccount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BankAccount findSystemBankAccount() {
|
||||||
|
BankAccount bankAccount = new BankAccount();
|
||||||
|
bankAccount.setIdBank(1);
|
||||||
|
bankAccount.setAccountType("1");
|
||||||
|
bankAccount.setAccountOwner(2);
|
||||||
|
return bankAccountMapper.selectOne(bankAccount);
|
||||||
|
}
|
||||||
|
|
||||||
private String nextBankAccount() {
|
private String nextBankAccount() {
|
||||||
String bankAccount = "600000001";
|
String bankAccount = "600000001";
|
||||||
String maxBankAccount = bankAccountMapper.selectMaxBankAccount();
|
String maxBankAccount = bankAccountMapper.selectMaxBankAccount();
|
||||||
|
@ -1,7 +1,11 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.constant.NotificationConstant;
|
||||||
import com.rymcu.forest.core.service.redis.RedisService;
|
import com.rymcu.forest.core.service.redis.RedisService;
|
||||||
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.service.JavaMailService;
|
import com.rymcu.forest.service.JavaMailService;
|
||||||
|
import com.rymcu.forest.service.UserService;
|
||||||
import com.rymcu.forest.util.Utils;
|
import com.rymcu.forest.util.Utils;
|
||||||
import org.apache.commons.lang.time.StopWatch;
|
import org.apache.commons.lang.time.StopWatch;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
@ -34,6 +38,8 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
private JavaMailSenderImpl mailSender;
|
private JavaMailSenderImpl mailSender;
|
||||||
@Resource
|
@Resource
|
||||||
private RedisService redisService;
|
private RedisService redisService;
|
||||||
|
@Resource
|
||||||
|
private UserService userService;
|
||||||
/**
|
/**
|
||||||
* thymeleaf模板引擎
|
* thymeleaf模板引擎
|
||||||
*/
|
*/
|
||||||
@ -53,12 +59,49 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer sendEmailCode(String email) throws MessagingException {
|
public Integer sendEmailCode(String email) throws MessagingException {
|
||||||
return sendCode(email,0);
|
return sendCode(email, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Integer sendForgetPasswordEmail(String email) throws MessagingException {
|
public Integer sendForgetPasswordEmail(String email) throws MessagingException {
|
||||||
return sendCode(email,1);
|
return sendCode(email, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Integer sendNotification(NotificationDTO notification) throws MessagingException {
|
||||||
|
Properties props = new Properties();
|
||||||
|
// 表示SMTP发送邮件,需要进行身份验证
|
||||||
|
props.put("mail.smtp.auth", true);
|
||||||
|
props.put("mail.smtp.ssl.enable", true);
|
||||||
|
props.put("mail.smtp.host", SERVER_HOST);
|
||||||
|
props.put("mail.smtp.port", SERVER_PORT);
|
||||||
|
// 如果使用ssl,则去掉使用25端口的配置,进行如下配置,
|
||||||
|
props.put("mail.smtp.socketFactory.class", "com.rymcu.forest.util.MailSSLSocketFactory");
|
||||||
|
props.put("mail.smtp.socketFactory.port", SERVER_PORT);
|
||||||
|
// 发件人的账号,填写控制台配置的发信地址,比如xxx@xxx.com
|
||||||
|
props.put("mail.user", USERNAME);
|
||||||
|
// 访问SMTP服务时需要提供的密码(在控制台选择发信地址进行设置)
|
||||||
|
props.put("mail.password", PASSWORD);
|
||||||
|
mailSender.setJavaMailProperties(props);
|
||||||
|
User user = userService.findById(String.valueOf(notification.getIdUser()));
|
||||||
|
if (NotificationConstant.Comment.equals(notification.getDataType())) {
|
||||||
|
String url = notification.getDataUrl();
|
||||||
|
String thymeleafTemplatePath = "mail/commentNotification";
|
||||||
|
Map<String, Object> thymeleafTemplateVariable = new HashMap<String, Object>(4);
|
||||||
|
thymeleafTemplateVariable.put("user", notification.getAuthor().getUserNickname());
|
||||||
|
thymeleafTemplateVariable.put("articleTitle", notification.getDataTitle());
|
||||||
|
thymeleafTemplateVariable.put("content", notification.getDataSummary());
|
||||||
|
thymeleafTemplateVariable.put("url", url);
|
||||||
|
|
||||||
|
sendTemplateEmail(USERNAME,
|
||||||
|
new String[]{user.getEmail()},
|
||||||
|
new String[]{},
|
||||||
|
"【RYMCU】 消息通知",
|
||||||
|
thymeleafTemplatePath,
|
||||||
|
thymeleafTemplateVariable);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Integer sendCode(String to, Integer type) throws MessagingException {
|
private Integer sendCode(String to, Integer type) throws MessagingException {
|
||||||
@ -79,29 +122,29 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
|
SimpleMailMessage simpleMailMessage = new SimpleMailMessage();
|
||||||
simpleMailMessage.setFrom(USERNAME);
|
simpleMailMessage.setFrom(USERNAME);
|
||||||
simpleMailMessage.setTo(to);
|
simpleMailMessage.setTo(to);
|
||||||
if(type == 0) {
|
if (type == 0) {
|
||||||
Integer code = Utils.genCode();
|
Integer code = Utils.genCode();
|
||||||
redisService.set(to,code,5*60);
|
redisService.set(to, code, 5 * 60);
|
||||||
simpleMailMessage.setSubject("新用户注册邮箱验证");
|
simpleMailMessage.setSubject("新用户注册邮箱验证");
|
||||||
simpleMailMessage.setText("【RYMCU】您的校验码是 " + code + ",有效时间 5 分钟,请不要泄露验证码给其他人。如非本人操作,请忽略!");
|
simpleMailMessage.setText("【RYMCU】您的校验码是 " + code + ",有效时间 5 分钟,请不要泄露验证码给其他人。如非本人操作,请忽略!");
|
||||||
mailSender.send(simpleMailMessage);
|
mailSender.send(simpleMailMessage);
|
||||||
return 1;
|
return 1;
|
||||||
} else if(type == 1){
|
} else if (type == 1) {
|
||||||
String code = Utils.entryptPassword(to);
|
String code = Utils.entryptPassword(to);
|
||||||
String url = BASE_URL + "/forget-password?code=" + code;
|
String url = BASE_URL + "/forget-password?code=" + code;
|
||||||
redisService.set(code,to,15*60);
|
redisService.set(code, to, 15 * 60);
|
||||||
|
|
||||||
String thymeleafTemplatePath = "mail/forgetPasswordTemplate";
|
String thymeleafTemplatePath = "mail/forgetPasswordTemplate";
|
||||||
Map<String, Object> thymeleafTemplateVariable = new HashMap<String, Object>();
|
Map<String, Object> thymeleafTemplateVariable = new HashMap<String, Object>(1);
|
||||||
thymeleafTemplateVariable.put("url", url);
|
thymeleafTemplateVariable.put("url", url);
|
||||||
|
|
||||||
sendTemplateEmail(USERNAME,
|
sendTemplateEmail(USERNAME,
|
||||||
new String[] { to },
|
new String[]{to},
|
||||||
new String[] {},
|
new String[]{},
|
||||||
"【RYMCU】 找回密码",
|
"【RYMCU】 找回密码",
|
||||||
thymeleafTemplatePath,
|
thymeleafTemplatePath,
|
||||||
thymeleafTemplateVariable);
|
thymeleafTemplateVariable);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -109,25 +152,19 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
/**
|
/**
|
||||||
* 发送thymeleaf模板邮件
|
* 发送thymeleaf模板邮件
|
||||||
*
|
*
|
||||||
* @param deliver
|
* @param deliver 发送人邮箱名 如: javalsj@163.com
|
||||||
* 发送人邮箱名 如: javalsj@163.com
|
* @param receivers 收件人,可多个收件人 如:11111@qq.com,2222@163.com
|
||||||
* @param receivers
|
* @param carbonCopys 抄送人,可多个抄送人 如:33333@sohu.com
|
||||||
* 收件人,可多个收件人 如:11111@qq.com,2222@163.com
|
* @param subject 邮件主题 如:您收到一封高大上的邮件,请查收。
|
||||||
* @param carbonCopys
|
* @param thymeleafTemplatePath 邮件模板 如:mail\mailTemplate.html。
|
||||||
* 抄送人,可多个抄送人 如:33333@sohu.com
|
* @param thymeleafTemplateVariable 邮件模板变量集
|
||||||
* @param subject
|
|
||||||
* 邮件主题 如:您收到一封高大上的邮件,请查收。
|
|
||||||
* @param thymeleafTemplatePath
|
|
||||||
* 邮件模板 如:mail\mailTemplate.html。
|
|
||||||
* @param thymeleafTemplateVariable
|
|
||||||
* 邮件模板变量集
|
|
||||||
*/
|
*/
|
||||||
public void sendTemplateEmail(String deliver, String[] receivers, String[] carbonCopys, String subject, String thymeleafTemplatePath,
|
public void sendTemplateEmail(String deliver, String[] receivers, String[] carbonCopys, String subject, String thymeleafTemplatePath,
|
||||||
Map<String, Object> thymeleafTemplateVariable) throws MessagingException {
|
Map<String, Object> thymeleafTemplateVariable) throws MessagingException {
|
||||||
String text = null;
|
String text = null;
|
||||||
if (thymeleafTemplateVariable != null && thymeleafTemplateVariable.size() > 0) {
|
if (thymeleafTemplateVariable != null && thymeleafTemplateVariable.size() > 0) {
|
||||||
Context context = new Context();
|
Context context = new Context();
|
||||||
thymeleafTemplateVariable.forEach((key, value)->context.setVariable(key, value));
|
thymeleafTemplateVariable.forEach((key, value) -> context.setVariable(key, value));
|
||||||
text = templateEngine.process(thymeleafTemplatePath, context);
|
text = templateEngine.process(thymeleafTemplatePath, context);
|
||||||
}
|
}
|
||||||
sendMimeMail(deliver, receivers, carbonCopys, subject, text, true, null);
|
sendMimeMail(deliver, receivers, carbonCopys, subject, text, true, null);
|
||||||
@ -136,22 +173,15 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
/**
|
/**
|
||||||
* 发送的邮件(支持带附件/html类型的邮件)
|
* 发送的邮件(支持带附件/html类型的邮件)
|
||||||
*
|
*
|
||||||
* @param deliver
|
* @param deliver 发送人邮箱名 如: javalsj@163.com
|
||||||
* 发送人邮箱名 如: javalsj@163.com
|
* @param receivers 收件人,可多个收件人 如:11111@qq.com,2222@163.com
|
||||||
* @param receivers
|
* @param carbonCopys 抄送人,可多个抄送人 如:3333@sohu.com
|
||||||
* 收件人,可多个收件人 如:11111@qq.com,2222@163.com
|
* @param subject 邮件主题 如:您收到一封高大上的邮件,请查收。
|
||||||
* @param carbonCopys
|
* @param text 邮件内容 如:测试邮件逗你玩的。 <html><body><img
|
||||||
* 抄送人,可多个抄送人 如:3333@sohu.com
|
* src=\"cid:attchmentFileName\"></body></html>
|
||||||
* @param subject
|
* @param attachmentFilePaths 附件文件路径 如:
|
||||||
* 邮件主题 如:您收到一封高大上的邮件,请查收。
|
* 需要注意的是addInline函数中资源名称attchmentFileName需要与正文中cid:attchmentFileName对应起来
|
||||||
* @param text
|
* @throws Exception 邮件发送过程中的异常信息
|
||||||
* 邮件内容 如:测试邮件逗你玩的。 <html><body><img
|
|
||||||
* src=\"cid:attchmentFileName\"></body></html>
|
|
||||||
* @param attachmentFilePaths
|
|
||||||
* 附件文件路径 如:
|
|
||||||
* 需要注意的是addInline函数中资源名称attchmentFileName需要与正文中cid:attchmentFileName对应起来
|
|
||||||
* @throws Exception
|
|
||||||
* 邮件发送过程中的异常信息
|
|
||||||
*/
|
*/
|
||||||
private void sendMimeMail(String deliver, String[] receivers, String[] carbonCopys, String subject, String text,
|
private void sendMimeMail(String deliver, String[] receivers, String[] carbonCopys, String subject, String text,
|
||||||
boolean isHtml, String[] attachmentFilePaths) throws MessagingException {
|
boolean isHtml, String[] attachmentFilePaths) throws MessagingException {
|
||||||
@ -186,7 +216,6 @@ public class JavaMailServiceImpl implements JavaMailService {
|
|||||||
}
|
}
|
||||||
mailSender.send(mimeMessage);
|
mailSender.send(mimeMessage);
|
||||||
stopWatch.stop();
|
stopWatch.stop();
|
||||||
//logger.info("邮件发送成功, 花费时间{}秒", stopWatch.getStartTime());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,22 +1,16 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
import com.rymcu.forest.dto.ArticleDTO;
|
|
||||||
import com.rymcu.forest.dto.Author;
|
|
||||||
import com.rymcu.forest.dto.NotificationDTO;
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
import com.rymcu.forest.entity.Comment;
|
|
||||||
import com.rymcu.forest.entity.Follow;
|
|
||||||
import com.rymcu.forest.entity.Notification;
|
import com.rymcu.forest.entity.Notification;
|
||||||
import com.rymcu.forest.entity.User;
|
|
||||||
import com.rymcu.forest.mapper.NotificationMapper;
|
import com.rymcu.forest.mapper.NotificationMapper;
|
||||||
import com.rymcu.forest.service.*;
|
import com.rymcu.forest.service.NotificationService;
|
||||||
import com.rymcu.forest.util.BeanCopierUtil;
|
import com.rymcu.forest.util.BeanCopierUtil;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import com.rymcu.forest.util.NotificationUtils;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@ -28,16 +22,6 @@ public class NotificationServiceImpl extends AbstractService<Notification> imple
|
|||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private NotificationMapper notificationMapper;
|
private NotificationMapper notificationMapper;
|
||||||
@Resource
|
|
||||||
private ArticleService articleService;
|
|
||||||
@Resource
|
|
||||||
private CommentService commentService;
|
|
||||||
@Resource
|
|
||||||
private UserService userService;
|
|
||||||
@Resource
|
|
||||||
private FollowService followService;
|
|
||||||
@Value("${resource.domain}")
|
|
||||||
private String domain;
|
|
||||||
|
|
||||||
private final static String unRead = "0";
|
private final static String unRead = "0";
|
||||||
|
|
||||||
@ -49,13 +33,12 @@ public class NotificationServiceImpl extends AbstractService<Notification> imple
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<NotificationDTO> findNotifications(Integer idUser) {
|
public List<NotificationDTO> findNotifications(Integer idUser) {
|
||||||
List<Notification> list = notificationMapper.selectNotifications(idUser);
|
List<NotificationDTO> list = notificationMapper.selectNotifications(idUser);
|
||||||
List<NotificationDTO> notifications = new ArrayList<>();
|
|
||||||
list.forEach(notification -> {
|
list.forEach(notification -> {
|
||||||
NotificationDTO notificationDTO = genNotification(notification);
|
NotificationDTO notificationDTO = NotificationUtils.genNotification(notification);
|
||||||
// 判断关联数据是否已删除
|
// 判断关联数据是否已删除
|
||||||
if (Objects.nonNull(notificationDTO.getAuthor())) {
|
if (Objects.nonNull(notificationDTO.getAuthor())) {
|
||||||
notifications.add(notificationDTO);
|
BeanCopierUtil.copy(notificationDTO, notification);
|
||||||
} else {
|
} else {
|
||||||
// 关联数据已删除,且未读
|
// 关联数据已删除,且未读
|
||||||
if (unRead.equals(notification.getHasRead())) {
|
if (unRead.equals(notification.getHasRead())) {
|
||||||
@ -66,88 +49,10 @@ public class NotificationServiceImpl extends AbstractService<Notification> imple
|
|||||||
dto.setDataType("-1");
|
dto.setDataType("-1");
|
||||||
dto.setHasRead("1");
|
dto.setHasRead("1");
|
||||||
dto.setCreatedTime(notification.getCreatedTime());
|
dto.setCreatedTime(notification.getCreatedTime());
|
||||||
notifications.add(dto);
|
BeanCopierUtil.copy(dto, notification);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return notifications;
|
return list;
|
||||||
}
|
|
||||||
|
|
||||||
private NotificationDTO genNotification(Notification notification) {
|
|
||||||
NotificationDTO notificationDTO = new NotificationDTO();
|
|
||||||
BeanCopierUtil.copy(notification, notificationDTO);
|
|
||||||
ArticleDTO article;
|
|
||||||
Comment comment;
|
|
||||||
User user;
|
|
||||||
Follow follow;
|
|
||||||
switch (notification.getDataType()) {
|
|
||||||
case "0":
|
|
||||||
// 系统公告/帖子
|
|
||||||
article = articleService.findArticleDTOById(notification.getDataId(), 0);
|
|
||||||
if (Objects.nonNull(article)) {
|
|
||||||
notificationDTO.setDataTitle("系统公告");
|
|
||||||
notificationDTO.setDataUrl(article.getArticlePermalink());
|
|
||||||
user = userService.findById(article.getArticleAuthorId().toString());
|
|
||||||
notificationDTO.setAuthor(genAuthor(user));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "1":
|
|
||||||
// 关注
|
|
||||||
follow = followService.findById(notification.getDataId().toString());
|
|
||||||
notificationDTO.setDataTitle("关注提醒");
|
|
||||||
if (Objects.nonNull(follow)) {
|
|
||||||
user = userService.findById(follow.getFollowerId().toString());
|
|
||||||
notificationDTO.setDataUrl(getFollowLink(follow.getFollowingType(), user.getNickname()));
|
|
||||||
notificationDTO.setAuthor(genAuthor(user));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "2":
|
|
||||||
// 回帖
|
|
||||||
comment = commentService.findById(notification.getDataId().toString());
|
|
||||||
article = articleService.findArticleDTOById(comment.getCommentArticleId(), 0);
|
|
||||||
if (Objects.nonNull(article)) {
|
|
||||||
notificationDTO.setDataTitle(article.getArticleTitle());
|
|
||||||
notificationDTO.setDataUrl(comment.getCommentSharpUrl());
|
|
||||||
user = userService.findById(comment.getCommentAuthorId().toString());
|
|
||||||
notificationDTO.setAuthor(genAuthor(user));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case "3":
|
|
||||||
// 关注用户发布文章
|
|
||||||
case "4":
|
|
||||||
// 关注文章更新
|
|
||||||
article = articleService.findArticleDTOById(notification.getDataId(), 0);
|
|
||||||
if (Objects.nonNull(article)) {
|
|
||||||
notificationDTO.setDataTitle("关注通知");
|
|
||||||
notificationDTO.setDataUrl(article.getArticlePermalink());
|
|
||||||
user = userService.findById(article.getArticleAuthorId().toString());
|
|
||||||
notificationDTO.setAuthor(genAuthor(user));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return notificationDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getFollowLink(String followingType, String id) {
|
|
||||||
StringBuilder url = new StringBuilder();
|
|
||||||
url.append(domain);
|
|
||||||
switch (followingType) {
|
|
||||||
case "0":
|
|
||||||
url = url.append("/user/").append(id);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
url.append("/notification");
|
|
||||||
}
|
|
||||||
return url.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private Author genAuthor(User user) {
|
|
||||||
Author author = new Author();
|
|
||||||
author.setUserNickname(user.getNickname());
|
|
||||||
author.setUserAvatarURL(user.getAvatarUrl());
|
|
||||||
author.setIdUser(user.getIdUser());
|
|
||||||
return author;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -41,10 +41,7 @@ public class PortfolioServiceImpl extends AbstractService<Portfolio> implements
|
|||||||
@Override
|
@Override
|
||||||
public List<PortfolioDTO> findUserPortfoliosByUser(UserDTO userDTO) {
|
public List<PortfolioDTO> findUserPortfoliosByUser(UserDTO userDTO) {
|
||||||
List<PortfolioDTO> list = portfolioMapper.selectUserPortfoliosByIdUser(userDTO.getIdUser());
|
List<PortfolioDTO> list = portfolioMapper.selectUserPortfoliosByIdUser(userDTO.getIdUser());
|
||||||
Author author = new Author();
|
Author author = userService.selectAuthor(userDTO.getIdUser());
|
||||||
author.setIdUser(userDTO.getIdUser());
|
|
||||||
author.setUserAvatarURL(userDTO.getAvatarUrl());
|
|
||||||
author.setUserNickname(userDTO.getNickname());
|
|
||||||
list.forEach(portfolioDTO -> {
|
list.forEach(portfolioDTO -> {
|
||||||
genPortfolioAuthor(portfolioDTO,author);
|
genPortfolioAuthor(portfolioDTO,author);
|
||||||
});
|
});
|
||||||
@ -190,6 +187,11 @@ public class PortfolioServiceImpl extends AbstractService<Portfolio> implements
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Portfolio> findPortfolios() {
|
||||||
|
return portfolioMapper.selectPortfolios();
|
||||||
|
}
|
||||||
|
|
||||||
private PortfolioDTO genPortfolioAuthor(PortfolioDTO portfolioDTO, Author author) {
|
private PortfolioDTO genPortfolioAuthor(PortfolioDTO portfolioDTO, Author author) {
|
||||||
portfolioDTO.setPortfolioAuthorAvatarUrl(author.getUserAvatarURL());
|
portfolioDTO.setPortfolioAuthorAvatarUrl(author.getUserAvatarURL());
|
||||||
portfolioDTO.setPortfolioAuthorName(author.getUserNickname());
|
portfolioDTO.setPortfolioAuthorName(author.getUserNickname());
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import com.rymcu.forest.core.exception.TransactionException;
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
import com.rymcu.forest.dto.ArticleDTO;
|
import com.rymcu.forest.dto.ArticleDTO;
|
||||||
import com.rymcu.forest.entity.Sponsor;
|
import com.rymcu.forest.entity.Sponsor;
|
||||||
import com.rymcu.forest.entity.TransactionRecord;
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.enumerate.SponsorEnum;
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
import com.rymcu.forest.mapper.SponsorMapper;
|
import com.rymcu.forest.mapper.SponsorMapper;
|
||||||
import com.rymcu.forest.service.ArticleService;
|
import com.rymcu.forest.service.ArticleService;
|
||||||
import com.rymcu.forest.service.SponsorService;
|
import com.rymcu.forest.service.SponsorService;
|
||||||
@ -39,7 +42,7 @@ public class SponsorServiceImpl extends AbstractService<Sponsor> implements Spon
|
|||||||
map.put("success", false);
|
map.put("success", false);
|
||||||
map.put("message", "数据异常");
|
map.put("message", "数据异常");
|
||||||
} else {
|
} else {
|
||||||
SponsorEnum result = Arrays.stream(SponsorEnum.values()).filter(sponsorEnum -> sponsorEnum.getDataType().equals(sponsor.getDataType())).findFirst().orElse(SponsorEnum.Article);
|
TransactionEnum result = TransactionEnum.findTransactionEnum(sponsor.getDataType());
|
||||||
BigDecimal money = BigDecimal.valueOf(result.getMoney());
|
BigDecimal money = BigDecimal.valueOf(result.getMoney());
|
||||||
sponsor.setSponsorshipMoney(money);
|
sponsor.setSponsorshipMoney(money);
|
||||||
User user = UserUtils.getCurrentUserByToken();
|
User user = UserUtils.getCurrentUserByToken();
|
||||||
@ -47,11 +50,11 @@ public class SponsorServiceImpl extends AbstractService<Sponsor> implements Spon
|
|||||||
sponsor.setSponsorshipTime(new Date());
|
sponsor.setSponsorshipTime(new Date());
|
||||||
sponsorMapper.insertSelective(sponsor);
|
sponsorMapper.insertSelective(sponsor);
|
||||||
// 赞赏金额划转
|
// 赞赏金额划转
|
||||||
if (result.isArticle()) {
|
if (result.isArticleSponsor()) {
|
||||||
ArticleDTO articleDTO = articleService.findArticleDTOById(sponsor.getDataId(), 1);
|
ArticleDTO articleDTO = articleService.findArticleDTOById(sponsor.getDataId(), 1);
|
||||||
TransactionRecord transactionRecord = transactionRecordService.transferByUserId(articleDTO.getArticleAuthorId(), user.getIdUser(), money);
|
TransactionRecord transactionRecord = transactionRecordService.userTransfer(articleDTO.getArticleAuthorId(), user.getIdUser(), result);
|
||||||
if (Objects.isNull(transactionRecord.getIdTransactionRecord())) {
|
if (Objects.isNull(transactionRecord.getIdTransactionRecord())) {
|
||||||
throw new Exception("余额不足");
|
throw new TransactionException(TransactionCode.InsufficientBalance);
|
||||||
}
|
}
|
||||||
// 更新文章赞赏数
|
// 更新文章赞赏数
|
||||||
sponsorMapper.updateArticleSponsorCount(articleDTO.getIdArticle());
|
sponsorMapper.updateArticleSponsorCount(articleDTO.getIdArticle());
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
package com.rymcu.forest.service.impl;
|
package com.rymcu.forest.service.impl;
|
||||||
|
|
||||||
import com.rymcu.forest.core.exception.ServiceException;
|
import com.rymcu.forest.core.exception.TransactionException;
|
||||||
import com.rymcu.forest.core.service.AbstractService;
|
import com.rymcu.forest.core.service.AbstractService;
|
||||||
import com.rymcu.forest.core.service.redis.RedisService;
|
import com.rymcu.forest.core.service.redis.RedisService;
|
||||||
import com.rymcu.forest.dto.BankAccountDTO;
|
import com.rymcu.forest.dto.BankAccountDTO;
|
||||||
import com.rymcu.forest.dto.TransactionRecordDTO;
|
import com.rymcu.forest.dto.TransactionRecordDTO;
|
||||||
import com.rymcu.forest.entity.BankAccount;
|
import com.rymcu.forest.entity.BankAccount;
|
||||||
import com.rymcu.forest.entity.TransactionRecord;
|
import com.rymcu.forest.entity.TransactionRecord;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionCode;
|
||||||
|
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||||
import com.rymcu.forest.mapper.TransactionRecordMapper;
|
import com.rymcu.forest.mapper.TransactionRecordMapper;
|
||||||
import com.rymcu.forest.service.BankAccountService;
|
import com.rymcu.forest.service.BankAccountService;
|
||||||
import com.rymcu.forest.service.TransactionRecordService;
|
import com.rymcu.forest.service.TransactionRecordService;
|
||||||
@ -47,7 +49,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
|||||||
transactionRecordMapper.insertSelective(transactionRecord);
|
transactionRecordMapper.insertSelective(transactionRecord);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new Exception("余额不足");
|
throw new TransactionException(TransactionCode.InsufficientBalance);
|
||||||
}
|
}
|
||||||
return transactionRecord;
|
return transactionRecord;
|
||||||
}
|
}
|
||||||
@ -58,17 +60,42 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TransactionRecord transferByUserId(Integer toUserId, Integer formUserId, BigDecimal money) throws Exception {
|
public TransactionRecord userTransfer(Integer toUserId, Integer formUserId, TransactionEnum transactionType) throws Exception {
|
||||||
BankAccountDTO toBankAccount = bankAccountService.findBankAccountByIdUser(toUserId);
|
BankAccountDTO toBankAccount = bankAccountService.findBankAccountByIdUser(toUserId);
|
||||||
BankAccountDTO formBankAccount = bankAccountService.findBankAccountByIdUser(formUserId);
|
BankAccountDTO formBankAccount = bankAccountService.findBankAccountByIdUser(formUserId);
|
||||||
TransactionRecord transactionRecord = new TransactionRecord();
|
TransactionRecord transactionRecord = new TransactionRecord();
|
||||||
transactionRecord.setToBankAccount(toBankAccount.getBankAccount());
|
transactionRecord.setToBankAccount(toBankAccount.getBankAccount());
|
||||||
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
||||||
transactionRecord.setMoney(money);
|
transactionRecord.setMoney(new BigDecimal(transactionType.getMoney()));
|
||||||
transactionRecord.setFunds("赞赏");
|
transactionRecord.setFunds(transactionType.getDescription());
|
||||||
return transfer(transactionRecord);
|
return transfer(transactionRecord);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TransactionRecord bankTransfer(Integer idUser, TransactionEnum transactionType) throws Exception {
|
||||||
|
BankAccountDTO toBankAccount = bankAccountService.findBankAccountByIdUser(idUser);
|
||||||
|
Boolean isTrue;
|
||||||
|
// 校验货币规则
|
||||||
|
switch (transactionType) {
|
||||||
|
case Answer:
|
||||||
|
case CorrectAnswer:
|
||||||
|
isTrue = transactionRecordMapper.existsWithBankAccountAndFunds(toBankAccount.getBankAccount(), transactionType.getDescription());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
isTrue = true;
|
||||||
|
}
|
||||||
|
if (isTrue) {
|
||||||
|
BankAccount formBankAccount = bankAccountService.findSystemBankAccount();
|
||||||
|
TransactionRecord transactionRecord = new TransactionRecord();
|
||||||
|
transactionRecord.setToBankAccount(toBankAccount.getBankAccount());
|
||||||
|
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
||||||
|
transactionRecord.setMoney(new BigDecimal(transactionType.getMoney()));
|
||||||
|
transactionRecord.setFunds(transactionType.getDescription());
|
||||||
|
return transfer(transactionRecord);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
private String nextTransactionNo() {
|
private String nextTransactionNo() {
|
||||||
String orderNo = "E";
|
String orderNo = "E";
|
||||||
String key = "orderId";
|
String key = "orderId";
|
||||||
|
@ -22,10 +22,7 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Date;
|
import java.util.*;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -126,8 +123,8 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserDTO findUserDTOByNickname(String nickname) {
|
public UserDTO findUserDTOByAccount(String account) {
|
||||||
UserDTO user = userMapper.selectUserDTOByNickname(nickname);
|
UserDTO user = userMapper.selectUserDTOByAccount(account);
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,7 +251,7 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UserExtend selectUserExtendByNickname(String nickname) {
|
public UserExtend selectUserExtendByAccount(String nickname) {
|
||||||
return userExtendMapper.selectUserExtendByNickname(nickname);
|
return userExtendMapper.selectUserExtendByNickname(nickname);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -284,4 +281,9 @@ public class UserServiceImpl extends AbstractService<User> implements UserServic
|
|||||||
map.put("message", "更新成功!");
|
map.put("message", "更新成功!");
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<User> findUsers(UserSearchDTO searchDTO) {
|
||||||
|
return userMapper.selectUsers(searchDTO);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,17 @@
|
|||||||
package com.rymcu.forest.util;
|
package com.rymcu.forest.util;
|
||||||
|
|
||||||
import com.rymcu.forest.core.constant.NotificationConstant;
|
import com.rymcu.forest.core.constant.NotificationConstant;
|
||||||
|
import com.rymcu.forest.dto.ArticleDTO;
|
||||||
|
import com.rymcu.forest.dto.Author;
|
||||||
|
import com.rymcu.forest.dto.NotificationDTO;
|
||||||
|
import com.rymcu.forest.entity.Comment;
|
||||||
import com.rymcu.forest.entity.Follow;
|
import com.rymcu.forest.entity.Follow;
|
||||||
import com.rymcu.forest.entity.Notification;
|
import com.rymcu.forest.entity.Notification;
|
||||||
import com.rymcu.forest.entity.User;
|
import com.rymcu.forest.entity.User;
|
||||||
import com.rymcu.forest.service.FollowService;
|
import com.rymcu.forest.service.*;
|
||||||
import com.rymcu.forest.service.NotificationService;
|
|
||||||
import com.rymcu.forest.service.UserService;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -19,12 +21,13 @@ import java.util.concurrent.*;
|
|||||||
*/
|
*/
|
||||||
public class NotificationUtils {
|
public class NotificationUtils {
|
||||||
|
|
||||||
@Resource
|
|
||||||
private static NotificationService notificationService = SpringContextHolder.getBean(NotificationService.class);
|
private static NotificationService notificationService = SpringContextHolder.getBean(NotificationService.class);
|
||||||
@Resource
|
|
||||||
private static UserService userService = SpringContextHolder.getBean(UserService.class);
|
private static UserService userService = SpringContextHolder.getBean(UserService.class);
|
||||||
@Resource
|
|
||||||
private static FollowService followService = SpringContextHolder.getBean(FollowService.class);
|
private static FollowService followService = SpringContextHolder.getBean(FollowService.class);
|
||||||
|
private static JavaMailService mailService = SpringContextHolder.getBean(JavaMailService.class);
|
||||||
|
|
||||||
|
private static ArticleService articleService = SpringContextHolder.getBean(ArticleService.class);
|
||||||
|
private static CommentService commentService = SpringContextHolder.getBean(CommentService.class);
|
||||||
|
|
||||||
public static void sendAnnouncement(Integer dataId, String dataType, String dataSummary) {
|
public static void sendAnnouncement(Integer dataId, String dataType, String dataSummary) {
|
||||||
ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
|
||||||
@ -53,6 +56,11 @@ public class NotificationUtils {
|
|||||||
// TODO 记录操作失败数据
|
// TODO 记录操作失败数据
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (NotificationConstant.Comment.equals(dataType)) {
|
||||||
|
notification = notificationService.findNotification(idUser, dataId, dataType);
|
||||||
|
NotificationDTO notificationDTO = genNotification(notification);
|
||||||
|
mailService.sendNotification(notificationDTO);
|
||||||
|
}
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// TODO 记录操作失败数据
|
// TODO 记录操作失败数据
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
@ -83,4 +91,82 @@ public class NotificationUtils {
|
|||||||
return 0;
|
return 0;
|
||||||
}, executor);
|
}, executor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static NotificationDTO genNotification(Notification notification) {
|
||||||
|
NotificationDTO notificationDTO = new NotificationDTO();
|
||||||
|
BeanCopierUtil.copy(notification, notificationDTO);
|
||||||
|
ArticleDTO article;
|
||||||
|
Comment comment;
|
||||||
|
User user;
|
||||||
|
Follow follow;
|
||||||
|
switch (notification.getDataType()) {
|
||||||
|
case "0":
|
||||||
|
// 系统公告/帖子
|
||||||
|
article = articleService.findArticleDTOById(notification.getDataId(), 0);
|
||||||
|
if (Objects.nonNull(article)) {
|
||||||
|
notificationDTO.setDataTitle("系统公告");
|
||||||
|
notificationDTO.setDataUrl(article.getArticlePermalink());
|
||||||
|
user = userService.findById(article.getArticleAuthorId().toString());
|
||||||
|
notificationDTO.setAuthor(genAuthor(user));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "1":
|
||||||
|
// 关注
|
||||||
|
follow = followService.findById(notification.getDataId().toString());
|
||||||
|
notificationDTO.setDataTitle("关注提醒");
|
||||||
|
if (Objects.nonNull(follow)) {
|
||||||
|
user = userService.findById(follow.getFollowerId().toString());
|
||||||
|
notificationDTO.setDataUrl(getFollowLink(follow.getFollowingType(), user.getNickname()));
|
||||||
|
notificationDTO.setAuthor(genAuthor(user));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "2":
|
||||||
|
// 回帖
|
||||||
|
comment = commentService.findById(notification.getDataId().toString());
|
||||||
|
article = articleService.findArticleDTOById(comment.getCommentArticleId(), 0);
|
||||||
|
if (Objects.nonNull(article)) {
|
||||||
|
notificationDTO.setDataTitle(article.getArticleTitle());
|
||||||
|
notificationDTO.setDataUrl(comment.getCommentSharpUrl());
|
||||||
|
user = userService.findById(comment.getCommentAuthorId().toString());
|
||||||
|
notificationDTO.setAuthor(genAuthor(user));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "3":
|
||||||
|
// 关注用户发布文章
|
||||||
|
case "4":
|
||||||
|
// 关注文章更新
|
||||||
|
article = articleService.findArticleDTOById(notification.getDataId(), 0);
|
||||||
|
if (Objects.nonNull(article)) {
|
||||||
|
notificationDTO.setDataTitle("关注通知");
|
||||||
|
notificationDTO.setDataUrl(article.getArticlePermalink());
|
||||||
|
user = userService.findById(article.getArticleAuthorId().toString());
|
||||||
|
notificationDTO.setAuthor(genAuthor(user));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return notificationDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getFollowLink(String followingType, String id) {
|
||||||
|
StringBuilder url = new StringBuilder();
|
||||||
|
url.append(Utils.getProperty("resource.domain"));
|
||||||
|
switch (followingType) {
|
||||||
|
case "0":
|
||||||
|
url = url.append("/user/").append(id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
url.append("/notification");
|
||||||
|
}
|
||||||
|
return url.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Author genAuthor(User user) {
|
||||||
|
Author author = new Author();
|
||||||
|
author.setUserNickname(user.getNickname());
|
||||||
|
author.setUserAvatarURL(user.getAvatarUrl());
|
||||||
|
author.setIdUser(user.getIdUser());
|
||||||
|
return author;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import com.github.pagehelper.PageHelper;
|
|||||||
import com.github.pagehelper.PageInfo;
|
import com.github.pagehelper.PageInfo;
|
||||||
import com.rymcu.forest.core.result.GlobalResult;
|
import com.rymcu.forest.core.result.GlobalResult;
|
||||||
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
import com.rymcu.forest.core.result.GlobalResultGenerator;
|
||||||
|
import com.rymcu.forest.dto.UserSearchDTO;
|
||||||
import com.rymcu.forest.dto.admin.TopicTagDTO;
|
import com.rymcu.forest.dto.admin.TopicTagDTO;
|
||||||
import com.rymcu.forest.dto.admin.UserRoleDTO;
|
import com.rymcu.forest.dto.admin.UserRoleDTO;
|
||||||
import com.rymcu.forest.entity.*;
|
import com.rymcu.forest.entity.*;
|
||||||
@ -18,8 +19,6 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static java.util.Comparator.comparing;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
* */
|
* */
|
||||||
@ -39,11 +38,9 @@ public class AdminController {
|
|||||||
private SpecialDayService specialDayService;
|
private SpecialDayService specialDayService;
|
||||||
|
|
||||||
@GetMapping("/users")
|
@GetMapping("/users")
|
||||||
public GlobalResult<Map<String, Object>> users(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows){
|
public GlobalResult<Map<String, Object>> users(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, UserSearchDTO searchDTO){
|
||||||
PageHelper.startPage(page, rows);
|
PageHelper.startPage(page, rows);
|
||||||
List<User> list = userService.findAll();
|
List<User> list = userService.findUsers(searchDTO);
|
||||||
// 按最后登录时间进行倒序排序
|
|
||||||
list.sort(comparing(User::getLastLoginTime).reversed());
|
|
||||||
PageInfo<User> pageInfo = new PageInfo<>(list);
|
PageInfo<User> pageInfo = new PageInfo<>(list);
|
||||||
Map<String, Object> map = new HashMap<String, Object>(2);
|
Map<String, Object> map = new HashMap<String, Object>(2);
|
||||||
map.put("users", pageInfo.getList());
|
map.put("users", pageInfo.getList());
|
||||||
|
@ -61,7 +61,7 @@ public class ArticleController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@DeleteMapping("/delete/{id}")
|
@DeleteMapping("/delete/{id}")
|
||||||
public GlobalResult delete(@PathVariable Integer id) {
|
public GlobalResult delete(@PathVariable Integer id) throws BaseApiException {
|
||||||
Map map = articleService.delete(id);
|
Map map = articleService.delete(id);
|
||||||
return GlobalResultGenerator.genSuccessResult(map);
|
return GlobalResultGenerator.genSuccessResult(map);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package com.rymcu.forest.web.api.common;
|
package com.rymcu.forest.web.api.common;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.messaging.handler.annotation.MessageMapping;
|
import org.springframework.messaging.handler.annotation.MessageMapping;
|
||||||
import org.springframework.messaging.handler.annotation.SendTo;
|
import org.springframework.messaging.handler.annotation.SendTo;
|
||||||
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
import org.springframework.messaging.simp.SimpMessagingTemplate;
|
||||||
@ -9,7 +8,7 @@ import org.springframework.messaging.simp.annotation.SendToUser;
|
|||||||
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author ronger
|
* @author ronger
|
||||||
@ -17,42 +16,18 @@ import java.util.HashMap;
|
|||||||
@Controller
|
@Controller
|
||||||
public class WebSocketController {
|
public class WebSocketController {
|
||||||
|
|
||||||
@Autowired
|
@Resource
|
||||||
private SimpMessagingTemplate template;
|
private SimpMessagingTemplate template;
|
||||||
|
|
||||||
@MessageMapping("/sendMessage")
|
@MessageMapping("/sendMessage")
|
||||||
@SendTo("/public/greetings")
|
@SendTo("/topic/greening")
|
||||||
public void sendMessage(JSONObject message, StompHeaderAccessor headerAccessor){
|
public void sendMessage(JSONObject message, StompHeaderAccessor headerAccessor) {
|
||||||
this.template.convertAndSend("/public/greetings",message);
|
this.template.convertAndSend("/topic/greening", message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@MessageMapping("/message")
|
@MessageMapping("/message")
|
||||||
@SendToUser("/message")
|
@SendToUser("/message")
|
||||||
public void message(JSONObject message){
|
public void message(JSONObject message, StompHeaderAccessor headerAccessor) {
|
||||||
String type = message.get("type").toString();
|
this.template.convertAndSendToUser(message.getString("to"), "/message", message);
|
||||||
HashMap res = (HashMap) message.get("data");
|
|
||||||
HashMap mine = (HashMap) res.get("mine");
|
|
||||||
HashMap to = (HashMap) res.get("to");
|
|
||||||
System.out.println(to.get("type"));
|
|
||||||
boolean flag = to.get("type").equals("friend")?true:false;
|
|
||||||
String id = to.get("id").toString();
|
|
||||||
HashMap map = new HashMap();
|
|
||||||
map.put("id",mine.get("id"));
|
|
||||||
map.put("avatar",mine.get("avatar"));
|
|
||||||
map.put("formid",mine.get("id"));
|
|
||||||
map.put("username",mine.get("username"));
|
|
||||||
map.put("type",to.get("type"));
|
|
||||||
map.put("content",mine.get("content"));
|
|
||||||
map.put("mine",false);
|
|
||||||
map.put("cid",0);
|
|
||||||
map.put("timestamp","");
|
|
||||||
JSONObject json = new JSONObject();
|
|
||||||
json.put("type",type);
|
|
||||||
json.put("data",map);
|
|
||||||
if(flag){
|
|
||||||
this.template.convertAndSendToUser(id,"/message",json);
|
|
||||||
}else{
|
|
||||||
this.template.convertAndSendToUser(id,"/message",json);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -37,16 +37,16 @@ public class UserController {
|
|||||||
@Resource
|
@Resource
|
||||||
private FollowService followService;
|
private FollowService followService;
|
||||||
|
|
||||||
@GetMapping("/{nickname}")
|
@GetMapping("/{account}")
|
||||||
@VisitLogger
|
@VisitLogger
|
||||||
public GlobalResult detail(@PathVariable String nickname){
|
public GlobalResult detail(@PathVariable String account){
|
||||||
UserDTO userDTO = userService.findUserDTOByNickname(nickname);
|
UserDTO userDTO = userService.findUserDTOByAccount(account);
|
||||||
return GlobalResultGenerator.genSuccessResult(userDTO);
|
return GlobalResultGenerator.genSuccessResult(userDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{nickname}/articles")
|
@GetMapping("/{account}/articles")
|
||||||
public GlobalResult userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
|
public GlobalResult userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
|
||||||
UserDTO userDTO = userService.findUserDTOByNickname(nickname);
|
UserDTO userDTO = userService.findUserDTOByAccount(account);
|
||||||
if (userDTO == null){
|
if (userDTO == null){
|
||||||
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
||||||
}
|
}
|
||||||
@ -57,9 +57,9 @@ public class UserController {
|
|||||||
return GlobalResultGenerator.genSuccessResult(map);
|
return GlobalResultGenerator.genSuccessResult(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{nickname}/portfolios")
|
@GetMapping("/{account}/portfolios")
|
||||||
public GlobalResult userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
|
public GlobalResult userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
|
||||||
UserDTO userDTO = userService.findUserDTOByNickname(nickname);
|
UserDTO userDTO = userService.findUserDTOByAccount(account);
|
||||||
if (userDTO == null){
|
if (userDTO == null){
|
||||||
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
||||||
}
|
}
|
||||||
@ -73,9 +73,9 @@ public class UserController {
|
|||||||
return GlobalResultGenerator.genSuccessResult(map);
|
return GlobalResultGenerator.genSuccessResult(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{nickname}/followers")
|
@GetMapping("/{account}/followers")
|
||||||
public GlobalResult userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
|
public GlobalResult userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
|
||||||
UserDTO userDTO = userService.findUserDTOByNickname(nickname);
|
UserDTO userDTO = userService.findUserDTOByAccount(account);
|
||||||
if (userDTO == null){
|
if (userDTO == null){
|
||||||
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
||||||
}
|
}
|
||||||
@ -89,9 +89,9 @@ public class UserController {
|
|||||||
return GlobalResultGenerator.genSuccessResult(map);
|
return GlobalResultGenerator.genSuccessResult(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{nickname}/followings")
|
@GetMapping("/{account}/followings")
|
||||||
public GlobalResult userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){
|
public GlobalResult userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){
|
||||||
UserDTO userDTO = userService.findUserDTOByNickname(nickname);
|
UserDTO userDTO = userService.findUserDTOByAccount(account);
|
||||||
if (userDTO == null){
|
if (userDTO == null){
|
||||||
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
return GlobalResultGenerator.genErrorResult("用户不存在!");
|
||||||
}
|
}
|
||||||
@ -105,9 +105,9 @@ public class UserController {
|
|||||||
return GlobalResultGenerator.genSuccessResult(map);
|
return GlobalResultGenerator.genSuccessResult(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/{nickname}/user-extend")
|
@GetMapping("/{account}/user-extend")
|
||||||
public GlobalResult userExtend(@PathVariable String nickname) {
|
public GlobalResult userExtend(@PathVariable String account) {
|
||||||
UserExtend userExtend = userService.selectUserExtendByNickname(nickname);
|
UserExtend userExtend = userService.selectUserExtendByAccount(account);
|
||||||
return GlobalResultGenerator.genSuccessResult(userExtend);
|
return GlobalResultGenerator.genSuccessResult(userExtend);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package com.rymcu.forest.wx.mp.controller;
|
package com.rymcu.forest.wx.mp.controller;
|
||||||
|
|
||||||
|
import com.rymcu.forest.wx.mp.service.WxMenuService;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||||
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
|
import me.chanjar.weixin.common.bean.menu.WxMenuButton;
|
||||||
@ -7,8 +8,11 @@ import me.chanjar.weixin.common.error.WxErrorException;
|
|||||||
import me.chanjar.weixin.mp.api.WxMpService;
|
import me.chanjar.weixin.mp.api.WxMpService;
|
||||||
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
|
import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult;
|
||||||
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
|
import me.chanjar.weixin.mp.bean.menu.WxMpMenu;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
|
|
||||||
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
||||||
@ -21,7 +25,8 @@ import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
|||||||
@RequestMapping("/wx/menu/{appId}")
|
@RequestMapping("/wx/menu/{appId}")
|
||||||
public class WxMenuController {
|
public class WxMenuController {
|
||||||
private final WxMpService wxService;
|
private final WxMpService wxService;
|
||||||
|
@Resource
|
||||||
|
private WxMenuService wxMenuService;
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* 自定义菜单创建接口
|
* 自定义菜单创建接口
|
||||||
@ -38,52 +43,9 @@ public class WxMenuController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/create")
|
@GetMapping("/create")
|
||||||
public String menuCreateSample(@PathVariable String appId) throws WxErrorException, MalformedURLException {
|
public String menuCreateSample(@PathVariable String appId) throws WxErrorException, IOException {
|
||||||
WxMenu menu = new WxMenu();
|
|
||||||
WxMenuButton button1 = new WxMenuButton();
|
|
||||||
button1.setType(MenuButtonType.VIEW);
|
|
||||||
button1.setName("官方网站");
|
|
||||||
button1.setUrl("https://rymcu.com");
|
|
||||||
|
|
||||||
// WxMenuButton button2 = new WxMenuButton();
|
|
||||||
// button2.setType(WxConsts.BUTTON_MINIPROGRAM);
|
|
||||||
// button2.setName("小程序");
|
|
||||||
// button2.setAppId("wx286b93c14bbf93aa");
|
|
||||||
// button2.setPagePath("pages/lunar/index.html");
|
|
||||||
// button2.setUrl("http://mp.weixin.qq.com");
|
|
||||||
|
|
||||||
WxMenuButton button3 = new WxMenuButton();
|
|
||||||
button3.setName("学习教程");
|
|
||||||
|
|
||||||
menu.getButtons().add(button1);
|
|
||||||
// menu.getButtons().add(button2);
|
|
||||||
menu.getButtons().add(button3);
|
|
||||||
|
|
||||||
WxMenuButton button31 = new WxMenuButton();
|
|
||||||
button31.setType(MenuButtonType.VIEW);
|
|
||||||
button31.setName("51单片机入门教程");
|
|
||||||
button31.setUrl("https://mp.weixin.qq.com/mp/homepage?__biz=MzA3NjMzMzM1Mw==&hid=1&sn=672df75323f9976d990f6be14355070b");
|
|
||||||
|
|
||||||
// WxMenuButton button34 = new WxMenuButton();
|
|
||||||
// button34.setType(MenuButtonType.VIEW);
|
|
||||||
// button34.setName("获取用户信息");
|
|
||||||
//
|
|
||||||
// ServletRequestAttributes servletRequestAttributes =
|
|
||||||
// (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
|
|
||||||
// if (servletRequestAttributes != null) {
|
|
||||||
// HttpServletRequest request = servletRequestAttributes.getRequest();
|
|
||||||
// URL requestURL = new URL(request.getRequestURL().toString());
|
|
||||||
// String url = this.wxService.switchoverTo(appId).oauth2buildAuthorizationUrl(
|
|
||||||
// String.format("%s://%s/wx/redirect/%s/greet", requestURL.getProtocol(), requestURL.getHost(), appId),
|
|
||||||
// WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
|
|
||||||
// button34.setUrl(url);
|
|
||||||
// }
|
|
||||||
|
|
||||||
button3.getSubButtons().add(button31);
|
|
||||||
// button3.getSubButtons().add(button34);
|
|
||||||
|
|
||||||
this.wxService.switchover(appId);
|
this.wxService.switchover(appId);
|
||||||
return this.wxService.getMenuService().menuCreate(menu);
|
return this.wxService.getMenuService().menuCreate(wxMenuService.getMenus());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
package com.rymcu.forest.wx.mp.controller;
|
package com.rymcu.forest.wx.mp.controller;
|
||||||
|
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
|
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
|
||||||
|
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
|
||||||
import me.chanjar.weixin.common.error.WxErrorException;
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
import me.chanjar.weixin.mp.api.WxMpService;
|
import me.chanjar.weixin.mp.api.WxMpService;
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
|
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
@ -27,8 +27,8 @@ public class WxRedirectController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
WxMpOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
|
WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
|
||||||
WxMpUser user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
|
WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
|
||||||
map.put("user", user);
|
map.put("user", user);
|
||||||
} catch (WxErrorException e) {
|
} catch (WxErrorException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
|
@ -4,10 +4,10 @@ import com.rymcu.forest.service.WxUserService;
|
|||||||
import com.rymcu.forest.util.ContextHolderUtils;
|
import com.rymcu.forest.util.ContextHolderUtils;
|
||||||
import me.chanjar.weixin.common.api.WxConsts;
|
import me.chanjar.weixin.common.api.WxConsts;
|
||||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||||
|
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
|
||||||
import me.chanjar.weixin.common.error.WxErrorException;
|
import me.chanjar.weixin.common.error.WxErrorException;
|
||||||
import me.chanjar.weixin.common.util.http.URIUtil;
|
import me.chanjar.weixin.common.util.http.URIUtil;
|
||||||
import me.chanjar.weixin.mp.api.WxMpService;
|
import me.chanjar.weixin.mp.api.WxMpService;
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken;
|
|
||||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
@ -44,7 +44,7 @@ public class WxoAuthController {
|
|||||||
baseUrl = new StringBuilder(domain).append(contextPath);
|
baseUrl = new StringBuilder(domain).append(contextPath);
|
||||||
}
|
}
|
||||||
StringBuilder accessTokenUrl = baseUrl.append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(redirectUrl));
|
StringBuilder accessTokenUrl = baseUrl.append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(redirectUrl));
|
||||||
String oauth2Url = wxMpService.getOAuth2Service().buildAuthorizationUrl(accessTokenUrl.toString(), WxConsts.OAuth2Scope.SNSAPI_BASE, null);
|
String oauth2Url = wxMpService.getOAuth2Service().buildAuthorizationUrl(accessTokenUrl.toString(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
|
||||||
|
|
||||||
return "redirect:" + oauth2Url;
|
return "redirect:" + oauth2Url;
|
||||||
}
|
}
|
||||||
@ -52,14 +52,14 @@ public class WxoAuthController {
|
|||||||
@GetMapping("getAccessToken")
|
@GetMapping("getAccessToken")
|
||||||
public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
|
public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
|
||||||
wxMpService.switchoverTo(appId);
|
wxMpService.switchoverTo(appId);
|
||||||
WxMpOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
||||||
boolean valid = wxMpService.getOAuth2Service().validateAccessToken(oAuth2AccessToken);
|
boolean valid = wxMpService.getOAuth2Service().validateAccessToken(oAuth2AccessToken);
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new Exception("无权限");
|
throw new Exception("无权限");
|
||||||
}
|
}
|
||||||
|
|
||||||
WxMpUser wxMpUser =wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
|
WxMpUser wxMpUser = wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
|
||||||
wxUserService.saveUser(wxMpUser,appId);
|
wxUserService.saveUser(wxMpUser, appId);
|
||||||
ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
|
ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
|
||||||
return "redirect:" + redirectUrl;
|
return "redirect:" + redirectUrl;
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
package com.rymcu.forest.wx.mp.service;
|
||||||
|
|
||||||
|
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
public interface WxMenuService {
|
||||||
|
/**
|
||||||
|
* 获取公众号菜单配置
|
||||||
|
* @return
|
||||||
|
* @throws IOException
|
||||||
|
*/
|
||||||
|
WxMenu getMenus() throws IOException;
|
||||||
|
}
|
@ -0,0 +1,46 @@
|
|||||||
|
package com.rymcu.forest.wx.mp.service.impl;
|
||||||
|
|
||||||
|
import com.rymcu.forest.wx.mp.service.WxMenuService;
|
||||||
|
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Scanner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author ronger
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
public class WxMenuServiceImpl implements WxMenuService {
|
||||||
|
@Value("classpath:wxMpMenus.json")
|
||||||
|
private Resource menuResource;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public WxMenu getMenus() throws IOException {
|
||||||
|
File file = menuResource.getFile();
|
||||||
|
String menuJson = this.jsonRead(file);
|
||||||
|
WxMenu wxMenu = WxMenu.fromJson(menuJson);
|
||||||
|
return wxMenu;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String jsonRead(File file) {
|
||||||
|
Scanner scanner = null;
|
||||||
|
StringBuilder buffer = new StringBuilder();
|
||||||
|
try {
|
||||||
|
scanner = new Scanner(file, "utf-8");
|
||||||
|
while (scanner.hasNextLine()) {
|
||||||
|
buffer.append(scanner.nextLine());
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
if (scanner != null) {
|
||||||
|
scanner.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return buffer.toString();
|
||||||
|
}
|
||||||
|
}
|
@ -97,6 +97,9 @@
|
|||||||
<delete id="deleteLinkedPortfolioData">
|
<delete id="deleteLinkedPortfolioData">
|
||||||
delete from forest_portfolio_article where id_article = #{id}
|
delete from forest_portfolio_article where id_article = #{id}
|
||||||
</delete>
|
</delete>
|
||||||
|
<delete id="deleteArticleContent">
|
||||||
|
delete from forest_article_content where id_article = #{idArticle}
|
||||||
|
</delete>
|
||||||
<select id="selectArticles" resultMap="DTOResultMap">
|
<select id="selectArticles" resultMap="DTOResultMap">
|
||||||
select art.*,su.nickname,su.avatar_url from forest_article art join forest_user su on art.article_author_id = su.id
|
select art.*,su.nickname,su.avatar_url from forest_article art join forest_user su on art.article_author_id = su.id
|
||||||
where article_status = 0
|
where article_status = 0
|
||||||
@ -142,12 +145,14 @@
|
|||||||
and instr(art.article_title, #{searchText}) > 0 and art.id not in (select id_article from forest_portfolio_article where id_portfolio = #{idPortfolio}) order by updated_time desc
|
and instr(art.article_title, #{searchText}) > 0 and art.id not in (select id_article from forest_portfolio_article where id_portfolio = #{idPortfolio}) order by updated_time desc
|
||||||
</select>
|
</select>
|
||||||
<select id="selectPortfolioArticles" resultMap="PortfolioArticleResultMap">
|
<select id="selectPortfolioArticles" resultMap="PortfolioArticleResultMap">
|
||||||
select vp.portfolio_title,vp.portfolio_head_img_url,vpa.id_portfolio,vpa.id_article,vpa.sort_no from forest_portfolio vp join forest_portfolio_article vpa on vp.id = vpa.id_portfolio where vpa.id_article = #{idArticle}
|
select vp.portfolio_title,vp.portfolio_head_img_url,vpa.id_portfolio,vpa.id_article,vpa.sort_no from forest_portfolio vp
|
||||||
|
join forest_portfolio_article vpa on vp.id = vpa.id_portfolio where vpa.id_article = #{idArticle}
|
||||||
</select>
|
</select>
|
||||||
<select id="existsCommentWithPrimaryKey" resultType="java.lang.Boolean">
|
<select id="existsCommentWithPrimaryKey" resultType="java.lang.Boolean">
|
||||||
select exists (select * from forest_comment where comment_article_id = #{id})
|
select exists (select * from forest_comment where comment_article_id = #{id})
|
||||||
</select>
|
</select>
|
||||||
<select id="selectPortfolioArticlesByIdPortfolioAndSortNo" resultMap="DTOResultMap">
|
<select id="selectPortfolioArticlesByIdPortfolioAndSortNo" resultMap="DTOResultMap">
|
||||||
select va.article_title, va.id, va.article_permalink from forest_portfolio_article vpa join forest_article va on va.id = vpa.id_article where id_portfolio = #{idPortfolio} order by sort_no
|
select va.article_title, va.id, va.article_permalink from forest_portfolio_article vpa
|
||||||
|
join forest_article va on va.id = vpa.id_article where va.article_status = '0' and id_portfolio = #{idPortfolio} order by sort_no
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -33,6 +33,7 @@
|
|||||||
<result column="id" property="idUser"/>
|
<result column="id" property="idUser"/>
|
||||||
<result column="nickname" property="userNickname"/>
|
<result column="nickname" property="userNickname"/>
|
||||||
<result column="avatar_url" property="userAvatarURL"/>
|
<result column="avatar_url" property="userAvatarURL"/>
|
||||||
|
<result column="account" property="userAccount"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<update id="updateCommentSharpUrl">
|
<update id="updateCommentSharpUrl">
|
||||||
update forest_comment set comment_sharp_url = #{commentSharpUrl} where id = #{idComment}
|
update forest_comment set comment_sharp_url = #{commentSharpUrl} where id = #{idComment}
|
||||||
@ -41,9 +42,9 @@
|
|||||||
select * from forest_comment where comment_article_id = #{idArticle} order by created_time desc
|
select * from forest_comment where comment_article_id = #{idArticle} order by created_time desc
|
||||||
</select>
|
</select>
|
||||||
<select id="selectAuthor" resultMap="AuthorResultMap">
|
<select id="selectAuthor" resultMap="AuthorResultMap">
|
||||||
select id,nickname,avatar_url from forest_user where id = #{commentAuthorId}
|
select id,nickname,avatar_url,account from forest_user where id = #{commentAuthorId}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectCommentOriginalAuthor" resultMap="AuthorResultMap">
|
<select id="selectCommentOriginalAuthor" resultMap="AuthorResultMap">
|
||||||
select vu.id,vu.nickname,vu.avatar_url from forest_comment vc left join forest_user vu on vu.id = vc.comment_author_id where vc.id = #{commentOriginalCommentId}
|
select vu.id,vu.nickname,vu.avatar_url,vu.account from forest_comment vc left join forest_user vu on vu.id = vc.comment_author_id where vc.id = #{commentOriginalCommentId}
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -10,6 +10,15 @@
|
|||||||
<result column="has_read" property="hasRead"></result>
|
<result column="has_read" property="hasRead"></result>
|
||||||
<result column="created_time" property="createdTime"></result>
|
<result column="created_time" property="createdTime"></result>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
<resultMap id="DTOResultMapper" type="com.rymcu.forest.dto.NotificationDTO">
|
||||||
|
<id column="id" property="idNotification"></id>
|
||||||
|
<result column="id_user" property="idUser"></result>
|
||||||
|
<result column="data_type" property="dataType"></result>
|
||||||
|
<result column="data_id" property="dataId"></result>
|
||||||
|
<result column="data_summary" property="dataSummary"></result>
|
||||||
|
<result column="has_read" property="hasRead"></result>
|
||||||
|
<result column="created_time" property="createdTime"></result>
|
||||||
|
</resultMap>
|
||||||
<insert id="insertNotification">
|
<insert id="insertNotification">
|
||||||
insert into forest_notification (id_user, data_type, data_id, data_summary, created_time) values (#{idUser}, #{dataType}, #{dataId}, #{dataSummary}, sysdate())
|
insert into forest_notification (id_user, data_type, data_id, data_summary, created_time) values (#{idUser}, #{dataType}, #{dataId}, #{dataSummary}, sysdate())
|
||||||
</insert>
|
</insert>
|
||||||
@ -19,8 +28,8 @@
|
|||||||
<select id="selectUnreadNotifications" resultMap="BaseResultMapper">
|
<select id="selectUnreadNotifications" resultMap="BaseResultMapper">
|
||||||
select * from forest_notification where has_read = '0' and id_user = #{idUser} order by created_time desc
|
select * from forest_notification where has_read = '0' and id_user = #{idUser} order by created_time desc
|
||||||
</select>
|
</select>
|
||||||
<select id="selectNotifications" resultMap="BaseResultMapper">
|
<select id="selectNotifications" resultMap="DTOResultMapper">
|
||||||
select * from forest_notification where id_user = #{idUser} order by created_time desc
|
select * from forest_notification where id_user = #{idUser} order by has_read,created_time desc
|
||||||
</select>
|
</select>
|
||||||
<select id="selectNotification" resultMap="BaseResultMapper">
|
<select id="selectNotification" resultMap="BaseResultMapper">
|
||||||
select * from forest_notification where id_user = #{idUser} and data_id = #{dataId} and data_type = #{dataType}
|
select * from forest_notification where id_user = #{idUser} and data_id = #{dataId} and data_type = #{dataType}
|
||||||
|
@ -51,4 +51,7 @@
|
|||||||
<select id="selectMaxSortNo" resultType="java.lang.Integer">
|
<select id="selectMaxSortNo" resultType="java.lang.Integer">
|
||||||
select ifnull(max(sort_no),0) + 1 from forest_portfolio_article where id_portfolio = #{idPortfolio}
|
select ifnull(max(sort_no),0) + 1 from forest_portfolio_article where id_portfolio = #{idPortfolio}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectPortfolios" resultMap="BaseResultMap">
|
||||||
|
select * from forest_portfolio order by updated_time desc
|
||||||
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -13,6 +13,6 @@
|
|||||||
select portfolio_title as label, id as value, 'portfolio' as type from forest_portfolio
|
select portfolio_title as label, id as value, 'portfolio' as type from forest_portfolio
|
||||||
</select>
|
</select>
|
||||||
<select id="searchInitialUserSearch" resultMap="BaseResultMap">
|
<select id="searchInitialUserSearch" resultMap="BaseResultMap">
|
||||||
select nickname as label, nickname as value, 'user' as type from forest_user where status = 0
|
select nickname as label, account as value, 'user' as type from forest_user where status = 0
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -16,6 +16,10 @@
|
|||||||
update forest_bank_account set account_balance = account_balance + #{money} where bank_account = #{toBankAccount};
|
update forest_bank_account set account_balance = account_balance + #{money} where bank_account = #{toBankAccount};
|
||||||
</update>
|
</update>
|
||||||
<select id="selectTransactionRecords" resultMap="DTOResultMap">
|
<select id="selectTransactionRecords" resultMap="DTOResultMap">
|
||||||
select * from forest_transaction_record where form_bank_account = #{bankAccount} or to_bank_account = #{bankAccount}
|
select * from forest_transaction_record where form_bank_account = #{bankAccount} or to_bank_account = #{bankAccount} order by transaction_time desc
|
||||||
|
</select>
|
||||||
|
<select id="existsWithBankAccountAndFunds" resultType="java.lang.Boolean">
|
||||||
|
select ifnull((select false from forest_transaction_record where to_bank_account = #{bankAccount}
|
||||||
|
and funds = #{funds} and transaction_time > str_to_date(date_format(sysdate(),'%Y-%m-%d'),'%Y-%m-%d') limit 1), true)
|
||||||
</select>
|
</select>
|
||||||
</mapper>
|
</mapper>
|
@ -45,6 +45,7 @@
|
|||||||
<result column="id" property="idUser"/>
|
<result column="id" property="idUser"/>
|
||||||
<result column="nickname" property="userNickname"/>
|
<result column="nickname" property="userNickname"/>
|
||||||
<result column="avatar_url" property="userAvatarURL"/>
|
<result column="avatar_url" property="userAvatarURL"/>
|
||||||
|
<result column="account" property="userAccount"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
<insert id="insertUserRole">
|
<insert id="insertUserRole">
|
||||||
insert into forest_user_role (id_user,id_role,created_time) values (#{idUser},#{idRole},sysdate())
|
insert into forest_user_role (id_user,id_role,created_time) values (#{idUser},#{idRole},sysdate())
|
||||||
@ -81,8 +82,8 @@
|
|||||||
<select id="findUserInfoByAccount" resultMap="UserInfoResultMapper">
|
<select id="findUserInfoByAccount" resultMap="UserInfoResultMapper">
|
||||||
select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time from forest_user where account = #{account}
|
select id, nickname, sex, avatar_type, avatar_url, email, phone, account, status, signature, last_login_time from forest_user where account = #{account}
|
||||||
</select>
|
</select>
|
||||||
<select id="selectUserDTOByNickname" resultMap="DTOResultMapper">
|
<select id="selectUserDTOByAccount" resultMap="DTOResultMapper">
|
||||||
select id, nickname, avatar_type, avatar_url, account, signature from forest_user where nickname = #{nickname} and status = 0
|
select id, nickname, avatar_type, avatar_url, account, signature from forest_user where account = #{account} and status = 0
|
||||||
</select>
|
</select>
|
||||||
<select id="selectRoleWeightsByUser" resultType="java.lang.Integer">
|
<select id="selectRoleWeightsByUser" resultType="java.lang.Integer">
|
||||||
select vr.weights from forest_role vr left join forest_user_role vur on vr.id = vur.id_role where vur.id_user = #{idUser}
|
select vr.weights from forest_role vr left join forest_user_role vur on vr.id = vur.id_role where vur.id_user = #{idUser}
|
||||||
@ -99,5 +100,14 @@
|
|||||||
<select id="selectAuthor" resultMap="AuthorResultMap">
|
<select id="selectAuthor" resultMap="AuthorResultMap">
|
||||||
select * from forest_user where id = #{id}
|
select * from forest_user where id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
<select id="selectUsers" resultMap="BaseResultMap">
|
||||||
|
select id, nickname, sex, avatar_type, avatar_url, email, account, status, last_login_time, created_time from forest_user
|
||||||
|
<where>
|
||||||
|
<if test="searchDTO.nickname != null and searchDTO.nickname != ''">
|
||||||
|
and instr(nickname, #{searchDTO.nickname}) > 0
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
order by last_login_time desc
|
||||||
|
</select>
|
||||||
|
|
||||||
</mapper>
|
</mapper>
|
@ -84,7 +84,7 @@ create table forest_comment
|
|||||||
comment_original_comment_id bigint null comment '父评论 id',
|
comment_original_comment_id bigint null comment '父评论 id',
|
||||||
comment_status char default '0' null comment '状态',
|
comment_status char default '0' null comment '状态',
|
||||||
comment_ip varchar(128) null comment '评论 IP',
|
comment_ip varchar(128) null comment '评论 IP',
|
||||||
comment_ua varchar(128) null comment 'User-Agent',
|
comment_ua varchar(512) null comment 'User-Agent',
|
||||||
comment_anonymous char null comment '0:公开回帖,1:匿名回帖',
|
comment_anonymous char null comment '0:公开回帖,1:匿名回帖',
|
||||||
comment_reply_count int null comment '回帖计数',
|
comment_reply_count int null comment '回帖计数',
|
||||||
comment_visible char null comment '0:所有人可见,1:仅楼主和自己可见',
|
comment_visible char null comment '0:所有人可见,1:仅楼主和自己可见',
|
||||||
|
BIN
src/main/resources/static/logo_size.jpg
Normal file
BIN
src/main/resources/static/logo_size.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.3 KiB |
BIN
src/main/resources/static/logo_size_invert.jpg
Normal file
BIN
src/main/resources/static/logo_size_invert.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
162
src/main/resources/templates/mail/commentNotification.html
Normal file
162
src/main/resources/templates/mail/commentNotification.html
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"
|
||||||
|
xmlns:th="http://www.thymeleaf.org">
|
||||||
|
<head>
|
||||||
|
<title> RYMCU 消息通知 </title>
|
||||||
|
<!--[if !mso]> -->
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||||
|
<!--<![endif]-->
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<style type="text/css">
|
||||||
|
#outlook a {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
table,
|
||||||
|
td {
|
||||||
|
border-collapse: collapse;
|
||||||
|
mso-table-lspace: 0pt;
|
||||||
|
mso-table-rspace: 0pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border: 0;
|
||||||
|
height: auto;
|
||||||
|
line-height: 100%;
|
||||||
|
outline: none;
|
||||||
|
text-decoration: none;
|
||||||
|
-ms-interpolation-mode: bicubic;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
display: block;
|
||||||
|
margin: 13px 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<!--[if mso]>
|
||||||
|
<xml>
|
||||||
|
<o:OfficeDocumentSettings>
|
||||||
|
<o:AllowPNG/>
|
||||||
|
<o:PixelsPerInch>96</o:PixelsPerInch>
|
||||||
|
</o:OfficeDocumentSettings>
|
||||||
|
</xml>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if lte mso 11]>
|
||||||
|
<style type="text/css">
|
||||||
|
.mj-outlook-group-fix {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<![endif]-->
|
||||||
|
<!--[if !mso]><!-->
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Quattrocento:wght@400;700&display=swap" rel="stylesheet"
|
||||||
|
type="text/css"/>
|
||||||
|
<style type="text/css">
|
||||||
|
@import url(https://fonts.googleapis.com/css2?family=Quattrocento:wght@400;700&display=swap);
|
||||||
|
</style>
|
||||||
|
<!--<![endif]-->
|
||||||
|
<style type="text/css">
|
||||||
|
@media only screen and (min-width: 480px) {
|
||||||
|
.mj-column-per-100 {
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
@media only screen and (max-width: 480px) {
|
||||||
|
table.mj-full-width-mobile {
|
||||||
|
width: 100% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.mj-full-width-mobile {
|
||||||
|
width: auto !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style type="text/css">
|
||||||
|
a,
|
||||||
|
span,
|
||||||
|
td,
|
||||||
|
th {
|
||||||
|
-webkit-font-smoothing: antialiased !important;
|
||||||
|
-moz-osx-font-smoothing: grayscale !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body style="background-color:#f6ab0c;text-align: center;">
|
||||||
|
<div style="background-color:#ffffff;margin:0px auto;border-radius:8px 8px 0 0;max-width:600px;">
|
||||||
|
<div style="max-width:600px;">
|
||||||
|
<div style="margin-top: 40px;">
|
||||||
|
<table align="center">
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td width="150" style="padding: 20px 0;">
|
||||||
|
<img alt="Logo" height="auto"
|
||||||
|
src="https://static.rymcu.com/article/1619013470064"
|
||||||
|
style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:14px;"
|
||||||
|
width="150">
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td width="200">
|
||||||
|
<img alt="welcome image" height="auto"
|
||||||
|
src="https://static.rymcu.com/article/1619013419068"
|
||||||
|
style="border:0;display:block;outline:none;text-decoration:none;height:auto;width:100%;font-size:14px;"
|
||||||
|
width="200"/>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-size:18px;font-weight:400;line-height:24px;text-align:left;color:#000000;">
|
||||||
|
<h1 style="margin: 0; font-size: 32px; line-height: 40px; font-weight: 700;">
|
||||||
|
消息通知</h1>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td align="left" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-size:18px;font-weight:400;line-height:24px;text-align:left;color:#000000;">
|
||||||
|
<div style="margin: 0;">
|
||||||
|
<span th:text="${user}"></span> 评论了您的文章《 <span th:text="${articleTitle}"></span>》:
|
||||||
|
</div>
|
||||||
|
<div th:text="*{content}"></div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div style="margin:0px auto;max-width:600px;">
|
||||||
|
<div class="mj-column-per-100 mj-outlook-group-fix" style="font-size:0px;text-align:left;direction:ltr;display:inline-block;vertical-align:top;width:100%;">
|
||||||
|
<table border="0" cellpadding="0" cellspacing="0" role="presentation" style="vertical-align:top;" width="100%">
|
||||||
|
<tbody><tr>
|
||||||
|
<td align="center" style="font-size:0px;padding:10px 25px;word-break:break-word;">
|
||||||
|
<div style="font-family:Quattrocento;font-size:16px;font-weight:400;line-height:24px;text-align:center;color:#333333;">
|
||||||
|
<a th:href="${url}" style="color: #428dfc; text-decoration: none; font-weight: bold;"> 点击这里进行查看 </a>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody></table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
26
src/main/resources/wxMpMenus.json
Normal file
26
src/main/resources/wxMpMenus.json
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
{
|
||||||
|
"menu": {
|
||||||
|
"button": [
|
||||||
|
{
|
||||||
|
"type": "view",
|
||||||
|
"name": "官方网站",
|
||||||
|
"url": "https://rymcu.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "view",
|
||||||
|
"name": "交流群",
|
||||||
|
"url": "https://mp.weixin.qq.com/s/0XDVL3mgrSpeGEALOQz-4Q"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "学习教程",
|
||||||
|
"sub_button": [
|
||||||
|
{
|
||||||
|
"type": "view",
|
||||||
|
"name": "51单片机入门教程",
|
||||||
|
"url": "https://mp.weixin.qq.com/mp/homepage?__biz=MzA3NjMzMzM1Mw==&hid=1&sn=672df75323f9976d990f6be14355070b"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user