diff --git a/README.md b/README.md index 810561c..7942e77 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # 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 这个项目。 -forest 在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony) 和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。 +在 2019 年的某一天,受到 [Hugh](https://rymcu.com/user/RYMCU-J) 的邀请, 构建一个开源嵌入式知识学习交流平台。因此就有了 forest 这个项目。 forest +在很多方面受到了 [Symphony](https://github.com/88250/symphony) 的启发,并尝试着在 [Symphony](https://github.com/88250/symphony) +和 [B3log 思想](https://ld246.com/article/1546941897596) 的基础上进一步探索。 -## ✨ 特性 +## ✨ 特性 -``` -内容编辑器 - Markdown(GFM) - Emoji - 上传文件 - 图片 - 文件 - 单独渲染 MP3 - 单独渲染视频 - 剪贴板处理 - 粘贴内容处理为 Markdown - 粘贴图片自动重新上传 - 数学公式(LaTeX)、流程图支持 - 快捷键支持 - 工具栏 - 表情 - 粗体 - 斜体 - 引用 - 无序列表 - 有序列表 - 链接 - 上传 - 预览 - 全屏 - 编辑模式 - 传统的 Markdown 分屏编辑预览 - 保留 Markdown 标记符的即时渲染 - 类富文本编辑器的所见即所得 -注册 - 用户名 - Email - 验证码 - 邮件验证 - 新手向导 - 上传头像 - 关注标签 - 关注用户 - 帮助指引 -登录 - 账户(用户名/Email) - 密码 - 忘记密码 - Email - 验证码 -发帖 - 帖子类型 - 普通帖子 - 标题 - 正文 - 内容编辑器 - 本地存储 - 标签 - 使用已有(选择、自动完成)或创建 - 过滤 - 黑白名单 - 规范化 - 默认“待分类” - 发布后 - 可更新 - 可删除 -回帖 - 内容编辑器 - 本地存储 - 回复(回复针对回帖) -货币 - 货币规则 -浏览帖子 - 实时热度 - 编辑自己的帖子 - 发布时间/浏览数/回帖数/标签 - 上一篇/下一篇 - 分享 - 微信 - QQ - 分享链接(带用户标识) - 相关帖子 - 缩略摘要 -帖子列表 - 专题 - 相关标签 - 最新 - 优选 - 搜索 - 标签 - 相关标签 - 创建者 - 贡献者 - 关注/引用/回帖数 - 所属专题 - 关注 - 排序 - 默认(按发布时间降序) - 热议(按回帖数降序) - 好评(按评分降序) - 最近回帖(按最近回帖时间降序) - 首图 - 实时热度 - 最新回复 - 回帖数 - 创建时间 -后台管理 - 后台首页 - 数据统计 - 当前在线 - 会员在线 - 最高在线 - 会员 - 帖子 - 专题 - 标签 - 回帖 - 用户管理 - 按用户名/邮件搜索 - 添加新用户 - 用户数据维护 - 各字段数据 - 用户状态 - 正常 - 未验证 - 限制登录 - 封禁 - 高级更新 - 用户名 - 邮箱地址 - 帖子管理 - 按 id 搜索帖子 - 重建所有帖子搜索索引 - 添加新帖 - 帖子数据维护 - 锁定帖子 - 删除帖子 - 专题管理 - 按名称搜索专题 - 添加专题 - 专题数据维护 - 添加/移除相关标签 - 名称 - URI - 描述 - 图标 - 是否用于导航 - 状态 - CSS - SEO - title - keywords - description - 删除专题 - 标签管理 - 按名称搜索标签 - 添加标签 - 标签数据维护 - 名称 - URI - 描述 - 图标 - 状态 - CSS - SEO - title - keywords - description - 角色管理 - 内建角色 - 管理员 - 社区管理员 - 作者 - 普通用户 - 创建角色 - 功能权限 -浏览统计 - 实时统计 - 会员 - 帖子 - 专题 - 标签 - 回帖 - 数据统计 - 最近 30 天 - 历史 - 新发贴数 - 新用户数 -消息通知 - 消息数 - 标记已读 - 消息类别 - 收到的回帖 - 收到的回复 - 收到的评论 - 提及我的 - 关注 - 我关注的 - 关注的用户发帖 -个人主页 - 用户统计数据 - 积分 - 关注标签 - 收藏帖子 - 关注者 - 关注用户 - 站点连接 -首页 - 专题、发帖、通知、个人等入口 - 专题导航列表 - 对搜索引擎爬虫友好 -用户设置 - 基本信息 - 昵称 - URL - 个性签名 - 个人主页背景图 - 个人卡片背景图 - 站点连接 - GitHub - 微博 - QQ - 微信 - 头像 - 账号 - 绑定邮箱 - 更新密码 - 更新用户名 - 永久停用账号 - 钱包 - 交易记录 - 帮助 - 使用入门 - 基础知识 - Markdown 教程 -评论 - 发布评论 -``` +- 内容编辑器 + - Markdown(GFM) + - emoji + - 上传文件 + - 图片 + - 文件 + - 单独渲染 MP3 文件 + - 单独渲染视频文件 + - 剪切板处理 + - 粘贴内容处理为 Markdown + - 粘贴图片自动重新上传 + - 数学公式(LaTeX)、流程图支持 + - 工具栏 + - 表情 + - 粗体 + - 斜体 + - 引用 + - 无序列表 + - 有序列表 + - 链接 + - 上传 + - 预览 + - 全屏 + - 编辑模式 + - 传统的 Markdown 分屏编辑预览 + - 保留 Markdown 标记符的即时渲染 + - 类富文本编辑器的所见即所得 +- 注册 + - 用户名 + - 邮箱 + - 验证码 +- 登录 + - 账户(用户名/邮箱) + - 密码 + - 忘记密码 + - 邮箱 + - 邮箱验证 +- 发帖 + - 帖子类型 + - 普通帖子 + - 标题 + - 正文 + - 内容编辑器 + - 标签 + - 使用已有(选择、自动完成)或创建 + - 默认“待分类” + - 发布后 + - 可更新 + - 可删除 +- 回帖 + - 内容编辑器 + - 回复(回复针对回帖) +- 货币 + - 货币规则 +- 浏览贴子 + - 编辑自己的帖子 + - 发布时间/浏览数/标签 + - 分享 + - 微信 + - 分享链接(带用户标识) -## 报告缺陷 +## 报告缺陷 > 社区系统可能存在一些潜在的缺陷,大家如果有空的话可以帮助我们一起解决。 @@ -260,4 +88,8 @@ forest 在很多方面受到了 [Symphony](https://github.com/88250/symphony) 欢迎对社区提出功能特性方面的建议,我们一起讨论,如果有可能我们会尽快实现。 -在提功能建议前可以先看一下 [计划表](https://rymcu.com/article/29) ,避免重复提议 \ No newline at end of file +在提功能建议前可以先看一下 [计划表](https://rymcu.com/article/29) ,避免重复提议 + +## 鸣谢 +- 感谢 `JetBrains` 对本项目的帮助,为作者提供了开源许可版 `JetBrains` 全家桶 +![JetBrains](src/main/resources/static/jetbrains.png) \ No newline at end of file diff --git a/pom.xml b/pom.xml index a4b7411..d42e26b 100644 --- a/pom.xml +++ b/pom.xml @@ -89,19 +89,19 @@ com.github.pagehelper pagehelper - 5.1.10 + 5.2.0 com.alibaba fastjson - 1.2.67 + 1.2.76 org.apache.shiro shiro-spring - 1.4.1 + 1.7.1 @@ -173,7 +173,7 @@ com.github.binarywang weixin-java-open - 3.9.0 + 4.0.0 commons-codec @@ -183,8 +183,17 @@ commons-io commons-io + + com.thoughtworks.xstream + xstream + + + com.thoughtworks.xstream + xstream + 1.4.16 + com.github.jedis-lock jedis-lock diff --git a/src/main/java/com/rymcu/forest/ForestApplication.java b/src/main/java/com/rymcu/forest/ForestApplication.java index 9a945f8..6279091 100644 --- a/src/main/java/com/rymcu/forest/ForestApplication.java +++ b/src/main/java/com/rymcu/forest/ForestApplication.java @@ -3,6 +3,9 @@ package com.rymcu.forest; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +/** + * @author ronger + */ @SpringBootApplication public class ForestApplication { diff --git a/src/main/java/com/rymcu/forest/answer/AnswerController.java b/src/main/java/com/rymcu/forest/answer/AnswerController.java index 0ebfd5c..92df131 100644 --- a/src/main/java/com/rymcu/forest/answer/AnswerController.java +++ b/src/main/java/com/rymcu/forest/answer/AnswerController.java @@ -2,9 +2,10 @@ package com.rymcu.forest.answer; import com.alibaba.fastjson.JSONObject; 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.entity.User; +import com.rymcu.forest.enumerate.TransactionEnum; import com.rymcu.forest.util.HttpUtils; import com.rymcu.forest.util.UserUtils; import com.rymcu.forest.web.api.exception.BaseApiException; @@ -30,6 +31,7 @@ public class AnswerController { } @PostMapping("/answer") + @TransactionLogger(transactionType = TransactionEnum.Answer) public GlobalResult answer(@RequestBody AnswerDTO answerDTO) throws BaseApiException { User user = UserUtils.getCurrentUserByToken(); Map params = new HashMap<>(3); diff --git a/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java b/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java index 5d60bf3..a73714f 100644 --- a/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java +++ b/src/main/java/com/rymcu/forest/config/BaseExceptionHandler.java @@ -2,8 +2,10 @@ package com.rymcu.forest.config; import com.alibaba.fastjson.support.spring.FastJsonJsonView; 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.ResultCode; +import com.rymcu.forest.enumerate.TransactionCode; import com.rymcu.forest.web.api.exception.BaseApiException; import org.apache.shiro.authz.UnauthenticatedException; import org.apache.shiro.authz.UnauthorizedException; @@ -25,7 +27,7 @@ import java.util.Map; * 全局异常处理器 * * @author ronger - * */ + */ @RestControllerAdvice public class BaseExceptionHandler { @@ -33,10 +35,10 @@ public class BaseExceptionHandler { @SuppressWarnings("Duplicates") @ExceptionHandler(Exception.class) - public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex){ - if(isAjax(request)){ + public Object errorHandler(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) { + if (isAjax(request)) { GlobalResult result = new GlobalResult(); - if (ex instanceof BaseApiException){ + if (ex instanceof BaseApiException) { result.setCode(401); result.setMessage("用户未登录"); logger.info("用户未登录"); @@ -48,7 +50,7 @@ public class BaseExceptionHandler { result.setCode(1000002); result.setMessage("用户无权限"); logger.info("用户无权限"); - }else if (ex instanceof ServiceException) { + } else if (ex instanceof ServiceException) { //业务失败的异常,如“账号或密码错误” result.setCode(((ServiceException) ex).getCode()); result.setMessage(ex.getMessage()); @@ -59,7 +61,10 @@ public class BaseExceptionHandler { } else if (ex instanceof ServletException) { result.setCode(ResultCode.FAIL.getCode()); 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()); String message; @@ -78,11 +83,11 @@ public class BaseExceptionHandler { } result.setSuccess(false); return result; - }else { + } else { ModelAndView mv = new ModelAndView(); FastJsonJsonView view = new FastJsonJsonView(); Map attributes = new HashMap(2); - if (ex instanceof BaseApiException){ + if (ex instanceof BaseApiException) { attributes.put("code", "401"); attributes.put("message", "用户未登录"); } else if (ex instanceof UnauthenticatedException) { @@ -93,18 +98,21 @@ public class BaseExceptionHandler { attributes.put("message", "用户无权限"); } else if (ex instanceof ServiceException) { //业务失败的异常,如“账号或密码错误” - attributes.put("code",((ServiceException) ex).getCode()); - attributes.put("message",ex.getMessage()); + attributes.put("code", ((ServiceException) ex).getCode()); + attributes.put("message", ex.getMessage()); logger.info(ex.getMessage()); } else if (ex instanceof NoHandlerFoundException) { - attributes.put("code",ResultCode.NOT_FOUND.getCode()); - attributes.put("message",ResultCode.NOT_FOUND.getMessage()); + attributes.put("code", ResultCode.NOT_FOUND.getCode()); + attributes.put("message", ResultCode.NOT_FOUND.getMessage()); } else if (ex instanceof ServletException) { - attributes.put("code",ResultCode.FAIL.getCode()); - attributes.put("message",ex.getMessage()); - }else { + attributes.put("code", ResultCode.FAIL.getCode()); + attributes.put("message", ex.getMessage()); + } 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; if (handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; @@ -117,9 +125,9 @@ public class BaseExceptionHandler { message = ex.getMessage(); } logger.error(message, ex); - attributes.put("message","操作失败"); + attributes.put("message", "操作失败"); } - attributes.put("success",false); + attributes.put("success", false); view.setAttributesMap(attributes); mv.setView(view); return mv; diff --git a/src/main/java/com/rymcu/forest/config/BaseShiroRealm.java b/src/main/java/com/rymcu/forest/config/BaseShiroRealm.java index 46aa766..bdd6323 100644 --- a/src/main/java/com/rymcu/forest/config/BaseShiroRealm.java +++ b/src/main/java/com/rymcu/forest/config/BaseShiroRealm.java @@ -29,7 +29,7 @@ import java.util.List; * @author ronger * @since 2018/05/28 11:00 * 自定义权限匹配和账号密码匹配 - * */ + */ public class BaseShiroRealm extends AuthorizingRealm { @Resource private RoleService roleService; @@ -43,13 +43,13 @@ public class BaseShiroRealm extends AuthorizingRealm { @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); - Principal principal = (Principal)principals.getPrimaryPrincipal(); + Principal principal = (Principal) principals.getPrimaryPrincipal(); User user = new User(); user.setIdUser(principal.getId()); try { List roles = roleService.selectRoleByUser(user); for (Role role : roles) { - if(StringUtils.isNotBlank(role.getInputCode())){ + if (StringUtils.isNotBlank(role.getInputCode())) { authorizationInfo.addRole(role.getInputCode()); } } @@ -70,7 +70,7 @@ public class BaseShiroRealm extends AuthorizingRealm { /** * 认证回调函数, 登录时调用,主要是用来进行身份认证的,也就是说验证用户输入的账号和密码是否正确。 - * */ + */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException { UsernamePasswordToken token = (UsernamePasswordToken) authcToken; @@ -90,10 +90,11 @@ public class BaseShiroRealm extends AuthorizingRealm { if (user == null) { return null; } - if (!"0".equals(user.getStatus())) { //账户冻结(是否允许登陆) + // 账户冻结(是否允许登陆) + if (!"0".equals(user.getStatus())) { 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()), 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; @@ -139,9 +140,9 @@ public class BaseShiroRealm extends AuthorizingRealm { * 获取SESSIONID */ public String getSessionid() { - try{ + try { return (String) Utils.getSession().getId(); - }catch (Exception e) { + } catch (Exception e) { return ""; } } diff --git a/src/main/java/com/rymcu/forest/config/MybatisConfigurer.java b/src/main/java/com/rymcu/forest/config/MybatisConfigurer.java index 594882c..9aa708d 100644 --- a/src/main/java/com/rymcu/forest/config/MybatisConfigurer.java +++ b/src/main/java/com/rymcu/forest/config/MybatisConfigurer.java @@ -45,7 +45,7 @@ public class MybatisConfigurer { //添加XML目录 ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver(); factory.setMapperLocations(resolver.getResources("classpath:mapper/**/*.xml")); - factory.setTypeHandlersPackage("com.rymcu.forest.util.handlers"); +// factory.setTypeHandlersPackage("com.rymcu.forest.util.handlers"); return factory.getObject(); } diff --git a/src/main/java/com/rymcu/forest/config/ShiroConfig.java b/src/main/java/com/rymcu/forest/config/ShiroConfig.java index c539574..4b02b82 100644 --- a/src/main/java/com/rymcu/forest/config/ShiroConfig.java +++ b/src/main/java/com/rymcu/forest/config/ShiroConfig.java @@ -55,6 +55,7 @@ public class ShiroConfig implements EnvironmentAware { filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/ws/**", "anon"); + filterChainDefinitionMap.put("/wss/**", "anon"); filterChainDefinitionMap.put("/wx/**", "anon"); filterChainDefinitionMap.put("/**", "auth"); //配置shiro默认登录界面地址,前后端分离中登录界面跳转应由前端路由控制,后台仅返回json数据 diff --git a/src/main/java/com/rymcu/forest/config/WebSocketStompConfig.java b/src/main/java/com/rymcu/forest/config/WebSocketStompConfig.java index a158e49..acce4a8 100644 --- a/src/main/java/com/rymcu/forest/config/WebSocketStompConfig.java +++ b/src/main/java/com/rymcu/forest/config/WebSocketStompConfig.java @@ -20,6 +20,7 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer { public void registerStompEndpoints(StompEndpointRegistry registry) { // 允许使用socketJs方式访问 即可通过http://IP:PORT/ws来和服务端websocket连接 registry.addEndpoint("/ws").setAllowedOrigins("*").withSockJS(); + registry.addEndpoint("/wss").setAllowedOrigins("*").withSockJS(); } /** @@ -30,7 +31,7 @@ public class WebSocketStompConfig implements WebSocketMessageBrokerConfigurer { public void configureMessageBroker(MessageBrokerRegistry registry) { // 订阅Broker名称 user点对点 topic广播即群发 - registry.enableSimpleBroker("/user","/public"); + registry.enableSimpleBroker("/topic", "/user"); // 全局(客户端)使用的消息前缀 registry.setApplicationDestinationPrefixes("/app"); // 点对点使用的前缀 无需配置 默认/user diff --git a/src/main/java/com/rymcu/forest/core/constant/ShiroConstants.java b/src/main/java/com/rymcu/forest/core/constant/ShiroConstants.java index 8b7476d..1c5d116 100644 --- a/src/main/java/com/rymcu/forest/core/constant/ShiroConstants.java +++ b/src/main/java/com/rymcu/forest/core/constant/ShiroConstants.java @@ -2,10 +2,10 @@ package com.rymcu.forest.core.constant; /** * 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"; /** * 验证码错误 diff --git a/src/main/java/com/rymcu/forest/core/exception/TransactionException.java b/src/main/java/com/rymcu/forest/core/exception/TransactionException.java new file mode 100644 index 0000000..5ecb5dd --- /dev/null +++ b/src/main/java/com/rymcu/forest/core/exception/TransactionException.java @@ -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; + } +} diff --git a/src/main/java/com/rymcu/forest/core/result/ResultCode.java b/src/main/java/com/rymcu/forest/core/result/ResultCode.java index c0f894e..40c43fe 100644 --- a/src/main/java/com/rymcu/forest/core/result/ResultCode.java +++ b/src/main/java/com/rymcu/forest/core/result/ResultCode.java @@ -2,18 +2,22 @@ package com.rymcu.forest.core.result; /** * 响应码枚举,参考HTTP状态码的语义 + * + * @author ronger */ public enum ResultCode { - SUCCESS(1, "SUCCESS"),//成功 - FAIL(400, "访问失败"),//失败 - UNAUTHORIZED(401, "签名错误"),//未认证(签名错误) - NOT_FOUND(404, "此接口不存在"),//接口不存在 - INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"),//服务器内部错误 - INVALID_PARAM(10000, "参数错误"), - - - - ; + // 成功 + SUCCESS(1, "SUCCESS"), + // 失败 + FAIL(400, "访问失败"), + // 未认证(签名错误) + UNAUTHORIZED(401, "签名错误"), + // 接口不存在 + NOT_FOUND(404, "此接口不存在"), + // 服务器内部错误 + INTERNAL_SERVER_ERROR(500, "系统繁忙,请稍后再试"), + // 参数错误 + INVALID_PARAM(10000, "参数错误"); private int code; private String message; diff --git a/src/main/java/com/rymcu/forest/core/service/AbstractService.java b/src/main/java/com/rymcu/forest/core/service/AbstractService.java index a1e2eb2..b609462 100644 --- a/src/main/java/com/rymcu/forest/core/service/AbstractService.java +++ b/src/main/java/com/rymcu/forest/core/service/AbstractService.java @@ -13,13 +13,17 @@ import java.util.List; /** * 基于通用MyBatis Mapper插件的Service接口的实现 + * + * @author ronger */ public abstract class AbstractService implements Service { @Autowired protected Mapper mapper; - - private Class modelClass; // 当前泛型真实类型的Class + /** + * 当前泛型真实类型的Class + */ + private Class modelClass; public AbstractService() { ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass(); diff --git a/src/main/java/com/rymcu/forest/core/service/Service.java b/src/main/java/com/rymcu/forest/core/service/Service.java index bf69a13..b755c14 100644 --- a/src/main/java/com/rymcu/forest/core/service/Service.java +++ b/src/main/java/com/rymcu/forest/core/service/Service.java @@ -8,16 +8,85 @@ import java.util.List; /** * Service 层 基础接口,其他Service 接口 请继承该接口 + * + * @author ronger */ public interface Service { - void save(T model);//持久化 - void save(List models);//批量持久化 - void deleteById(String id);//通过主鍵刪除 - void deleteByIds(String ids);//批量刪除 eg:ids -> “1,2,3,4” - void update(T model);//更新 - T findById(String id);//通过ID查找 - T findBy(String fieldName, Object value) throws TooManyResultsException, ServiceException; //通过Model中某个成员变量名称(非数据表中column的名称)查找,value需符合unique约束 - List findByIds(String ids);//通过多个ID查找//eg:ids -> “1,2,3,4” - List findByCondition(Condition condition);//根据条件查找 - List findAll();//获取所有 + /** + * 持久化 + * + * @param model + */ + void save(T model); + + /** + * 批量持久化 + * + * @param models + */ + void save(List 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 findByIds(String ids); + + /** + * 根据条件查找 + * + * @param condition + * @return + */ + List findByCondition(Condition condition); + + /** + * 获取所有 + * + * @return + */ + List findAll(); } diff --git a/src/main/java/com/rymcu/forest/core/service/log/TransactionAspect.java b/src/main/java/com/rymcu/forest/core/service/log/TransactionAspect.java new file mode 100644 index 0000000..0f017c0 --- /dev/null +++ b/src/main/java/com/rymcu/forest/core/service/log/TransactionAspect.java @@ -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; + } +} diff --git a/src/main/java/com/rymcu/forest/core/service/log/annotation/TransactionLogger.java b/src/main/java/com/rymcu/forest/core/service/log/annotation/TransactionLogger.java new file mode 100644 index 0000000..452aa3b --- /dev/null +++ b/src/main/java/com/rymcu/forest/core/service/log/annotation/TransactionLogger.java @@ -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(); + +} diff --git a/src/main/java/com/rymcu/forest/dto/Author.java b/src/main/java/com/rymcu/forest/dto/Author.java index 5dca54e..3782f01 100644 --- a/src/main/java/com/rymcu/forest/dto/Author.java +++ b/src/main/java/com/rymcu/forest/dto/Author.java @@ -12,6 +12,8 @@ public class Author { private String userNickname; + private String userAccount; + private String userAvatarURL; private String userArticleCount; diff --git a/src/main/java/com/rymcu/forest/dto/UserSearchDTO.java b/src/main/java/com/rymcu/forest/dto/UserSearchDTO.java new file mode 100644 index 0000000..f645f60 --- /dev/null +++ b/src/main/java/com/rymcu/forest/dto/UserSearchDTO.java @@ -0,0 +1,12 @@ +package com.rymcu.forest.dto; + +import lombok.Data; + +/** + * @author ronger + */ +@Data +public class UserSearchDTO { + + private String nickname; +} diff --git a/src/main/java/com/rymcu/forest/enumerate/SponsorEnum.java b/src/main/java/com/rymcu/forest/enumerate/SponsorEnum.java deleted file mode 100644 index 7efc1e7..0000000 --- a/src/main/java/com/rymcu/forest/enumerate/SponsorEnum.java +++ /dev/null @@ -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); - } -} diff --git a/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java b/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java new file mode 100644 index 0000000..233331a --- /dev/null +++ b/src/main/java/com/rymcu/forest/enumerate/TransactionCode.java @@ -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; + } +} diff --git a/src/main/java/com/rymcu/forest/enumerate/TransactionEnum.java b/src/main/java/com/rymcu/forest/enumerate/TransactionEnum.java new file mode 100644 index 0000000..fcfe846 --- /dev/null +++ b/src/main/java/com/rymcu/forest/enumerate/TransactionEnum.java @@ -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); + } +} diff --git a/src/main/java/com/rymcu/forest/mapper/ArticleMapper.java b/src/main/java/com/rymcu/forest/mapper/ArticleMapper.java index 4f9d5ca..58a34d2 100644 --- a/src/main/java/com/rymcu/forest/mapper/ArticleMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/ArticleMapper.java @@ -184,4 +184,10 @@ public interface ArticleMapper extends Mapper
{ * @return */ int updatePerfect(@Param("idArticle") Integer idArticle, @Param("articlePerfect") String articlePerfect); + + /** + * 删除文章关联文章内容表信息 + * @param idArticle + */ + void deleteArticleContent(@Param("idArticle") Integer idArticle); } diff --git a/src/main/java/com/rymcu/forest/mapper/NotificationMapper.java b/src/main/java/com/rymcu/forest/mapper/NotificationMapper.java index 8a3dd6f..2ae27ad 100644 --- a/src/main/java/com/rymcu/forest/mapper/NotificationMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/NotificationMapper.java @@ -1,6 +1,7 @@ package com.rymcu.forest.mapper; import com.rymcu.forest.core.mapper.Mapper; +import com.rymcu.forest.dto.NotificationDTO; import com.rymcu.forest.entity.Notification; import org.apache.ibatis.annotations.Param; @@ -23,7 +24,7 @@ public interface NotificationMapper extends Mapper { * @param idUser * @return */ - List selectNotifications(@Param("idUser") Integer idUser); + List selectNotifications(@Param("idUser") Integer idUser); /** * 获取消息数据 diff --git a/src/main/java/com/rymcu/forest/mapper/PortfolioMapper.java b/src/main/java/com/rymcu/forest/mapper/PortfolioMapper.java index 7439e31..d90c0b0 100644 --- a/src/main/java/com/rymcu/forest/mapper/PortfolioMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/PortfolioMapper.java @@ -73,4 +73,10 @@ public interface PortfolioMapper extends Mapper { * @return */ Integer unbindArticle(@Param("idPortfolio") Integer idPortfolio, @Param("idArticle") Integer idArticle); + + /** + * 获取作品集列表数据 + * @return + */ + List selectPortfolios(); } diff --git a/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java b/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java index e181c85..75c1b3f 100644 --- a/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/TransactionRecordMapper.java @@ -27,4 +27,12 @@ public interface TransactionRecordMapper extends Mapper { * @return */ List selectTransactionRecords(@Param("bankAccount") String bankAccount); + + /** + * 校验今日是否已发放答题奖励 + * @param bankAccount + * @param funds + * @return + */ + Boolean existsWithBankAccountAndFunds(@Param("bankAccount") String bankAccount, @Param("funds") String funds); } diff --git a/src/main/java/com/rymcu/forest/mapper/UserMapper.java b/src/main/java/com/rymcu/forest/mapper/UserMapper.java index 901e765..f23b726 100644 --- a/src/main/java/com/rymcu/forest/mapper/UserMapper.java +++ b/src/main/java/com/rymcu/forest/mapper/UserMapper.java @@ -4,9 +4,12 @@ import com.rymcu.forest.core.mapper.Mapper; import com.rymcu.forest.dto.Author; import com.rymcu.forest.dto.UserDTO; import com.rymcu.forest.dto.UserInfoDTO; +import com.rymcu.forest.dto.UserSearchDTO; import com.rymcu.forest.entity.User; import org.apache.ibatis.annotations.Param; +import java.util.List; + /** * @author ronger */ @@ -36,10 +39,10 @@ public interface UserMapper extends Mapper { /** * 根据用户昵称获取用户信息 - * @param nickname + * @param account * @return */ - UserDTO selectUserDTOByNickname(@Param("nickname") String nickname); + UserDTO selectUserDTOByAccount(@Param("account") String account); /** * 修改用户密码 @@ -136,4 +139,11 @@ public interface UserMapper extends Mapper { * @return */ Integer updatePasswordById(@Param("idUser") Integer idUser, @Param("password") String password); + + /** + * 查询用户数据 + * @param searchDTO + * @return + */ + List selectUsers(@Param("searchDTO") UserSearchDTO searchDTO); } \ No newline at end of file diff --git a/src/main/java/com/rymcu/forest/service/ArticleService.java b/src/main/java/com/rymcu/forest/service/ArticleService.java index f839ed5..f564de9 100644 --- a/src/main/java/com/rymcu/forest/service/ArticleService.java +++ b/src/main/java/com/rymcu/forest/service/ArticleService.java @@ -67,7 +67,7 @@ public interface ArticleService extends Service
{ * @param id * @return * */ - Map delete(Integer id); + Map delete(Integer id) throws BaseApiException; /** * 增量文章浏览数 diff --git a/src/main/java/com/rymcu/forest/service/BankAccountService.java b/src/main/java/com/rymcu/forest/service/BankAccountService.java index a764f7b..fa355e7 100644 --- a/src/main/java/com/rymcu/forest/service/BankAccountService.java +++ b/src/main/java/com/rymcu/forest/service/BankAccountService.java @@ -32,4 +32,10 @@ public interface BankAccountService extends Service { * @return */ BankAccount findByBankAccount(String bankAccount); + + /** + * 查询系统社区银行 + * @return + */ + BankAccount findSystemBankAccount(); } diff --git a/src/main/java/com/rymcu/forest/service/JavaMailService.java b/src/main/java/com/rymcu/forest/service/JavaMailService.java index 269cd20..761d3c6 100644 --- a/src/main/java/com/rymcu/forest/service/JavaMailService.java +++ b/src/main/java/com/rymcu/forest/service/JavaMailService.java @@ -1,5 +1,7 @@ package com.rymcu.forest.service; +import com.rymcu.forest.dto.NotificationDTO; + import javax.mail.MessagingException; /** @@ -12,6 +14,7 @@ public interface JavaMailService { * 发送验证码邮件 * @param email 收件人邮箱 * @return 执行结果 0:失败1:成功 + * @throws MessagingException * */ Integer sendEmailCode(String email) throws MessagingException; @@ -19,6 +22,15 @@ public interface JavaMailService { * 发送找回密码邮件 * @param email 收件人邮箱 * @return 执行结果 0:失败1:成功 + * @throws MessagingException * */ Integer sendForgetPasswordEmail(String email) throws MessagingException; + + /** + * 发送下消息通知 + * @param notification + * @return + * @throws MessagingException + */ + Integer sendNotification(NotificationDTO notification) throws MessagingException; } diff --git a/src/main/java/com/rymcu/forest/service/PortfolioService.java b/src/main/java/com/rymcu/forest/service/PortfolioService.java index 9413ccd..df8d2e7 100644 --- a/src/main/java/com/rymcu/forest/service/PortfolioService.java +++ b/src/main/java/com/rymcu/forest/service/PortfolioService.java @@ -77,4 +77,10 @@ public interface PortfolioService extends Service { * @return */ Map deletePortfolio(Integer idPortfolio); + + /** + * 获取作品集列表数据 + * @return + */ + List findPortfolios(); } diff --git a/src/main/java/com/rymcu/forest/service/TransactionRecordService.java b/src/main/java/com/rymcu/forest/service/TransactionRecordService.java index feb08ed..2f0acdd 100644 --- a/src/main/java/com/rymcu/forest/service/TransactionRecordService.java +++ b/src/main/java/com/rymcu/forest/service/TransactionRecordService.java @@ -3,6 +3,7 @@ package com.rymcu.forest.service; import com.rymcu.forest.core.service.Service; import com.rymcu.forest.dto.TransactionRecordDTO; import com.rymcu.forest.entity.TransactionRecord; +import com.rymcu.forest.enumerate.TransactionEnum; import java.math.BigDecimal; import java.util.List; @@ -30,9 +31,18 @@ public interface TransactionRecordService extends Service { * 根据用户主键进行交易 * @param toUserId * @param formUserId - * @param money + * @param transactionType * @return * @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; } diff --git a/src/main/java/com/rymcu/forest/service/UserService.java b/src/main/java/com/rymcu/forest/service/UserService.java index 87530c4..31ad8c3 100644 --- a/src/main/java/com/rymcu/forest/service/UserService.java +++ b/src/main/java/com/rymcu/forest/service/UserService.java @@ -6,6 +6,7 @@ import com.rymcu.forest.entity.User; import com.rymcu.forest.entity.UserExtend; import org.apache.ibatis.exceptions.TooManyResultsException; +import java.util.List; import java.util.Map; @@ -42,11 +43,11 @@ public interface UserService extends Service { Map login(String account, String password); /** - * 通过 nickname 获取用户信息接口 - * @param nickname 昵称 + * 通过 account 获取用户信息接口 + * @param account 昵称 * @return UserDTO * */ - UserDTO findUserDTOByNickname(String nickname); + UserDTO findUserDTOByAccount(String account); /** * 找回密码接口 @@ -117,10 +118,10 @@ public interface UserService extends Service { /** * 获取用户扩展信息 - * @param nickname + * @param account * @return */ - UserExtend selectUserExtendByNickname(String nickname); + UserExtend selectUserExtendByAccount(String account); /** * 更换邮箱 @@ -135,4 +136,11 @@ public interface UserService extends Service { * @return */ Map updatePassword(UpdatePasswordDTO updatePasswordDTO); + + /** + * 查询用户列表 + * @param searchDTO + * @return + */ + List findUsers(UserSearchDTO searchDTO); } diff --git a/src/main/java/com/rymcu/forest/service/impl/ArticleServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/ArticleServiceImpl.java index e389e44..a23b9ae 100644 --- a/src/main/java/com/rymcu/forest/service/impl/ArticleServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/ArticleServiceImpl.java @@ -203,9 +203,14 @@ public class ArticleServiceImpl extends AbstractService
implements Arti } if (StringUtils.isNotBlank(articleContentHtml)) { - String previewContent = BaiDuAipUtils.getNewsSummary(newArticle.getArticleTitle(), articleContentHtml, MAX_PREVIEW); - if (previewContent.length() > MAX_PREVIEW) { - previewContent = previewContent.substring(0, MAX_PREVIEW); + String previewContent; + if (articleContentHtml.length() > 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); } @@ -260,8 +265,18 @@ public class ArticleServiceImpl extends AbstractService
implements Arti @Override @Transactional(rollbackFor = Exception.class) - public Map delete(Integer id) { + public Map delete(Integer id) throws BaseApiException { Map 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; // 判断是否有评论 boolean isHavComment = articleMapper.existsCommentWithPrimaryKey(id); @@ -285,6 +300,8 @@ public class ArticleServiceImpl extends AbstractService
implements Arti articleMapper.deleteLinkedPortfolioData(id); // 删除引用标签记录 articleMapper.deleteTagArticle(id); + // 删除文章内容表 + articleMapper.deleteArticleContent(id); } @Override @@ -398,9 +415,11 @@ public class ArticleServiceImpl extends AbstractService
implements Arti private Author genAuthor(ArticleDTO article) { Author author = new Author(); + User user = userService.findById(String.valueOf(article.getArticleAuthorId())); author.setUserNickname(article.getArticleAuthorName()); author.setUserAvatarURL(article.getArticleAuthorAvatarUrl()); author.setIdUser(article.getArticleAuthorId()); + author.setUserAccount(user.getAccount()); return author; } } diff --git a/src/main/java/com/rymcu/forest/service/impl/BankAccountServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/BankAccountServiceImpl.java index 714f372..5721464 100644 --- a/src/main/java/com/rymcu/forest/service/impl/BankAccountServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/BankAccountServiceImpl.java @@ -67,6 +67,15 @@ public class BankAccountServiceImpl extends AbstractService impleme 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() { String bankAccount = "600000001"; String maxBankAccount = bankAccountMapper.selectMaxBankAccount(); diff --git a/src/main/java/com/rymcu/forest/service/impl/JavaMailServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/JavaMailServiceImpl.java index 0b40654..fe4f4cc 100644 --- a/src/main/java/com/rymcu/forest/service/impl/JavaMailServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/JavaMailServiceImpl.java @@ -1,7 +1,11 @@ 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.dto.NotificationDTO; +import com.rymcu.forest.entity.User; import com.rymcu.forest.service.JavaMailService; +import com.rymcu.forest.service.UserService; import com.rymcu.forest.util.Utils; import org.apache.commons.lang.time.StopWatch; import org.springframework.beans.factory.annotation.Value; @@ -34,6 +38,8 @@ public class JavaMailServiceImpl implements JavaMailService { private JavaMailSenderImpl mailSender; @Resource private RedisService redisService; + @Resource + private UserService userService; /** * thymeleaf模板引擎 */ @@ -53,12 +59,49 @@ public class JavaMailServiceImpl implements JavaMailService { @Override public Integer sendEmailCode(String email) throws MessagingException { - return sendCode(email,0); + return sendCode(email, 0); } @Override 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 thymeleafTemplateVariable = new HashMap(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 { @@ -79,29 +122,29 @@ public class JavaMailServiceImpl implements JavaMailService { SimpleMailMessage simpleMailMessage = new SimpleMailMessage(); simpleMailMessage.setFrom(USERNAME); simpleMailMessage.setTo(to); - if(type == 0) { + if (type == 0) { Integer code = Utils.genCode(); - redisService.set(to,code,5*60); + redisService.set(to, code, 5 * 60); simpleMailMessage.setSubject("新用户注册邮箱验证"); simpleMailMessage.setText("【RYMCU】您的校验码是 " + code + ",有效时间 5 分钟,请不要泄露验证码给其他人。如非本人操作,请忽略!"); mailSender.send(simpleMailMessage); return 1; - } else if(type == 1){ + } else if (type == 1) { String code = Utils.entryptPassword(to); String url = BASE_URL + "/forget-password?code=" + code; - redisService.set(code,to,15*60); + redisService.set(code, to, 15 * 60); - String thymeleafTemplatePath = "mail/forgetPasswordTemplate"; - Map thymeleafTemplateVariable = new HashMap(); - thymeleafTemplateVariable.put("url", url); + String thymeleafTemplatePath = "mail/forgetPasswordTemplate"; + Map thymeleafTemplateVariable = new HashMap(1); + thymeleafTemplateVariable.put("url", url); - sendTemplateEmail(USERNAME, - new String[] { to }, - new String[] {}, - "【RYMCU】 找回密码", - thymeleafTemplatePath, - thymeleafTemplateVariable); - return 1; + sendTemplateEmail(USERNAME, + new String[]{to}, + new String[]{}, + "【RYMCU】 找回密码", + thymeleafTemplatePath, + thymeleafTemplateVariable); + return 1; } return 0; } @@ -109,25 +152,19 @@ public class JavaMailServiceImpl implements JavaMailService { /** * 发送thymeleaf模板邮件 * - * @param deliver - * 发送人邮箱名 如: javalsj@163.com - * @param receivers - * 收件人,可多个收件人 如:11111@qq.com,2222@163.com - * @param carbonCopys - * 抄送人,可多个抄送人 如:33333@sohu.com - * @param subject - * 邮件主题 如:您收到一封高大上的邮件,请查收。 - * @param thymeleafTemplatePath - * 邮件模板 如:mail\mailTemplate.html。 - * @param thymeleafTemplateVariable - * 邮件模板变量集 + * @param deliver 发送人邮箱名 如: javalsj@163.com + * @param receivers 收件人,可多个收件人 如:11111@qq.com,2222@163.com + * @param carbonCopys 抄送人,可多个抄送人 如:33333@sohu.com + * @param subject 邮件主题 如:您收到一封高大上的邮件,请查收。 + * @param thymeleafTemplatePath 邮件模板 如:mail\mailTemplate.html。 + * @param thymeleafTemplateVariable 邮件模板变量集 */ public void sendTemplateEmail(String deliver, String[] receivers, String[] carbonCopys, String subject, String thymeleafTemplatePath, Map thymeleafTemplateVariable) throws MessagingException { String text = null; if (thymeleafTemplateVariable != null && thymeleafTemplateVariable.size() > 0) { 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); } sendMimeMail(deliver, receivers, carbonCopys, subject, text, true, null); @@ -136,22 +173,15 @@ public class JavaMailServiceImpl implements JavaMailService { /** * 发送的邮件(支持带附件/html类型的邮件) * - * @param deliver - * 发送人邮箱名 如: javalsj@163.com - * @param receivers - * 收件人,可多个收件人 如:11111@qq.com,2222@163.com - * @param carbonCopys - * 抄送人,可多个抄送人 如:3333@sohu.com - * @param subject - * 邮件主题 如:您收到一封高大上的邮件,请查收。 - * @param text - * 邮件内容 如:测试邮件逗你玩的。 - * @param attachmentFilePaths - * 附件文件路径 如: - * 需要注意的是addInline函数中资源名称attchmentFileName需要与正文中cid:attchmentFileName对应起来 - * @throws Exception - * 邮件发送过程中的异常信息 + * @param deliver 发送人邮箱名 如: javalsj@163.com + * @param receivers 收件人,可多个收件人 如:11111@qq.com,2222@163.com + * @param carbonCopys 抄送人,可多个抄送人 如:3333@sohu.com + * @param subject 邮件主题 如:您收到一封高大上的邮件,请查收。 + * @param text 邮件内容 如:测试邮件逗你玩的。 + * @param attachmentFilePaths 附件文件路径 如: + * 需要注意的是addInline函数中资源名称attchmentFileName需要与正文中cid:attchmentFileName对应起来 + * @throws Exception 邮件发送过程中的异常信息 */ private void sendMimeMail(String deliver, String[] receivers, String[] carbonCopys, String subject, String text, boolean isHtml, String[] attachmentFilePaths) throws MessagingException { @@ -186,7 +216,6 @@ public class JavaMailServiceImpl implements JavaMailService { } mailSender.send(mimeMessage); stopWatch.stop(); - //logger.info("邮件发送成功, 花费时间{}秒", stopWatch.getStartTime()); } diff --git a/src/main/java/com/rymcu/forest/service/impl/NotificationServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/NotificationServiceImpl.java index 7aef442..22b22d1 100644 --- a/src/main/java/com/rymcu/forest/service/impl/NotificationServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/NotificationServiceImpl.java @@ -1,22 +1,16 @@ package com.rymcu.forest.service.impl; 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.entity.Comment; -import com.rymcu.forest.entity.Follow; import com.rymcu.forest.entity.Notification; -import com.rymcu.forest.entity.User; import com.rymcu.forest.mapper.NotificationMapper; -import com.rymcu.forest.service.*; +import com.rymcu.forest.service.NotificationService; 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.transaction.annotation.Transactional; import javax.annotation.Resource; -import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -28,16 +22,6 @@ public class NotificationServiceImpl extends AbstractService imple @Resource 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"; @@ -49,13 +33,12 @@ public class NotificationServiceImpl extends AbstractService imple @Override public List findNotifications(Integer idUser) { - List list = notificationMapper.selectNotifications(idUser); - List notifications = new ArrayList<>(); + List list = notificationMapper.selectNotifications(idUser); list.forEach(notification -> { - NotificationDTO notificationDTO = genNotification(notification); + NotificationDTO notificationDTO = NotificationUtils.genNotification(notification); // 判断关联数据是否已删除 if (Objects.nonNull(notificationDTO.getAuthor())) { - notifications.add(notificationDTO); + BeanCopierUtil.copy(notificationDTO, notification); } else { // 关联数据已删除,且未读 if (unRead.equals(notification.getHasRead())) { @@ -66,88 +49,10 @@ public class NotificationServiceImpl extends AbstractService imple dto.setDataType("-1"); dto.setHasRead("1"); dto.setCreatedTime(notification.getCreatedTime()); - notifications.add(dto); + BeanCopierUtil.copy(dto, notification); } }); - return notifications; - } - - 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; + return list; } @Override diff --git a/src/main/java/com/rymcu/forest/service/impl/PortfolioServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/PortfolioServiceImpl.java index d63e1ea..1d67f06 100644 --- a/src/main/java/com/rymcu/forest/service/impl/PortfolioServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/PortfolioServiceImpl.java @@ -41,10 +41,7 @@ public class PortfolioServiceImpl extends AbstractService implements @Override public List findUserPortfoliosByUser(UserDTO userDTO) { List list = portfolioMapper.selectUserPortfoliosByIdUser(userDTO.getIdUser()); - Author author = new Author(); - author.setIdUser(userDTO.getIdUser()); - author.setUserAvatarURL(userDTO.getAvatarUrl()); - author.setUserNickname(userDTO.getNickname()); + Author author = userService.selectAuthor(userDTO.getIdUser()); list.forEach(portfolioDTO -> { genPortfolioAuthor(portfolioDTO,author); }); @@ -190,6 +187,11 @@ public class PortfolioServiceImpl extends AbstractService implements return map; } + @Override + public List findPortfolios() { + return portfolioMapper.selectPortfolios(); + } + private PortfolioDTO genPortfolioAuthor(PortfolioDTO portfolioDTO, Author author) { portfolioDTO.setPortfolioAuthorAvatarUrl(author.getUserAvatarURL()); portfolioDTO.setPortfolioAuthorName(author.getUserNickname()); diff --git a/src/main/java/com/rymcu/forest/service/impl/SponsorServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/SponsorServiceImpl.java index 8b1e589..f8db4ea 100644 --- a/src/main/java/com/rymcu/forest/service/impl/SponsorServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/SponsorServiceImpl.java @@ -1,11 +1,14 @@ package com.rymcu.forest.service.impl; + +import com.rymcu.forest.core.exception.TransactionException; import com.rymcu.forest.core.service.AbstractService; import com.rymcu.forest.dto.ArticleDTO; import com.rymcu.forest.entity.Sponsor; import com.rymcu.forest.entity.TransactionRecord; 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.service.ArticleService; import com.rymcu.forest.service.SponsorService; @@ -39,7 +42,7 @@ public class SponsorServiceImpl extends AbstractService implements Spon map.put("success", false); map.put("message", "数据异常"); } 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()); sponsor.setSponsorshipMoney(money); User user = UserUtils.getCurrentUserByToken(); @@ -47,11 +50,11 @@ public class SponsorServiceImpl extends AbstractService implements Spon sponsor.setSponsorshipTime(new Date()); sponsorMapper.insertSelective(sponsor); // 赞赏金额划转 - if (result.isArticle()) { + if (result.isArticleSponsor()) { 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())) { - throw new Exception("余额不足"); + throw new TransactionException(TransactionCode.InsufficientBalance); } // 更新文章赞赏数 sponsorMapper.updateArticleSponsorCount(articleDTO.getIdArticle()); diff --git a/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java b/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java index 7925da4..a832bf3 100644 --- a/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java +++ b/src/main/java/com/rymcu/forest/service/impl/TransactionRecordServiceImpl.java @@ -1,12 +1,14 @@ 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.redis.RedisService; import com.rymcu.forest.dto.BankAccountDTO; import com.rymcu.forest.dto.TransactionRecordDTO; import com.rymcu.forest.entity.BankAccount; 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.service.BankAccountService; import com.rymcu.forest.service.TransactionRecordService; @@ -47,7 +49,7 @@ public class TransactionRecordServiceImpl extends AbstractService implements UserServic } @Override - public UserDTO findUserDTOByNickname(String nickname) { - UserDTO user = userMapper.selectUserDTOByNickname(nickname); + public UserDTO findUserDTOByAccount(String account) { + UserDTO user = userMapper.selectUserDTOByAccount(account); return user; } @@ -254,7 +251,7 @@ public class UserServiceImpl extends AbstractService implements UserServic } @Override - public UserExtend selectUserExtendByNickname(String nickname) { + public UserExtend selectUserExtendByAccount(String nickname) { return userExtendMapper.selectUserExtendByNickname(nickname); } @@ -284,4 +281,9 @@ public class UserServiceImpl extends AbstractService implements UserServic map.put("message", "更新成功!"); return map; } + + @Override + public List findUsers(UserSearchDTO searchDTO) { + return userMapper.selectUsers(searchDTO); + } } diff --git a/src/main/java/com/rymcu/forest/util/NotificationUtils.java b/src/main/java/com/rymcu/forest/util/NotificationUtils.java index b301bdd..c6b0500 100644 --- a/src/main/java/com/rymcu/forest/util/NotificationUtils.java +++ b/src/main/java/com/rymcu/forest/util/NotificationUtils.java @@ -1,15 +1,17 @@ package com.rymcu.forest.util; 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.Notification; import com.rymcu.forest.entity.User; -import com.rymcu.forest.service.FollowService; -import com.rymcu.forest.service.NotificationService; -import com.rymcu.forest.service.UserService; +import com.rymcu.forest.service.*; -import javax.annotation.Resource; import java.util.List; +import java.util.Objects; import java.util.concurrent.*; /** @@ -19,12 +21,13 @@ import java.util.concurrent.*; */ public class NotificationUtils { - @Resource private static NotificationService notificationService = SpringContextHolder.getBean(NotificationService.class); - @Resource private static UserService userService = SpringContextHolder.getBean(UserService.class); - @Resource 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) { ExecutorService executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue()); @@ -53,6 +56,11 @@ public class NotificationUtils { // TODO 记录操作失败数据 } } + if (NotificationConstant.Comment.equals(dataType)) { + notification = notificationService.findNotification(idUser, dataId, dataType); + NotificationDTO notificationDTO = genNotification(notification); + mailService.sendNotification(notificationDTO); + } } catch (Exception ex) { // TODO 记录操作失败数据 ex.printStackTrace(); @@ -83,4 +91,82 @@ public class NotificationUtils { return 0; }, 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; + } } diff --git a/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java b/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java index 69cc224..f39b423 100644 --- a/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java +++ b/src/main/java/com/rymcu/forest/web/api/admin/AdminController.java @@ -4,6 +4,7 @@ import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import com.rymcu.forest.core.result.GlobalResult; 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.UserRoleDTO; import com.rymcu.forest.entity.*; @@ -18,8 +19,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import static java.util.Comparator.comparing; - /** * @author ronger * */ @@ -39,11 +38,9 @@ public class AdminController { private SpecialDayService specialDayService; @GetMapping("/users") - public GlobalResult> users(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows){ + public GlobalResult> users(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "10") Integer rows, UserSearchDTO searchDTO){ PageHelper.startPage(page, rows); - List list = userService.findAll(); - // 按最后登录时间进行倒序排序 - list.sort(comparing(User::getLastLoginTime).reversed()); + List list = userService.findUsers(searchDTO); PageInfo pageInfo = new PageInfo<>(list); Map map = new HashMap(2); map.put("users", pageInfo.getList()); diff --git a/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java b/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java index 32c7526..69a6d98 100644 --- a/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java +++ b/src/main/java/com/rymcu/forest/web/api/article/ArticleController.java @@ -61,7 +61,7 @@ public class ArticleController { } @DeleteMapping("/delete/{id}") - public GlobalResult delete(@PathVariable Integer id) { + public GlobalResult delete(@PathVariable Integer id) throws BaseApiException { Map map = articleService.delete(id); return GlobalResultGenerator.genSuccessResult(map); } diff --git a/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java b/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java index 62f5e26..7a3a4b1 100644 --- a/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java +++ b/src/main/java/com/rymcu/forest/web/api/common/WebSocketController.java @@ -1,7 +1,6 @@ package com.rymcu.forest.web.api.common; 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.SendTo; 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.stereotype.Controller; -import java.util.HashMap; +import javax.annotation.Resource; /** * @author ronger @@ -17,42 +16,18 @@ import java.util.HashMap; @Controller public class WebSocketController { - @Autowired + @Resource private SimpMessagingTemplate template; @MessageMapping("/sendMessage") - @SendTo("/public/greetings") - public void sendMessage(JSONObject message, StompHeaderAccessor headerAccessor){ - this.template.convertAndSend("/public/greetings",message); + @SendTo("/topic/greening") + public void sendMessage(JSONObject message, StompHeaderAccessor headerAccessor) { + this.template.convertAndSend("/topic/greening", message); } @MessageMapping("/message") @SendToUser("/message") - public void message(JSONObject message){ - String type = message.get("type").toString(); - 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); - } + public void message(JSONObject message, StompHeaderAccessor headerAccessor) { + this.template.convertAndSendToUser(message.getString("to"), "/message", message); } } diff --git a/src/main/java/com/rymcu/forest/web/api/user/UserController.java b/src/main/java/com/rymcu/forest/web/api/user/UserController.java index f7e154e..9976387 100644 --- a/src/main/java/com/rymcu/forest/web/api/user/UserController.java +++ b/src/main/java/com/rymcu/forest/web/api/user/UserController.java @@ -37,16 +37,16 @@ public class UserController { @Resource private FollowService followService; - @GetMapping("/{nickname}") + @GetMapping("/{account}") @VisitLogger - public GlobalResult detail(@PathVariable String nickname){ - UserDTO userDTO = userService.findUserDTOByNickname(nickname); + public GlobalResult detail(@PathVariable String account){ + UserDTO userDTO = userService.findUserDTOByAccount(account); return GlobalResultGenerator.genSuccessResult(userDTO); } - @GetMapping("/{nickname}/articles") - public GlobalResult userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){ - UserDTO userDTO = userService.findUserDTOByNickname(nickname); + @GetMapping("/{account}/articles") + public GlobalResult userArticles(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){ + UserDTO userDTO = userService.findUserDTOByAccount(account); if (userDTO == null){ return GlobalResultGenerator.genErrorResult("用户不存在!"); } @@ -57,9 +57,9 @@ public class UserController { return GlobalResultGenerator.genSuccessResult(map); } - @GetMapping("/{nickname}/portfolios") - public GlobalResult userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){ - UserDTO userDTO = userService.findUserDTOByNickname(nickname); + @GetMapping("/{account}/portfolios") + public GlobalResult userPortfolios(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){ + UserDTO userDTO = userService.findUserDTOByAccount(account); if (userDTO == null){ return GlobalResultGenerator.genErrorResult("用户不存在!"); } @@ -73,9 +73,9 @@ public class UserController { return GlobalResultGenerator.genSuccessResult(map); } - @GetMapping("/{nickname}/followers") - public GlobalResult userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){ - UserDTO userDTO = userService.findUserDTOByNickname(nickname); + @GetMapping("/{account}/followers") + public GlobalResult userFollowers(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){ + UserDTO userDTO = userService.findUserDTOByAccount(account); if (userDTO == null){ return GlobalResultGenerator.genErrorResult("用户不存在!"); } @@ -89,9 +89,9 @@ public class UserController { return GlobalResultGenerator.genSuccessResult(map); } - @GetMapping("/{nickname}/followings") - public GlobalResult userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String nickname){ - UserDTO userDTO = userService.findUserDTOByNickname(nickname); + @GetMapping("/{account}/followings") + public GlobalResult userFollowings(@RequestParam(defaultValue = "0") Integer page, @RequestParam(defaultValue = "12") Integer rows, @PathVariable String account){ + UserDTO userDTO = userService.findUserDTOByAccount(account); if (userDTO == null){ return GlobalResultGenerator.genErrorResult("用户不存在!"); } @@ -105,9 +105,9 @@ public class UserController { return GlobalResultGenerator.genSuccessResult(map); } - @GetMapping("/{nickname}/user-extend") - public GlobalResult userExtend(@PathVariable String nickname) { - UserExtend userExtend = userService.selectUserExtendByNickname(nickname); + @GetMapping("/{account}/user-extend") + public GlobalResult userExtend(@PathVariable String account) { + UserExtend userExtend = userService.selectUserExtendByAccount(account); return GlobalResultGenerator.genSuccessResult(userExtend); } diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java index 09668aa..1a0e8ad 100644 --- a/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java +++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxMenuController.java @@ -1,5 +1,6 @@ package com.rymcu.forest.wx.mp.controller; +import com.rymcu.forest.wx.mp.service.WxMenuService; import lombok.AllArgsConstructor; import me.chanjar.weixin.common.bean.menu.WxMenu; 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.bean.menu.WxMpGetSelfMenuInfoResult; import me.chanjar.weixin.mp.bean.menu.WxMpMenu; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import javax.annotation.Resource; +import java.io.IOException; import java.net.MalformedURLException; 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}") public class WxMenuController { private final WxMpService wxService; - + @Resource + private WxMenuService wxMenuService; /** *
      * 自定义菜单创建接口
@@ -38,52 +43,9 @@ public class WxMenuController {
     }
 
     @GetMapping("/create")
-    public String menuCreateSample(@PathVariable String appId) throws WxErrorException, MalformedURLException {
-        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);
-
+    public String menuCreateSample(@PathVariable String appId) throws WxErrorException, IOException {
         this.wxService.switchover(appId);
-        return this.wxService.getMenuService().menuCreate(menu);
+        return this.wxService.getMenuService().menuCreate(wxMenuService.getMenus());
     }
 
     /**
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java
index 0395f65..2e0364c 100644
--- a/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxRedirectController.java
@@ -1,10 +1,10 @@
 package com.rymcu.forest.wx.mp.controller;
 
 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.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.ui.ModelMap;
 import org.springframework.web.bind.annotation.PathVariable;
@@ -27,8 +27,8 @@ public class WxRedirectController {
         }
 
         try {
-            WxMpOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
-            WxMpUser user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
+            WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
+            WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
             map.put("user", user);
         } catch (WxErrorException e) {
             e.printStackTrace();
diff --git a/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java b/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java
index d302914..8638bf5 100644
--- a/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java
+++ b/src/main/java/com/rymcu/forest/wx/mp/controller/WxoAuthController.java
@@ -4,10 +4,10 @@ import com.rymcu.forest.service.WxUserService;
 import com.rymcu.forest.util.ContextHolderUtils;
 import me.chanjar.weixin.common.api.WxConsts;
 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.util.http.URIUtil;
 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.beans.factory.annotation.Value;
 import org.springframework.stereotype.Controller;
@@ -44,7 +44,7 @@ public class WxoAuthController {
             baseUrl = new StringBuilder(domain).append(contextPath);
         }
         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;
     }
@@ -52,14 +52,14 @@ public class WxoAuthController {
     @GetMapping("getAccessToken")
     public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
         wxMpService.switchoverTo(appId);
-        WxMpOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
+        WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
         boolean valid = wxMpService.getOAuth2Service().validateAccessToken(oAuth2AccessToken);
         if (!valid) {
             throw new Exception("无权限");
         }
 
-        WxMpUser wxMpUser =wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
-        wxUserService.saveUser(wxMpUser,appId);
+        WxMpUser wxMpUser = wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
+        wxUserService.saveUser(wxMpUser, appId);
         ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
         return "redirect:" + redirectUrl;
     }
diff --git a/src/main/java/com/rymcu/forest/wx/mp/service/WxMenuService.java b/src/main/java/com/rymcu/forest/wx/mp/service/WxMenuService.java
new file mode 100644
index 0000000..b67745d
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/service/WxMenuService.java
@@ -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;
+}
diff --git a/src/main/java/com/rymcu/forest/wx/mp/service/impl/WxMenuServiceImpl.java b/src/main/java/com/rymcu/forest/wx/mp/service/impl/WxMenuServiceImpl.java
new file mode 100644
index 0000000..f70493c
--- /dev/null
+++ b/src/main/java/com/rymcu/forest/wx/mp/service/impl/WxMenuServiceImpl.java
@@ -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();
+    }
+}
diff --git a/src/main/java/mapper/ArticleMapper.xml b/src/main/java/mapper/ArticleMapper.xml
index 240f694..6b8fd88 100644
--- a/src/main/java/mapper/ArticleMapper.xml
+++ b/src/main/java/mapper/ArticleMapper.xml
@@ -97,6 +97,9 @@
     
         delete from forest_portfolio_article where id_article = #{id}
     
+    
+        delete from forest_article_content where id_article = #{idArticle}
+    
     
     
     
     
 
\ No newline at end of file
diff --git a/src/main/java/mapper/CommentMapper.xml b/src/main/java/mapper/CommentMapper.xml
index 183286a..646abb2 100644
--- a/src/main/java/mapper/CommentMapper.xml
+++ b/src/main/java/mapper/CommentMapper.xml
@@ -33,6 +33,7 @@
         
         
         
+        
     
     
         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
     
     
     
 
\ No newline at end of file
diff --git a/src/main/java/mapper/NotificationMapper.xml b/src/main/java/mapper/NotificationMapper.xml
index 81fa9b0..144d4ca 100644
--- a/src/main/java/mapper/NotificationMapper.xml
+++ b/src/main/java/mapper/NotificationMapper.xml
@@ -10,6 +10,15 @@
         
         
     
+    
+        
+        
+        
+        
+        
+        
+        
+    
     
         insert into forest_notification (id_user, data_type, data_id, data_summary, created_time) values (#{idUser}, #{dataType}, #{dataId}, #{dataSummary}, sysdate())
     
@@ -19,8 +28,8 @@
     
-    
+        select * from forest_notification where id_user = #{idUser} order by has_read,created_time desc
     
     
         select ifnull(max(sort_no),0) + 1 from forest_portfolio_article where id_portfolio = #{idPortfolio}
     
+    
 
\ No newline at end of file
diff --git a/src/main/java/mapper/SearchMapper.xml b/src/main/java/mapper/SearchMapper.xml
index f159899..7bdfcb4 100644
--- a/src/main/java/mapper/SearchMapper.xml
+++ b/src/main/java/mapper/SearchMapper.xml
@@ -13,6 +13,6 @@
         select portfolio_title as label, id as value, 'portfolio' as type from forest_portfolio
     
     
 
\ No newline at end of file
diff --git a/src/main/java/mapper/TransactionRecordMapper.xml b/src/main/java/mapper/TransactionRecordMapper.xml
index a81b2a4..effeafe 100644
--- a/src/main/java/mapper/TransactionRecordMapper.xml
+++ b/src/main/java/mapper/TransactionRecordMapper.xml
@@ -16,6 +16,10 @@
         update forest_bank_account set account_balance = account_balance + #{money} where bank_account = #{toBankAccount};
     
     
+    
 
\ No newline at end of file
diff --git a/src/main/java/mapper/UserMapper.xml b/src/main/java/mapper/UserMapper.xml
index c0d14f9..d7e0615 100644
--- a/src/main/java/mapper/UserMapper.xml
+++ b/src/main/java/mapper/UserMapper.xml
@@ -45,6 +45,7 @@
         
         
         
+        
     
     
         insert into forest_user_role (id_user,id_role,created_time) values (#{idUser},#{idRole},sysdate())
@@ -81,8 +82,8 @@
     
-    
+        select id, nickname, avatar_type, avatar_url, account, signature from forest_user where account = #{account} and status = 0
     
     
         select * from forest_user where id = #{id}
     
+    
 
 
\ No newline at end of file
diff --git a/src/main/resources/static/forest.sql b/src/main/resources/static/forest.sql
index 3970dee..ca90822 100644
--- a/src/main/resources/static/forest.sql
+++ b/src/main/resources/static/forest.sql
@@ -84,7 +84,7 @@ create table forest_comment
     comment_original_comment_id bigint           null comment '父评论 id',
     comment_status              char default '0' null comment '状态',
     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_reply_count         int              null comment '回帖计数',
     comment_visible             char             null comment '0:所有人可见,1:仅楼主和自己可见',
diff --git a/src/main/resources/static/logo_size.jpg b/src/main/resources/static/logo_size.jpg
new file mode 100644
index 0000000..f06a109
Binary files /dev/null and b/src/main/resources/static/logo_size.jpg differ
diff --git a/src/main/resources/static/logo_size_invert.jpg b/src/main/resources/static/logo_size_invert.jpg
new file mode 100644
index 0000000..d456de3
Binary files /dev/null and b/src/main/resources/static/logo_size_invert.jpg differ
diff --git a/src/main/resources/templates/mail/commentNotification.html b/src/main/resources/templates/mail/commentNotification.html
new file mode 100644
index 0000000..920498e
--- /dev/null
+++ b/src/main/resources/templates/mail/commentNotification.html
@@ -0,0 +1,162 @@
+
+
+
+     RYMCU 消息通知 
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+    
+
+
+
+
+
+
+ + + + + + + + + +
+ Logo +
+ welcome image + +
+
+
+ + + + + + + + + +
+
+

+ 消息通知

+
+
+
+
+ 评论了您的文章《 》: +
+
+
+
+
+
+
+ + + + +
+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/wxMpMenus.json b/src/main/resources/wxMpMenus.json new file mode 100644 index 0000000..44ba96b --- /dev/null +++ b/src/main/resources/wxMpMenus.json @@ -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" + } + ] + } + ] + } +} \ No newline at end of file