From 1ec10e3d3861f0deccce1ef1a9ba028a53d97ac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=83=91=E6=9D=B0?= Date: Mon, 31 Dec 2018 16:59:03 +0800 Subject: [PATCH] =?UTF-8?q?v1.3=20=E7=89=88=E6=9C=AC=E5=8F=91=E5=B8=83?= =?UTF-8?q?=EF=BC=8C=E8=AF=A6=E7=BB=86=E4=BF=A1=E6=81=AF=E6=9F=A5=E7=9C=8B?= =?UTF-8?q?=E5=8F=91=E8=A1=8C=E7=89=88=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 22 ++- pom.xml | 14 ++ sql/eladmin.sql | 111 ++++++++++- .../me/zhengjie/common/aop/log/LogAspect.java | 3 + .../common/exception/BadRequestException.java | 10 + .../handler/GlobalExceptionHandler.java | 61 +++++- .../common/utils/ElAdminConstant.java | 16 +- .../core/config/WebSecurityConfig.java | 38 ++-- .../me/zhengjie/core/security/JwtUser.java | 4 + .../core/service/JwtUserDetailsService.java | 1 + .../me/zhengjie/core/utils/JwtTokenUtil.java | 16 +- .../me/zhengjie/monitor/config/LogFilter.java | 13 +- .../monitor/config/WebSocketConfig.java | 4 + .../zhengjie/monitor/domain/LogMessage.java | 1 - .../me/zhengjie/monitor/domain/Logging.java | 2 + .../service/impl/LoggingServiceImpl.java | 4 +- .../system/domain/VerificationCode.java | 21 +- .../system/repository/UserRepository.java | 28 +++ .../VerificationCodeRepository.java | 8 + .../zhengjie/system/rest/UserController.java | 90 +++++++++ .../rest/VerificationCodeController.java | 37 +++- .../zhengjie/system/service/UserService.java | 22 +++ .../service/VerificationCodeService.java | 3 +- .../system/service/impl/MenuServiceImpl.java | 12 +- .../system/service/impl/UserServiceImpl.java | 19 ++ .../impl/VerificationCodeServiceImpl.java | 62 +++++- .../zhengjie/tools/domain/AlipayConfig.java | 80 ++++++++ .../me/zhengjie/tools/domain/QiniuConfig.java | 61 ++++++ .../zhengjie/tools/domain/QiniuContent.java | 54 ++++++ .../me/zhengjie/tools/domain/vo/EmailVo.java | 4 + .../me/zhengjie/tools/domain/vo/TradeVo.java | 65 +++++++ .../tools/repository/AlipayRepository.java | 11 ++ .../repository/QiNiuConfigRepository.java | 11 ++ .../repository/QiniuContentRepository.java | 19 ++ .../zhengjie/tools/rest/AliPayController.java | 125 ++++++++++++ .../zhengjie/tools/rest/EmailController.java | 3 - .../zhengjie/tools/rest/QiniuController.java | 108 +++++++++++ .../zhengjie/tools/service/AlipayService.java | 48 +++++ .../zhengjie/tools/service/QiNiuService.java | 73 +++++++ .../tools/service/impl/AlipayServiceImpl.java | 135 +++++++++++++ .../tools/service/impl/EmailServiceImpl.java | 3 +- .../service/impl/PictureServiceImpl.java | 2 +- .../tools/service/impl/QiNiuServiceImpl.java | 179 ++++++++++++++++++ .../service/query/QiNiuQueryService.java | 66 +++++++ .../zhengjie/tools/util/AliPayStatusEnum.java | 41 ++++ .../me/zhengjie/tools/util/AlipayUtils.java | 79 ++++++++ .../me/zhengjie/tools/util/QiNiuUtil.java | 60 ++++++ src/main/resources/application.yml | 15 +- 48 files changed, 1776 insertions(+), 88 deletions(-) create mode 100644 src/main/java/me/zhengjie/tools/domain/AlipayConfig.java create mode 100644 src/main/java/me/zhengjie/tools/domain/QiniuConfig.java create mode 100644 src/main/java/me/zhengjie/tools/domain/QiniuContent.java create mode 100644 src/main/java/me/zhengjie/tools/domain/vo/TradeVo.java create mode 100644 src/main/java/me/zhengjie/tools/repository/AlipayRepository.java create mode 100644 src/main/java/me/zhengjie/tools/repository/QiNiuConfigRepository.java create mode 100644 src/main/java/me/zhengjie/tools/repository/QiniuContentRepository.java create mode 100644 src/main/java/me/zhengjie/tools/rest/AliPayController.java create mode 100644 src/main/java/me/zhengjie/tools/rest/QiniuController.java create mode 100644 src/main/java/me/zhengjie/tools/service/AlipayService.java create mode 100644 src/main/java/me/zhengjie/tools/service/QiNiuService.java create mode 100644 src/main/java/me/zhengjie/tools/service/impl/AlipayServiceImpl.java create mode 100644 src/main/java/me/zhengjie/tools/service/impl/QiNiuServiceImpl.java create mode 100644 src/main/java/me/zhengjie/tools/service/query/QiNiuQueryService.java create mode 100644 src/main/java/me/zhengjie/tools/util/AliPayStatusEnum.java create mode 100644 src/main/java/me/zhengjie/tools/util/AlipayUtils.java create mode 100644 src/main/java/me/zhengjie/tools/util/QiNiuUtil.java diff --git a/README.md b/README.md index 4b7153876..26f2d9865 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # eladmin -项目基于 Spring Boot 2.1.0 、 Spring boot Jpa、 Spring Security、redis、Vue的前后端分离的权限管理系统, 权限控制采用 RBAC 思想,支持 动态路由、项目1.0版本提供一个纯净的后台管理,第三方工具将在后面的版本中添加 +项目基于 Spring Boot 2.1.0 、 Spring boot Jpa、 Spring Security、redis、Vue的前后端分离的权限管理系统, 权限控制采用 RBAC 思想,支持动态路由 #### 前端源码 - 码云:[https://gitee.com/elunez/eladmin-qt](https://gitee.com/elunez/eladmin-qt) @@ -14,21 +14,29 @@ #### 预览地址 [http://auauz.net](http://auauz.net) -- 用户名: admin + +##### 用户账号 + +- 管理员: admin +- 测试用户: test + +##### 默认密码 + - 密码: 123456 #### 系统功能模块 - 用户管理 提供用户的相关配置 +- 个人中心 提供修改头像,密码,邮箱验等功能 - 角色管理 角色菜单分配权限 - 权限管理 权限细化到接口 - 菜单管理 已实现动态路由,后端可配置化 - 系统日志 记录用户访问监控异常信息 -- 实时控制台 显示logback实时日志 +- 实时控制台 显示logback实时日志,可显示异常堆栈信息 - redis管理 将redis的操作可视化,提供对redis的基本操作 - redis限流 对系统的流量进行控制,由[everhopingandwaiting](https://github.com/everhopingandwaiting)提供 - SQL监控 采用 druid 监控数据库访问性能 -- 三方工具: 邮件工具,sm.ms免费图床 +- 三方工具: 邮件工具,sm.ms免费图床,支付宝支付,七牛云存储 - 富文本编辑器 #### 后端技术栈 @@ -64,11 +72,15 @@ + + + + #### 反馈交流 -- QQ交流群:891137268 +- QQ交流群:Quella/el-admin - 作者邮箱:elunez@qq.com diff --git a/pom.xml b/pom.xml index 93c72e072..df66854cd 100644 --- a/pom.xml +++ b/pom.xml @@ -161,6 +161,20 @@ 1.4.7 + + + com.qiniu + qiniu-java-sdk + [7.2.0, 7.2.99] + + + + + com.alipay.sdk + alipay-sdk-java + 3.1.0 + + diff --git a/sql/eladmin.sql b/sql/eladmin.sql index 68af9a2d3..d3580bf7e 100644 --- a/sql/eladmin.sql +++ b/sql/eladmin.sql @@ -11,12 +11,36 @@ Target Server Version : 50559 File Encoding : 65001 - Date: 28/12/2018 17:50:46 + Date: 31/12/2018 15:52:01 */ SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0; +-- ---------------------------- +-- Table structure for alipay_config +-- ---------------------------- +DROP TABLE IF EXISTS `alipay_config`; +CREATE TABLE `alipay_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `appID` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `charset` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `format` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `gatewayUrl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `notifyUrl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `privateKey` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `publicKey` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `returnUrl` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `signType` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `sysServiceProviderId` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Records of alipay_config +-- ---------------------------- +INSERT INTO `alipay_config` VALUES (1, '2016091700532697', 'utf-8', 'JSON', 'https://openapi.alipaydev.com/gateway.do', 'http://api.auauz.net/api/aliPay/notify', 'MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQC5js8sInU10AJ0cAQ8UMMyXrQ+oHZEkVt5lBwsStmTJ7YikVYgbskx1YYEXTojRsWCb+SH/kDmDU4pK/u91SJ4KFCRMF2411piYuXU/jF96zKrADznYh/zAraqT6hvAIVtQAlMHN53nx16rLzZ/8jDEkaSwT7+HvHiS+7sxSojnu/3oV7BtgISoUNstmSe8WpWHOaWv19xyS+Mce9MY4BfseFhzTICUymUQdd/8hXA28/H6osUfAgsnxAKv7Wil3aJSgaJczWuflYOve0dJ3InZkhw5Cvr0atwpk8YKBQjy5CdkoHqvkOcIB+cYHXJKzOE5tqU7inSwVbHzOLQ3XbnAgMBAAECggEAVJp5eT0Ixg1eYSqFs9568WdetUNCSUchNxDBu6wxAbhUgfRUGZuJnnAll63OCTGGck+EGkFh48JjRcBpGoeoHLL88QXlZZbC/iLrea6gcDIhuvfzzOffe1RcZtDFEj9hlotg8dQj1tS0gy9pN9g4+EBH7zeu+fyv+qb2e/v1l6FkISXUjpkD7RLQr3ykjiiEw9BpeKb7j5s7Kdx1NNIzhkcQKNqlk8JrTGDNInbDM6inZfwwIO2R1DHinwdfKWkvOTODTYa2MoAvVMFT9Bec9FbLpoWp7ogv1JMV9svgrcF9XLzANZ/OQvkbe9TV9GWYvIbxN6qwQioKCWO4GPnCAQKBgQDgW5MgfhX8yjXqoaUy/d1VjI8dHeIyw8d+OBAYwaxRSlCfyQ+tieWcR2HdTzPca0T0GkWcKZm0ei5xRURgxt4DUDLXNh26HG0qObbtLJdu/AuBUuCqgOiLqJ2f1uIbrz6OZUHns+bT/jGW2Ws8+C13zTCZkZt9CaQsrp3QOGDx5wKBgQDTul39hp3ZPwGNFeZdkGoUoViOSd5Lhowd5wYMGAEXWRLlU8z+smT5v0POz9JnIbCRchIY2FAPKRdVTICzmPk2EPJFxYTcwaNbVqL6lN7J2IlXXMiit5QbiLauo55w7plwV6LQmKm9KV7JsZs5XwqF7CEovI7GevFzyD3w+uizAQKBgC3LY1eRhOlpWOIAhpjG6qOoohmeXOphvdmMlfSHq6WYFqbWwmV4rS5d/6LNpNdL6fItXqIGd8I34jzql49taCmi+A2nlR/E559j0mvM20gjGDIYeZUz5MOE8k+K6/IcrhcgofgqZ2ZED1ksHdB/E8DNWCswZl16V1FrfvjeWSNnAoGAMrBplCrIW5xz+J0Hm9rZKrs+AkK5D4fUv8vxbK/KgxZ2KaUYbNm0xv39c+PZUYuFRCz1HDGdaSPDTE6WeWjkMQd5mS6ikl9hhpqFRkyh0d0fdGToO9yLftQKOGE/q3XUEktI1XvXF0xyPwNgUCnq0QkpHyGVZPtGFxwXiDvpvgECgYA5PoB+nY8iDiRaJNko9w0hL4AeKogwf+4TbCw+KWVEn6jhuJa4LFTdSqp89PktQaoVpwv92el/AhYjWOl/jVCm122f9b7GyoelbjMNolToDwe5pF5RnSpEuDdLy9MfE8LnE3PlbE7E5BipQ3UjSebkgNboLHH/lNZA5qvEtvbfvQ==', 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAut9evKRuHJ/2QNfDlLwvN/S8l9hRAgPbb0u61bm4AtzaTGsLeMtScetxTWJnVvAVpMS9luhEJjt+Sbk5TNLArsgzzwARgaTKOLMT1TvWAK5EbHyI+eSrc3s7Awe1VYGwcubRFWDm16eQLv0k7iqiw+4mweHSz/wWyvBJVgwLoQ02btVtAQErCfSJCOmt0Q/oJQjj08YNRV4EKzB19+f5A+HQVAKy72dSybTzAK+3FPtTtNen/+b5wGeat7c32dhYHnGorPkPeXLtsqqUTp1su5fMfd4lElNdZaoCI7osZxWWUo17vBCZnyeXc9fk0qwD9mK6yRAxNbrY72Xx5VqIqwIDAQAB', 'http://api.auauz.ne/api/aliPay/return', 'RSA2', '2088102176044281'); + -- ---------------------------- -- Table structure for email_config -- ---------------------------- @@ -31,6 +55,24 @@ CREATE TABLE `email_config` ( PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +-- ---------------------------- +-- Table structure for log +-- ---------------------------- +DROP TABLE IF EXISTS `log`; +CREATE TABLE `log` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `createTime` datetime NULL DEFAULT NULL, + `description` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `exceptionDetail` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `logType` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `method` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `params` varchar(1500) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `requestIp` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `time` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 4214 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + -- ---------------------------- -- Table structure for menu -- ---------------------------- @@ -46,7 +88,7 @@ CREATE TABLE `menu` ( `icon` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `path` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 18 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 20 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Records of menu @@ -59,7 +101,7 @@ INSERT INTO `menu` VALUES (5, '2018-12-18 15:17:28', b'0', '菜单管理', 'syst INSERT INTO `menu` VALUES (6, '2018-12-18 15:17:48', b'0', '系统监控', NULL, 0, 10, 'monitor', 'monitor'); INSERT INTO `menu` VALUES (7, '2018-12-18 15:18:26', b'0', '系统日志', 'monitor/log/index', 6, 11, 'log', 'logs'); INSERT INTO `menu` VALUES (8, '2018-12-18 15:19:01', b'0', '系统缓存', 'monitor/redis/index', 6, 12, 'redis', 'redis'); -INSERT INTO `menu` VALUES (9, '2018-12-18 15:19:34', b'1', 'SQL监控', NULL, 6, 14, 'sqlMonitor', 'http://localhost/druid'); +INSERT INTO `menu` VALUES (9, '2018-12-18 15:19:34', b'1', 'SQL监控', NULL, 6, 14, 'sqlMonitor', 'http://localhost:8000/druid'); INSERT INTO `menu` VALUES (10, '2018-12-19 13:38:16', b'0', '组件管理', NULL, 0, 50, 'zujian', 'components'); INSERT INTO `menu` VALUES (11, '2018-12-19 13:38:49', b'0', '图标库', 'components/IconSelect', 10, 51, 'icon', 'icon'); INSERT INTO `menu` VALUES (12, '2018-12-24 20:37:35', b'0', '实时控制台', 'monitor/log/msg', 6, 13, 'codeConsole', 'msg'); @@ -68,6 +110,8 @@ INSERT INTO `menu` VALUES (14, '2018-12-27 10:13:09', b'0', '邮件工具', 'too INSERT INTO `menu` VALUES (15, '2018-12-27 11:58:25', b'0', '富文本', 'components/Editor', 10, 52, 'fwb', 'tinymce'); INSERT INTO `menu` VALUES (16, '2018-12-28 09:36:53', b'0', 'SM.MS图床', 'tools/picture/index', 13, 22, 'image', 'pictures'); INSERT INTO `menu` VALUES (17, '2018-12-28 15:09:49', b'1', '项目地址', '', 0, 0, 'github', 'https://github.com/elunez/eladmin'); +INSERT INTO `menu` VALUES (18, '2018-12-31 11:12:15', b'0', '七牛云存储', 'tools/qiniu/index', 13, 23, 'qiniu', 'qiniu'); +INSERT INTO `menu` VALUES (19, '2018-12-31 14:52:38', b'0', '支付宝工具', 'tools/aliPay/index', 13, 24, 'alipay', 'aliPay'); -- ---------------------------- -- Table structure for menus_roles @@ -102,6 +146,8 @@ INSERT INTO `menus_roles` VALUES (14, 1); INSERT INTO `menus_roles` VALUES (15, 1); INSERT INTO `menus_roles` VALUES (16, 1); INSERT INTO `menus_roles` VALUES (17, 1); +INSERT INTO `menus_roles` VALUES (18, 1); +INSERT INTO `menus_roles` VALUES (19, 1); INSERT INTO `menus_roles` VALUES (1, 2); INSERT INTO `menus_roles` VALUES (2, 2); INSERT INTO `menus_roles` VALUES (3, 2); @@ -111,8 +157,11 @@ INSERT INTO `menus_roles` VALUES (6, 2); INSERT INTO `menus_roles` VALUES (9, 2); INSERT INTO `menus_roles` VALUES (12, 2); INSERT INTO `menus_roles` VALUES (13, 2); +INSERT INTO `menus_roles` VALUES (14, 2); INSERT INTO `menus_roles` VALUES (16, 2); INSERT INTO `menus_roles` VALUES (17, 2); +INSERT INTO `menus_roles` VALUES (18, 2); +INSERT INTO `menus_roles` VALUES (19, 2); -- ---------------------------- -- Table structure for permission @@ -176,12 +225,37 @@ CREATE TABLE `picture` ( `username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `width` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 38 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 47 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Table structure for qiniu_config +-- ---------------------------- +DROP TABLE IF EXISTS `qiniu_config`; +CREATE TABLE `qiniu_config` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `accessKey` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `bucket` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `host` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `secretKey` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `zone` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- --- Records of picture +-- Table structure for qiniu_content -- ---------------------------- -INSERT INTO `picture` VALUES (34, '2018-12-28 16:02:42', 'https://sm.ms/delete/JDAtayhFMH56wCXE', '1', '220', '3.73KB ', 'https://i.loli.net/2018/12/28/5c25d8a253445.jpg', 'admin', '229'); +DROP TABLE IF EXISTS `qiniu_content`; +CREATE TABLE `qiniu_content` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `bucket` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `size` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `updateTime` datetime NULL DEFAULT NULL, + `url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; -- ---------------------------- -- Table structure for role @@ -246,8 +320,8 @@ CREATE TABLE `user` ( -- ---------------------------- -- Records of user -- ---------------------------- -INSERT INTO `user` VALUES (1, 'https://i.loli.net/2018/12/06/5c08894d8de21.jpg', '2018-08-23 09:11:56', 'zhengjie@tom.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'admin', '2018-11-23 10:12:36'); -INSERT INTO `user` VALUES (3, 'https://i.loli.net/2018/12/06/5c08894d8de21.jpg', '2018-12-27 20:05:26', 'test@qq.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'test', NULL); +INSERT INTO `user` VALUES (1, 'https://i.loli.net/2018/12/31/5c297270b20e2.jpg', '2018-08-23 09:11:56', 'elunez@qq.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'admin', '2018-11-23 10:12:36'); +INSERT INTO `user` VALUES (3, 'https://i.loli.net/2018/12/30/5c2871d6aa101.jpg', '2018-12-27 20:05:26', 'test@qq.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'test', NULL); -- ---------------------------- -- Table structure for users_roles @@ -279,8 +353,27 @@ CREATE TABLE `verification_code` ( `status` bit(1) NULL DEFAULT NULL, `type` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `value` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `scenes` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE -) ENGINE = InnoDB AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +) ENGINE = InnoDB AUTO_INCREMENT = 32 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; +-- ---------------------------- +-- Table structure for visits +-- ---------------------------- +DROP TABLE IF EXISTS `visits`; +CREATE TABLE `visits` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `date` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `ip_counts` bigint(20) NULL DEFAULT NULL, + `pv_counts` bigint(20) NULL DEFAULT NULL, + `weekDay` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, + `createTime` datetime NULL DEFAULT NULL, + PRIMARY KEY (`id`) USING BTREE +) ENGINE = InnoDB AUTO_INCREMENT = 47 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact; + +-- ---------------------------- +-- Records of visits +-- ---------------------------- +INSERT INTO `visits` VALUES (46, '2018-12-31', 1, 3, 'Mon', '2018-12-31 15:50:19'); SET FOREIGN_KEY_CHECKS = 1; diff --git a/src/main/java/me/zhengjie/common/aop/log/LogAspect.java b/src/main/java/me/zhengjie/common/aop/log/LogAspect.java index 1a81f7130..0017e744a 100644 --- a/src/main/java/me/zhengjie/common/aop/log/LogAspect.java +++ b/src/main/java/me/zhengjie/common/aop/log/LogAspect.java @@ -13,6 +13,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.io.PrintWriter; +import java.io.StringWriter; + /** * @author jie * @date 2018-11-24 diff --git a/src/main/java/me/zhengjie/common/exception/BadRequestException.java b/src/main/java/me/zhengjie/common/exception/BadRequestException.java index efe7801de..bfbf7f962 100644 --- a/src/main/java/me/zhengjie/common/exception/BadRequestException.java +++ b/src/main/java/me/zhengjie/common/exception/BadRequestException.java @@ -3,6 +3,8 @@ import lombok.Getter; import org.springframework.http.HttpStatus; +import static org.springframework.http.HttpStatus.BAD_REQUEST; + /** * @author jie * @date 2018-11-23 @@ -10,7 +12,15 @@ */ @Getter public class BadRequestException extends RuntimeException{ + + private Integer status = BAD_REQUEST.value(); + public BadRequestException(String msg){ super(msg); } + + public BadRequestException(HttpStatus status,String msg){ + super(msg); + this.status = status.value(); + } } diff --git a/src/main/java/me/zhengjie/common/exception/handler/GlobalExceptionHandler.java b/src/main/java/me/zhengjie/common/exception/handler/GlobalExceptionHandler.java index 7f812169a..402624314 100644 --- a/src/main/java/me/zhengjie/common/exception/handler/GlobalExceptionHandler.java +++ b/src/main/java/me/zhengjie/common/exception/handler/GlobalExceptionHandler.java @@ -6,10 +6,14 @@ import me.zhengjie.common.exception.EntityNotFoundException; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.AccessDeniedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; +import java.io.PrintWriter; +import java.io.StringWriter; import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.FORBIDDEN; import static org.springframework.http.HttpStatus.NOT_FOUND; /** @@ -20,6 +24,32 @@ @RestControllerAdvice public class GlobalExceptionHandler { + /** + * 处理所有不可知的异常 + * @param e + * @return + */ + @ExceptionHandler(Exception.class) + public ResponseEntity handleException(Exception e){ + // 打印堆栈信息 + log.error(getStackTrace(e)); + ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage()); + return buildResponseEntity(apiError); + } + + /** + * 处理 接口无权访问异常AccessDeniedException + * @param e + * @return + */ + @ExceptionHandler(AccessDeniedException.class) + public ResponseEntity handleAccessDeniedException(AccessDeniedException e){ + // 打印堆栈信息 + log.error(getStackTrace(e)); + ApiError apiError = new ApiError(FORBIDDEN.value(),e.getMessage()); + return buildResponseEntity(apiError); + } + /** * 处理自定义异常 * @param e @@ -27,8 +57,9 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(value = BadRequestException.class) public ResponseEntity badRequestException(BadRequestException e) { - log.error(e.getMessage()); - ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage()); + // 打印堆栈信息 + log.error(getStackTrace(e)); + ApiError apiError = new ApiError(e.getStatus(),e.getMessage()); return buildResponseEntity(apiError); } @@ -39,7 +70,8 @@ public ResponseEntity badRequestException(BadRequestException e) { */ @ExceptionHandler(value = EntityExistException.class) public ResponseEntity entityExistException(EntityExistException e) { - log.error(e.getMessage()); + // 打印堆栈信息 + log.error(getStackTrace(e)); ApiError apiError = new ApiError(BAD_REQUEST.value(),e.getMessage()); return buildResponseEntity(apiError); } @@ -51,7 +83,8 @@ public ResponseEntity entityExistException(EntityExistException e) { */ @ExceptionHandler(value = EntityNotFoundException.class) public ResponseEntity entityNotFoundException(EntityNotFoundException e) { - log.error(e.getMessage()); + // 打印堆栈信息 + log.error(getStackTrace(e)); ApiError apiError = new ApiError(NOT_FOUND.value(),e.getMessage()); return buildResponseEntity(apiError); } @@ -63,7 +96,8 @@ public ResponseEntity entityNotFoundException(EntityNotFoundException */ @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException e){ - log.error(e.getMessage()); + // 打印堆栈信息 + log.error(getStackTrace(e)); String[] str = e.getBindingResult().getAllErrors().get(0).getCodes()[1].split("\\."); StringBuffer msg = new StringBuffer(str[1]+":"); msg.append(e.getBindingResult().getAllErrors().get(0).getDefaultMessage()); @@ -79,4 +113,21 @@ public ResponseEntity handleMethodArgumentNotValidException(MethodArgu private ResponseEntity buildResponseEntity(ApiError apiError) { return new ResponseEntity(apiError, HttpStatus.valueOf(apiError.getStatus())); } + + /** + * 获取堆栈信息 + * @param throwable + * @return + */ + private String getStackTrace(Throwable throwable) + { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + try { + throwable.printStackTrace(pw); + return "\n"+sw.toString(); + } finally { + pw.close(); + } + } } diff --git a/src/main/java/me/zhengjie/common/utils/ElAdminConstant.java b/src/main/java/me/zhengjie/common/utils/ElAdminConstant.java index be69087a9..065e3320f 100644 --- a/src/main/java/me/zhengjie/common/utils/ElAdminConstant.java +++ b/src/main/java/me/zhengjie/common/utils/ElAdminConstant.java @@ -7,21 +7,13 @@ */ public class ElAdminConstant { - /** - * 用于七牛云zone与机房对应关系 - */ - public static class QiNiu{ - - public static final String HUAD = "华东"; + public static final String RESET_PASS = "重置密码"; - public static final String HUAB = "华北"; + public static final String RESET_MAIL = "重置邮箱"; - public static final String HUAN = "华南"; + public static final String EMAIL_CODE = "

你的验证码为:"; - public static final String BEIM = "北美"; - - public static final String DNY = "东南亚"; - } + public static final String EMAIL_CONTENT = "

----- 邮件来自 eladmin 后台管理系统,系统邮件请勿回复

"; /** * 常用接口 diff --git a/src/main/java/me/zhengjie/core/config/WebSecurityConfig.java b/src/main/java/me/zhengjie/core/config/WebSecurityConfig.java index 8e075585c..9e3031649 100644 --- a/src/main/java/me/zhengjie/core/config/WebSecurityConfig.java +++ b/src/main/java/me/zhengjie/core/config/WebSecurityConfig.java @@ -78,12 +78,18 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { .antMatchers("/auth/**").permitAll() .antMatchers("/websocket/**").permitAll() .antMatchers("/druid/**").anonymous() + + // 支付宝回调 + .antMatchers("/api/aliPay/return").anonymous() + .antMatchers("/api/aliPay/notify").anonymous() + // swagger start .antMatchers("/swagger-ui.html").anonymous() .antMatchers("/swagger-resources/**").anonymous() .antMatchers("/webjars/**").anonymous() .antMatchers("/*/api-docs").anonymous() // swagger end + .antMatchers("/test/**").anonymous() .antMatchers(HttpMethod.OPTIONS, "/**").anonymous() // 所有请求都需要认证 @@ -96,21 +102,21 @@ protected void configure(HttpSecurity httpSecurity) throws Exception { @Override public void configure(WebSecurity web) throws Exception { // AuthenticationTokenFilter will ignore the below paths - web - .ignoring() - .antMatchers( - HttpMethod.POST, - authenticationPath - ) - // allow anonymous resource requests - .and() - .ignoring() - .antMatchers( - HttpMethod.GET, - "/*.html", - "/**/*.html", - "/**/*.css", - "/**/*.js" - ); + web.ignoring() + .antMatchers( + HttpMethod.POST, + authenticationPath + ) + + // allow anonymous resource requests + .and() + .ignoring() + .antMatchers( + HttpMethod.GET, + "/*.html", + "/**/*.html", + "/**/*.css", + "/**/*.js" + ); } } diff --git a/src/main/java/me/zhengjie/core/security/JwtUser.java b/src/main/java/me/zhengjie/core/security/JwtUser.java index 4967f9cd4..e72410a8a 100644 --- a/src/main/java/me/zhengjie/core/security/JwtUser.java +++ b/src/main/java/me/zhengjie/core/security/JwtUser.java @@ -5,6 +5,8 @@ import lombok.Getter; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.userdetails.UserDetails; + +import java.sql.Timestamp; import java.util.*; /** @@ -32,6 +34,8 @@ public class JwtUser implements UserDetails { private final boolean enabled; + private Timestamp createTime; + @JsonIgnore private final Date lastPasswordResetDate; diff --git a/src/main/java/me/zhengjie/core/service/JwtUserDetailsService.java b/src/main/java/me/zhengjie/core/service/JwtUserDetailsService.java index 5c11a18b8..560bf1596 100644 --- a/src/main/java/me/zhengjie/core/service/JwtUserDetailsService.java +++ b/src/main/java/me/zhengjie/core/service/JwtUserDetailsService.java @@ -64,6 +64,7 @@ public UserDetails create(User user) { user.getEmail(), mapToGrantedAuthorities(user.getRoles(),permissionRepository), user.getEnabled(), + user.getCreateTime(), user.getLastPasswordResetTime() ); } diff --git a/src/main/java/me/zhengjie/core/utils/JwtTokenUtil.java b/src/main/java/me/zhengjie/core/utils/JwtTokenUtil.java index e7ea56cf5..80b0e0145 100644 --- a/src/main/java/me/zhengjie/core/utils/JwtTokenUtil.java +++ b/src/main/java/me/zhengjie/core/utils/JwtTokenUtil.java @@ -5,12 +5,10 @@ import me.zhengjie.common.exception.BadRequestException; import me.zhengjie.core.security.JwtUser; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authentication.AccountExpiredException; +import org.springframework.http.HttpStatus; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; - import javax.servlet.http.HttpServletRequest; import java.io.Serializable; import java.util.Date; @@ -18,13 +16,9 @@ import java.util.Map; import java.util.function.Function; -import static org.springframework.http.HttpStatus.UNAUTHORIZED; - @Component public class JwtTokenUtil implements Serializable { - static final String CLAIM_KEY_USERNAME = "sub"; - static final String CLAIM_KEY_CREATED = "iat"; private static final long serialVersionUID = -3301605591108950415L; private Clock clock = DefaultClock.INSTANCE; @@ -129,7 +123,7 @@ public String getUserName(HttpServletRequest request){ String authToken = request.getHeader(tokenHeader); if(StringUtils.isEmpty(authToken)||authToken.length()<7){ - throw new AccountExpiredException("令牌已过期或无效"); + throw new BadRequestException(HttpStatus.FORBIDDEN,"Token令牌无效"); } final String token = authToken.substring(7); @@ -137,11 +131,7 @@ public String getUserName(HttpServletRequest request){ try { username = getUsernameFromToken(token); } catch (ExpiredJwtException e){ - throw new AccountExpiredException("令牌已过期或无效"); - } - - if(StringUtils.isEmpty(username)){ - throw new AccountExpiredException("令牌已过期或无效"); + throw new BadRequestException(HttpStatus.UNAUTHORIZED,"Token令牌已过期"); } return username; diff --git a/src/main/java/me/zhengjie/monitor/config/LogFilter.java b/src/main/java/me/zhengjie/monitor/config/LogFilter.java index 0220a8f3f..1ba2ae13f 100644 --- a/src/main/java/me/zhengjie/monitor/config/LogFilter.java +++ b/src/main/java/me/zhengjie/monitor/config/LogFilter.java @@ -20,19 +20,12 @@ public class LogFilter extends Filter{ public FilterReply decide(ILoggingEvent event) { String exception = ""; IThrowableProxy iThrowableProxy1 = event.getThrowableProxy(); - if(iThrowableProxy1!=null){ - exception = ""+iThrowableProxy1.getClassName()+" "+iThrowableProxy1.getMessage()+"
"; - for(int i=0; i
"; - } - } LogMessage loggerMessage = new LogMessage( - event.getFormattedMessage() /* repair format message*/ - , DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())), + event.getFormattedMessage(), + DateFormat.getDateTimeInstance().format(new Date(event.getTimeStamp())), event.getThreadName(), event.getLoggerName(), - event.getLevel().levelStr, - exception + event.getLevel().levelStr ); LoggerQueue.getInstance().push(loggerMessage); return FilterReply.ACCEPT; diff --git a/src/main/java/me/zhengjie/monitor/config/WebSocketConfig.java b/src/main/java/me/zhengjie/monitor/config/WebSocketConfig.java index a421066fe..343d27ac5 100644 --- a/src/main/java/me/zhengjie/monitor/config/WebSocketConfig.java +++ b/src/main/java/me/zhengjie/monitor/config/WebSocketConfig.java @@ -45,6 +45,10 @@ public void run() { try { LogMessage log = LoggerQueue.getInstance().poll(); if(log!=null){ + // 格式化异常堆栈信息 + if("ERROR".equals(log.getLevel()) && "me.zhengjie.common.exception.handler.GlobalExceptionHandler".equals(log.getClassName())){ + log.setBody("
"+log.getBody()+"
"); + } if(log.getClassName().equals("jdbc.resultsettable")){ log.setBody("
"+log.getBody()+"
"); } diff --git a/src/main/java/me/zhengjie/monitor/domain/LogMessage.java b/src/main/java/me/zhengjie/monitor/domain/LogMessage.java index fa7a264ef..66a8a4bc9 100644 --- a/src/main/java/me/zhengjie/monitor/domain/LogMessage.java +++ b/src/main/java/me/zhengjie/monitor/domain/LogMessage.java @@ -16,5 +16,4 @@ public class LogMessage { private String threadName; private String className; private String level; - private String exception; } diff --git a/src/main/java/me/zhengjie/monitor/domain/Logging.java b/src/main/java/me/zhengjie/monitor/domain/Logging.java index 327285616..0531694e5 100644 --- a/src/main/java/me/zhengjie/monitor/domain/Logging.java +++ b/src/main/java/me/zhengjie/monitor/domain/Logging.java @@ -38,6 +38,7 @@ public class Logging { /** * 参数 */ + @Column(length = 1500) private String params; /** @@ -58,6 +59,7 @@ public class Logging { /** * 异常详细 */ + @Column(length = 1500) private String exceptionDetail; /** diff --git a/src/main/java/me/zhengjie/monitor/service/impl/LoggingServiceImpl.java b/src/main/java/me/zhengjie/monitor/service/impl/LoggingServiceImpl.java index e1d05800c..a55bc210c 100644 --- a/src/main/java/me/zhengjie/monitor/service/impl/LoggingServiceImpl.java +++ b/src/main/java/me/zhengjie/monitor/service/impl/LoggingServiceImpl.java @@ -83,7 +83,9 @@ public void save(ProceedingJoinPoint joinPoint, Logging logging){ username = user.getUsername(); } - logging.setMethod(methodName); + if (params.length() > 1000){ + params = params.substring(0,999); + } logging.setUsername(username); logging.setParams(params + " }"); loggingRepository.save(logging); diff --git a/src/main/java/me/zhengjie/system/domain/VerificationCode.java b/src/main/java/me/zhengjie/system/domain/VerificationCode.java index 7c8f45215..b555419e8 100644 --- a/src/main/java/me/zhengjie/system/domain/VerificationCode.java +++ b/src/main/java/me/zhengjie/system/domain/VerificationCode.java @@ -1,9 +1,12 @@ package me.zhengjie.system.domain; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import org.hibernate.annotations.CreationTimestamp; import javax.persistence.*; +import javax.validation.constraints.NotBlank; import java.sql.Timestamp; /** @@ -12,6 +15,8 @@ */ @Data @Entity +@AllArgsConstructor +@NoArgsConstructor @Table(name = "verification_code") public class VerificationCode { @@ -22,7 +27,12 @@ public class VerificationCode { private String code; /** - * true 为有效,false 为无效 + * 使用场景,自己定义 + */ + private String scenes; + + /** + * true 为有效,false 为无效,验证时状态+时间+具体的邮箱或者手机号 */ private Boolean status = true; @@ -30,11 +40,13 @@ public class VerificationCode { /** * 类型 :phone 和 email */ + @NotBlank private String type; /** * 具体的phone与email */ + @NotBlank private String value; /** @@ -42,4 +54,11 @@ public class VerificationCode { */ @CreationTimestamp private Timestamp createTime; + + public VerificationCode(String code, String scenes, @NotBlank String type, @NotBlank String value) { + this.code = code; + this.scenes = scenes; + this.type = type; + this.value = value; + } } diff --git a/src/main/java/me/zhengjie/system/repository/UserRepository.java b/src/main/java/me/zhengjie/system/repository/UserRepository.java index fdf8acc10..3a4c2ab88 100644 --- a/src/main/java/me/zhengjie/system/repository/UserRepository.java +++ b/src/main/java/me/zhengjie/system/repository/UserRepository.java @@ -3,6 +3,7 @@ import me.zhengjie.system.domain.User; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -27,4 +28,31 @@ public interface UserRepository extends JpaRepository, JpaSpecificat */ @Query("from User u join fetch u.roles where u.email = :email") User findByEmail(@Param("email") String email); + + /** + * 修改密码 + * @param id + * @param pass + */ + @Modifying + @Query(value = "update user set password = ?2 where id = ?1",nativeQuery = true) + void updatePass(Long id, String pass); + + /** + * 修改头像 + * @param id + * @param url + */ + @Modifying + @Query(value = "update user set avatar = ?2 where id = ?1",nativeQuery = true) + void updateAvatar(Long id, String url); + + /** + * 修改邮箱 + * @param id + * @param email + */ + @Modifying + @Query(value = "update user set email = ?2 where id = ?1",nativeQuery = true) + void updateEmail(Long id, String email); } diff --git a/src/main/java/me/zhengjie/system/repository/VerificationCodeRepository.java b/src/main/java/me/zhengjie/system/repository/VerificationCodeRepository.java index 813bb86af..3b5b0037f 100644 --- a/src/main/java/me/zhengjie/system/repository/VerificationCodeRepository.java +++ b/src/main/java/me/zhengjie/system/repository/VerificationCodeRepository.java @@ -9,4 +9,12 @@ */ public interface VerificationCodeRepository extends JpaRepository { + /** + * 获取有效的验证码 + * @param scenes 业务场景,如重置密码,重置邮箱等等 + * @param type + * @param value + * @return + */ + VerificationCode findByScenesAndTypeAndValueAndStatusIsTrue(String scenes,String type,String value); } diff --git a/src/main/java/me/zhengjie/system/rest/UserController.java b/src/main/java/me/zhengjie/system/rest/UserController.java index 481998b64..81e4e1c1d 100644 --- a/src/main/java/me/zhengjie/system/rest/UserController.java +++ b/src/main/java/me/zhengjie/system/rest/UserController.java @@ -2,17 +2,31 @@ import me.zhengjie.common.aop.log.Log; import me.zhengjie.common.exception.BadRequestException; +import me.zhengjie.common.utils.ElAdminConstant; +import me.zhengjie.common.utils.RequestHolder; +import me.zhengjie.core.security.JwtUser; +import me.zhengjie.core.utils.EncryptUtils; +import me.zhengjie.core.utils.JwtTokenUtil; import me.zhengjie.system.domain.User; +import me.zhengjie.system.domain.VerificationCode; import me.zhengjie.system.service.UserService; +import me.zhengjie.system.service.VerificationCodeService; import me.zhengjie.system.service.dto.UserDTO; import me.zhengjie.system.service.query.UserQueryService; +import me.zhengjie.tools.domain.Picture; +import me.zhengjie.tools.service.PictureService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; +import java.util.HashMap; +import java.util.Map; /** * @author jie @@ -28,6 +42,20 @@ public class UserController { @Autowired private UserQueryService userQueryService; + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + @Qualifier("jwtUserDetailsService") + private UserDetailsService userDetailsService; + + @Autowired + private PictureService pictureService; + + @Autowired + private VerificationCodeService verificationCodeService; + + private static final String ENTITY_NAME = "user"; @GetMapping(value = "/users/{id}") @@ -71,4 +99,66 @@ public ResponseEntity delete(@PathVariable Long id){ userService.delete(id); return new ResponseEntity(HttpStatus.OK); } + + /** + * 验证密码 + * @param pass + * @return + */ + @GetMapping(value = "/users/validPass/{pass}") + public ResponseEntity validPass(@PathVariable String pass){ + JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); + Map map = new HashMap(); + map.put("status",200); + if(!jwtUser.getPassword().equals(EncryptUtils.encryptPassword(pass))){ + map.put("status",400); + } + return new ResponseEntity(map,HttpStatus.OK); + } + + /** + * 修改密码 + * @param pass + * @return + */ + @GetMapping(value = "/users/updatePass/{pass}") + public ResponseEntity updatePass(@PathVariable String pass){ + JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); + if(jwtUser.getPassword().equals(EncryptUtils.encryptPassword(pass))){ + throw new BadRequestException("新密码不能与旧密码相同"); + } + userService.updatePass(jwtUser,EncryptUtils.encryptPassword(pass)); + return new ResponseEntity(HttpStatus.OK); + } + + /** + * 修改头像 + * @param file + * @return + */ + @PostMapping(value = "/users/updateAvatar") + public ResponseEntity updateAvatar(@RequestParam MultipartFile file){ + JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); + Picture picture = pictureService.upload(file,jwtUser.getUsername()); + userService.updateAvatar(jwtUser,picture.getUrl()); + return new ResponseEntity(HttpStatus.OK); + } + + /** + * 修改邮箱 + * @param user + * @param user + * @return + */ + @PostMapping(value = "/users/updateEmail/{code}") + public ResponseEntity updateEmail(@PathVariable String code,@RequestBody User user){ + JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); + if(!jwtUser.getPassword().equals(EncryptUtils.encryptPassword(user.getPassword()))){ + throw new BadRequestException("密码错误"); + } + VerificationCode verificationCode = new VerificationCode(code, ElAdminConstant.RESET_MAIL,"email",user.getEmail()); + verificationCodeService.validated(verificationCode); + userService.updateEmail(jwtUser,user.getEmail()); + return new ResponseEntity(HttpStatus.OK); + } } diff --git a/src/main/java/me/zhengjie/system/rest/VerificationCodeController.java b/src/main/java/me/zhengjie/system/rest/VerificationCodeController.java index f0ea7d682..dab85e0c1 100644 --- a/src/main/java/me/zhengjie/system/rest/VerificationCodeController.java +++ b/src/main/java/me/zhengjie/system/rest/VerificationCodeController.java @@ -1,10 +1,18 @@ package me.zhengjie.system.rest; +import me.zhengjie.common.utils.ElAdminConstant; +import me.zhengjie.common.utils.RequestHolder; +import me.zhengjie.core.security.JwtUser; +import me.zhengjie.core.utils.JwtTokenUtil; import me.zhengjie.system.domain.VerificationCode; import me.zhengjie.system.service.VerificationCodeService; +import me.zhengjie.tools.domain.vo.EmailVo; +import me.zhengjie.tools.service.EmailService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.web.bind.annotation.*; /** @@ -18,10 +26,33 @@ public class VerificationCodeController { @Autowired private VerificationCodeService verificationCodeService; - @PostMapping(value = "/code/sendEmail") - public ResponseEntity sendEmail(@RequestBody VerificationCode code){ + @Autowired + private JwtTokenUtil jwtTokenUtil; + + @Autowired + @Qualifier("jwtUserDetailsService") + private UserDetailsService userDetailsService; + + @Autowired + private EmailService emailService; + + @PostMapping(value = "/code/resetEmail") + public ResponseEntity resetEmail(@RequestBody VerificationCode code) throws Exception { + code.setScenes(ElAdminConstant.RESET_MAIL); + EmailVo emailVo = verificationCodeService.sendEmail(code); + emailService.send(emailVo,emailService.find()); + return new ResponseEntity(HttpStatus.OK); + } + + @PostMapping(value = "/code/email/resetPass") + public ResponseEntity resetPass() throws Exception { + JwtUser jwtUser = (JwtUser)userDetailsService.loadUserByUsername(jwtTokenUtil.getUserName(RequestHolder.getHttpServletRequest())); + VerificationCode code = new VerificationCode(); code.setType("email"); - verificationCodeService.sendEmail(code); + code.setValue(jwtUser.getEmail()); + code.setScenes(ElAdminConstant.RESET_MAIL); + EmailVo emailVo = verificationCodeService.sendEmail(code); + emailService.send(emailVo,emailService.find()); return new ResponseEntity(HttpStatus.OK); } diff --git a/src/main/java/me/zhengjie/system/service/UserService.java b/src/main/java/me/zhengjie/system/service/UserService.java index 966bd064c..41c66289e 100644 --- a/src/main/java/me/zhengjie/system/service/UserService.java +++ b/src/main/java/me/zhengjie/system/service/UserService.java @@ -1,5 +1,6 @@ package me.zhengjie.system.service; +import me.zhengjie.core.security.JwtUser; import me.zhengjie.system.domain.User; import me.zhengjie.system.service.dto.UserDTO; import org.springframework.cache.annotation.CacheConfig; @@ -50,4 +51,25 @@ public interface UserService { */ @Cacheable(key = "'findByName'+#p0") User findByName(String userName); + + /** + * 修改密码 + * @param jwtUser + * @param encryptPassword + */ + void updatePass(JwtUser jwtUser, String encryptPassword); + + /** + * 修改头像 + * @param jwtUser + * @param url + */ + void updateAvatar(JwtUser jwtUser, String url); + + /** + * 修改邮箱 + * @param jwtUser + * @param email + */ + void updateEmail(JwtUser jwtUser, String email); } diff --git a/src/main/java/me/zhengjie/system/service/VerificationCodeService.java b/src/main/java/me/zhengjie/system/service/VerificationCodeService.java index db6e5f524..76d48c213 100644 --- a/src/main/java/me/zhengjie/system/service/VerificationCodeService.java +++ b/src/main/java/me/zhengjie/system/service/VerificationCodeService.java @@ -1,6 +1,7 @@ package me.zhengjie.system.service; import me.zhengjie.system.domain.VerificationCode; +import me.zhengjie.tools.domain.vo.EmailVo; /** * @author jie @@ -12,7 +13,7 @@ public interface VerificationCodeService { * 发送邮件验证码 * @param code */ - void sendEmail(VerificationCode code); + EmailVo sendEmail(VerificationCode code); /** * 验证 diff --git a/src/main/java/me/zhengjie/system/service/impl/MenuServiceImpl.java b/src/main/java/me/zhengjie/system/service/impl/MenuServiceImpl.java index c21a68760..d6bdd54d1 100644 --- a/src/main/java/me/zhengjie/system/service/impl/MenuServiceImpl.java +++ b/src/main/java/me/zhengjie/system/service/impl/MenuServiceImpl.java @@ -1,6 +1,7 @@ package me.zhengjie.system.service.impl; import cn.hutool.core.util.StrUtil; +import me.zhengjie.common.exception.BadRequestException; import me.zhengjie.common.exception.EntityExistException; import me.zhengjie.common.utils.ValidationUtil; import me.zhengjie.system.domain.Menu; @@ -51,6 +52,11 @@ public MenuDTO create(Menu resources) { if(menuRepository.findByName(resources.getName()) != null){ throw new EntityExistException(Menu.class,"name",resources.getName()); } + if(resources.getIFrame()){ + if (!(resources.getPath().toLowerCase().startsWith("http://")||resources.getPath().toLowerCase().startsWith("https://"))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } return menuMapper.toDto(menuRepository.save(resources)); } @@ -59,13 +65,17 @@ public void update(Menu resources) { Optional optionalPermission = menuRepository.findById(resources.getId()); ValidationUtil.isNull(optionalPermission,"Permission","id",resources.getId()); + if(resources.getIFrame()){ + if (!(resources.getPath().toLowerCase().startsWith("http://")||resources.getPath().toLowerCase().startsWith("https://"))) { + throw new BadRequestException("外链必须以http://或者https://开头"); + } + } Menu menu = optionalPermission.get(); Menu menu1 = menuRepository.findByName(resources.getName()); if(menu1 != null && !menu1.getId().equals(menu.getId())){ throw new EntityExistException(Menu.class,"name",resources.getName()); } - menu.setName(resources.getName()); menu.setComponent(resources.getComponent()); menu.setPath(resources.getPath()); diff --git a/src/main/java/me/zhengjie/system/service/impl/UserServiceImpl.java b/src/main/java/me/zhengjie/system/service/impl/UserServiceImpl.java index bed22c5af..11b2efc03 100644 --- a/src/main/java/me/zhengjie/system/service/impl/UserServiceImpl.java +++ b/src/main/java/me/zhengjie/system/service/impl/UserServiceImpl.java @@ -4,6 +4,7 @@ import me.zhengjie.common.exception.EntityExistException; import me.zhengjie.common.exception.EntityNotFoundException; import me.zhengjie.common.utils.ValidationUtil; +import me.zhengjie.core.security.JwtUser; import me.zhengjie.core.utils.EncryptUtils; import me.zhengjie.core.utils.JwtTokenUtil; import me.zhengjie.system.domain.User; @@ -130,4 +131,22 @@ public User findByName(String userName) { return user; } } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updatePass(JwtUser jwtUser, String pass) { + userRepository.updatePass(jwtUser.getId(),pass); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateAvatar(JwtUser jwtUser, String url) { + userRepository.updateAvatar(jwtUser.getId(),url); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void updateEmail(JwtUser jwtUser, String email) { + userRepository.updateEmail(jwtUser.getId(),email); + } } diff --git a/src/main/java/me/zhengjie/system/service/impl/VerificationCodeServiceImpl.java b/src/main/java/me/zhengjie/system/service/impl/VerificationCodeServiceImpl.java index da922c66e..8fe77fd38 100644 --- a/src/main/java/me/zhengjie/system/service/impl/VerificationCodeServiceImpl.java +++ b/src/main/java/me/zhengjie/system/service/impl/VerificationCodeServiceImpl.java @@ -1,23 +1,81 @@ package me.zhengjie.system.service.impl; +import cn.hutool.core.util.RandomUtil; +import me.zhengjie.common.exception.BadRequestException; +import me.zhengjie.common.utils.ElAdminConstant; import me.zhengjie.system.domain.VerificationCode; +import me.zhengjie.system.repository.VerificationCodeRepository; import me.zhengjie.system.service.VerificationCodeService; +import me.zhengjie.tools.domain.vo.EmailVo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import java.util.Arrays; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * @author jie * @date 2018-12-26 */ @Service +@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class VerificationCodeServiceImpl implements VerificationCodeService { - @Override - public void sendEmail(VerificationCode code) { + @Autowired + private VerificationCodeRepository verificationCodeRepository; + + @Value("${code.expiration}") + private Integer expiration; + @Override + @Transactional(rollbackFor = Exception.class) + public EmailVo sendEmail(VerificationCode code) { + EmailVo emailVo = null; + String content = ""; + VerificationCode verificationCode = verificationCodeRepository.findByScenesAndTypeAndValueAndStatusIsTrue(code.getScenes(),code.getType(),code.getValue()); + // 如果不存在有效的验证码,就创建一个新的 + if(verificationCode == null){ + code.setCode(RandomUtil.randomNumbers (6)); + content = ElAdminConstant.EMAIL_CODE + code.getCode() + "

"; + emailVo = new EmailVo(Arrays.asList(code.getValue()),"eladmin后台管理系统",content); + timedDestruction(verificationCodeRepository.save(code)); + // 存在就再次发送原来的验证码 + } else { + content = ElAdminConstant.EMAIL_CODE + verificationCode.getCode() + "

"; + emailVo = new EmailVo(Arrays.asList(verificationCode.getValue()),"eladmin后台管理系统",content); + } + return emailVo; } @Override public void validated(VerificationCode code) { + VerificationCode verificationCode = verificationCodeRepository.findByScenesAndTypeAndValueAndStatusIsTrue(code.getScenes(),code.getType(),code.getValue()); + if(verificationCode == null || !verificationCode.getCode().equals(code.getCode())){ + throw new BadRequestException("无效验证码"); + } else { + verificationCode.setStatus(false); + verificationCodeRepository.save(verificationCode); + } + } + /** + * 定时任务,指定分钟后改变验证码状态 + * @param verifyCode + */ + private void timedDestruction(VerificationCode verifyCode) { + //以下示例为程序调用结束继续运行 + ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor(); + try { + executorService.schedule(() -> { + verifyCode.setStatus(false); + verificationCodeRepository.save(verifyCode); + }, expiration * 60 * 1000L, TimeUnit.MILLISECONDS); + }catch (Exception e){ + e.printStackTrace(); + } } } diff --git a/src/main/java/me/zhengjie/tools/domain/AlipayConfig.java b/src/main/java/me/zhengjie/tools/domain/AlipayConfig.java new file mode 100644 index 000000000..58256fbac --- /dev/null +++ b/src/main/java/me/zhengjie/tools/domain/AlipayConfig.java @@ -0,0 +1,80 @@ +package me.zhengjie.tools.domain; + +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 支付宝配置类 + * @author jie + * @date 2018-12-31 + */ +@Data +@Entity +@Table(name = "alipay_config") +public class AlipayConfig implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 应用ID,APPID,收款账号既是APPID对应支付宝账号 + */ + @NotBlank + private String appID; + + /** + * 商户私钥,您的PKCS8格式RSA2私钥 + */ + @NotBlank + @Column(length = 2000) + private String privateKey; + + /** + * 支付宝公钥 + */ + @NotBlank + @Column(length = 2000) + private String publicKey; + + /** + * 签名方式,固定格式 + */ + private String signType="RSA2"; + + /** + * 支付宝开放安全地址,一般不会变 + */ + private String gatewayUrl = "https://openapi.alipaydev.com/gateway.do"; + + /** + * 编码,固定格式 + */ + private String charset= "utf-8"; + + /** + * 异步通知地址 + */ + @NotBlank + private String notifyUrl; + + /** + * 订单完成后返回的页面 + */ + @NotBlank + private String returnUrl; + + /** + * 类型,固定格式 + */ + private String format="JSON"; + + /** + * 商户号 + */ + @NotBlank + private String sysServiceProviderId; + +} diff --git a/src/main/java/me/zhengjie/tools/domain/QiniuConfig.java b/src/main/java/me/zhengjie/tools/domain/QiniuConfig.java new file mode 100644 index 000000000..39400b4af --- /dev/null +++ b/src/main/java/me/zhengjie/tools/domain/QiniuConfig.java @@ -0,0 +1,61 @@ +package me.zhengjie.tools.domain; + +import lombok.Data; +import javax.persistence.*; +import javax.validation.constraints.NotBlank; +import java.io.Serializable; + +/** + * 七牛云对象存储配置类 + * @author jie + * @date 2018-12-31 + */ +@Data +@Entity +@Table(name = "qiniu_config") +public class QiniuConfig implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 一个账号最多拥有两对密钥(Access/Secret Key) + */ + @NotBlank + private String accessKey; + + /** + * 一个账号最多拥有两对密钥(Access/Secret Key) + */ + @NotBlank + private String secretKey; + + /** + * 存储空间名称作为唯一的 Bucket 识别符 + */ + @NotBlank + private String bucket; + + /** + * Zone表示与机房的对应关系 + * 华东 Zone.zone0() + * 华北 Zone.zone1() + * 华南 Zone.zone2() + * 北美 Zone.zoneNa0() + * 东南亚 Zone.zoneAs0() + */ + @NotBlank + private String zone; + + /** + * 外链域名,可自定义,需在七牛云绑定 + */ + @NotBlank + private String host; + + /** + * 空间类型:公开/私有 + */ + private String type = "公开"; +} diff --git a/src/main/java/me/zhengjie/tools/domain/QiniuContent.java b/src/main/java/me/zhengjie/tools/domain/QiniuContent.java new file mode 100644 index 000000000..de33fdffb --- /dev/null +++ b/src/main/java/me/zhengjie/tools/domain/QiniuContent.java @@ -0,0 +1,54 @@ +package me.zhengjie.tools.domain; + +import lombok.Data; +import org.hibernate.annotations.UpdateTimestamp; +import javax.persistence.*; +import java.io.Serializable; +import java.sql.Timestamp; + +/** + * 上传成功后,存储结果 + * @author jie + * @date 2018-12-31 + */ +@Data +@Entity +@Table(name = "qiniu_content") +public class QiniuContent implements Serializable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + /** + * 文件名,如qiniu.jpg + */ + @Column(name = "name",unique = false) + private String key; + + /** + * 空间名 + */ + private String bucket; + + /** + * 大小 + */ + private String size; + + /** + * 文件地址 + */ + private String url; + + /** + * 空间类型:公开/私有 + */ + private String type = "公开"; + + /** + * 更新时间 + */ + @UpdateTimestamp + private Timestamp updateTime; +} diff --git a/src/main/java/me/zhengjie/tools/domain/vo/EmailVo.java b/src/main/java/me/zhengjie/tools/domain/vo/EmailVo.java index cb8c78ccb..cbed2b8fb 100644 --- a/src/main/java/me/zhengjie/tools/domain/vo/EmailVo.java +++ b/src/main/java/me/zhengjie/tools/domain/vo/EmailVo.java @@ -1,6 +1,8 @@ package me.zhengjie.tools.domain.vo; +import lombok.AllArgsConstructor; import lombok.Data; +import lombok.NoArgsConstructor; import javax.validation.constraints.NotBlank; import javax.validation.constraints.NotEmpty; @@ -13,6 +15,8 @@ * @date 2018/09/28 12:02:14 */ @Data +@AllArgsConstructor +@NoArgsConstructor public class EmailVo { /** diff --git a/src/main/java/me/zhengjie/tools/domain/vo/TradeVo.java b/src/main/java/me/zhengjie/tools/domain/vo/TradeVo.java new file mode 100644 index 000000000..bc57634d7 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/domain/vo/TradeVo.java @@ -0,0 +1,65 @@ +package me.zhengjie.tools.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import javax.validation.constraints.NotBlank; +import java.sql.Date; +import java.sql.Timestamp; + +/** + * 交易详情,按需应该存入数据库,这里存入数据库,仅供临时测试 + * @author jie + * @date 2018-12-31 + */ +@Data +public class TradeVo { + + /** + * (必填)商品描述 + */ + @NotBlank + private String body; + + /** + * (必填)商品名称 + */ + @NotBlank + private String subject; + + /** + * (必填)商户订单号,应该由后台生成 + */ + @ApiModelProperty(hidden = true) + private String outTradeNo; + + /** + * (必填)第三方订单号 + */ + @ApiModelProperty(hidden = true) + private String tradeNo; + + /** + * (必填)价格 + */ + @NotBlank + private String totalAmount; + + /** + * 订单状态,已支付,未支付,作废 + */ + @ApiModelProperty(hidden = true) + private String state; + + /** + * 创建时间,存入数据库时需要 + */ + @ApiModelProperty(hidden = true) + private Timestamp createTime; + + /** + * 作废时间,存入数据库时需要 + */ + @ApiModelProperty(hidden = true) + private Date cancelTime; +} diff --git a/src/main/java/me/zhengjie/tools/repository/AlipayRepository.java b/src/main/java/me/zhengjie/tools/repository/AlipayRepository.java new file mode 100644 index 000000000..cb176035f --- /dev/null +++ b/src/main/java/me/zhengjie/tools/repository/AlipayRepository.java @@ -0,0 +1,11 @@ +package me.zhengjie.tools.repository; + +import me.zhengjie.tools.domain.AlipayConfig; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author jie + * @date 2018-12-31 + */ +public interface AlipayRepository extends JpaRepository { +} diff --git a/src/main/java/me/zhengjie/tools/repository/QiNiuConfigRepository.java b/src/main/java/me/zhengjie/tools/repository/QiNiuConfigRepository.java new file mode 100644 index 000000000..481dd53a5 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/repository/QiNiuConfigRepository.java @@ -0,0 +1,11 @@ +package me.zhengjie.tools.repository; + +import me.zhengjie.tools.domain.QiniuConfig; +import org.springframework.data.jpa.repository.JpaRepository; + +/** + * @author jie + * @date 2018-12-31 + */ +public interface QiNiuConfigRepository extends JpaRepository { +} diff --git a/src/main/java/me/zhengjie/tools/repository/QiniuContentRepository.java b/src/main/java/me/zhengjie/tools/repository/QiniuContentRepository.java new file mode 100644 index 000000000..868f26aa5 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/repository/QiniuContentRepository.java @@ -0,0 +1,19 @@ +package me.zhengjie.tools.repository; + +import me.zhengjie.tools.domain.QiniuContent; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +/** + * @author jie + * @date 2018-12-31 + */ +public interface QiniuContentRepository extends JpaRepository, JpaSpecificationExecutor { + + /** + * 根据key查询 + * @param key + * @return + */ + QiniuContent findByKey(String key); +} diff --git a/src/main/java/me/zhengjie/tools/rest/AliPayController.java b/src/main/java/me/zhengjie/tools/rest/AliPayController.java new file mode 100644 index 000000000..5ce574f4f --- /dev/null +++ b/src/main/java/me/zhengjie/tools/rest/AliPayController.java @@ -0,0 +1,125 @@ +package me.zhengjie.tools.rest; + +import io.swagger.annotations.ApiOperation; +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.common.aop.log.Log; +import me.zhengjie.tools.domain.AlipayConfig; +import me.zhengjie.tools.domain.vo.TradeVo; +import me.zhengjie.tools.service.AlipayService; +import me.zhengjie.tools.util.AliPayStatusEnum; +import me.zhengjie.tools.util.AlipayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import springfox.documentation.annotations.ApiIgnore; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.Map; + +/** + * @author jie + * @date 2018-12-31 + */ +@Slf4j +@RestController +@RequestMapping("/api") +public class AliPayController { + + @Autowired + AlipayUtils alipayUtils; + + @Autowired + private AlipayService alipayService; + + @GetMapping(value = "/aliPay") + public ResponseEntity get(){ + return new ResponseEntity(alipayService.find(),HttpStatus.OK); + } + + @Log(description = "配置支付宝") + @PutMapping(value = "/aliPay") + public ResponseEntity payConfig(@Validated @RequestBody AlipayConfig alipayConfig){ + alipayConfig.setId(1L); + alipayService.update(alipayConfig); + return new ResponseEntity(HttpStatus.OK); + } + + @Log(description = "支付宝PC网页支付") + @ApiOperation(value = "PC网页支付") + @PostMapping(value = "/aliPay/toPayAsPC") + public ResponseEntity toPayAsPC(@Validated@RequestBody TradeVo trade) throws Exception{ + log.warn("REST request to toPayAsPC Trade : {}" +trade); + AlipayConfig alipay = alipayService.find(); + trade.setOutTradeNo(alipayUtils.getOrderCode()); + String payUrl = alipayService.toPayAsPC(alipay,trade); + return ResponseEntity.ok(payUrl); + } + + @Log(description = "支付宝手机网页支付") + @ApiOperation(value = "手机网页支付") + @PostMapping(value = "/aliPay/toPayAsWeb") + public ResponseEntity toPayAsWeb(@Validated @RequestBody TradeVo trade) throws Exception{ + log.warn("REST request to toPayAsWeb Trade : {}" +trade); + AlipayConfig alipay = alipayService.find(); + trade.setOutTradeNo(alipayUtils.getOrderCode()); + String payUrl = alipayService.toPayAsWeb(alipay,trade); + return ResponseEntity.ok(payUrl); + } + + @ApiIgnore + @GetMapping("/aliPay/return") + @ApiOperation(value = "支付之后跳转的链接") + public ResponseEntity returnPage(HttpServletRequest request, HttpServletResponse response) throws Exception { + AlipayConfig alipay = alipayService.find(); + response.setContentType("text/html;charset=" + alipay.getCharset()); + //内容验签,防止黑客篡改参数 + if(alipayUtils.rsaCheck(request,alipay)){ + //商户订单号 + String outTradeNo = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8"); + //支付宝交易号 + String tradeNo = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8"); + System.out.println("商户订单号"+outTradeNo+" "+"第三方交易号"+tradeNo); + + /** + * 根据业务需要返回数据,这里统一返回OK + */ + return new ResponseEntity("payment successful",HttpStatus.OK); + }else{ + /** + * 根据业务需要返回数据 + */ + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } + } + + @ApiIgnore + @RequestMapping("/aliPay/notify") + @ApiOperation(value = "支付异步通知(要公网访问),接收异步通知,检查通知内容app_id、out_trade_no、total_amount是否与请求中的一致,根据trade_status进行后续业务处理") + public ResponseEntity notify(HttpServletRequest request) throws Exception{ + AlipayConfig alipay = alipayService.find(); + Map parameterMap = request.getParameterMap(); + StringBuilder notifyBuild = new StringBuilder("/****************************** pay notify ******************************/\n"); + parameterMap.forEach((key, value) -> notifyBuild.append(key + "=" + value[0] + "\n") ); + //内容验签,防止黑客篡改参数 + if (alipayUtils.rsaCheck(request,alipay)) { + //交易状态 + String tradeStatus = new String(request.getParameter("trade_status").getBytes("ISO-8859-1"),"UTF-8"); + // 商户订单号 + String outTradeNo = new String(request.getParameter("out_trade_no").getBytes("ISO-8859-1"),"UTF-8"); + //支付宝交易号 + String tradeNo = new String(request.getParameter("trade_no").getBytes("ISO-8859-1"),"UTF-8"); + //付款金额 + String totalAmount = new String(request.getParameter("total_amount").getBytes("ISO-8859-1"),"UTF-8"); + //验证 + if(tradeStatus.equals(AliPayStatusEnum.SUCCESS.getValue())||tradeStatus.equals(AliPayStatusEnum.FINISHED.getValue())){ + /** + * 验证通过后应该根据业务需要处理订单 + */ + } + return new ResponseEntity(HttpStatus.OK); + } + return new ResponseEntity(HttpStatus.BAD_REQUEST); + } +} diff --git a/src/main/java/me/zhengjie/tools/rest/EmailController.java b/src/main/java/me/zhengjie/tools/rest/EmailController.java index a30f6f2e0..f9c37f653 100644 --- a/src/main/java/me/zhengjie/tools/rest/EmailController.java +++ b/src/main/java/me/zhengjie/tools/rest/EmailController.java @@ -25,13 +25,11 @@ public class EmailController { @Autowired private EmailService emailService; - @PreAuthorize("hasAnyRole('ADMIN')") @GetMapping(value = "/email") public ResponseEntity get(){ return new ResponseEntity(emailService.find(),HttpStatus.OK); } - @PreAuthorize("hasAnyRole('ADMIN')") @Log(description = "配置邮件") @PutMapping(value = "/email") public ResponseEntity emailConfig(@Validated @RequestBody EmailConfig emailConfig){ @@ -39,7 +37,6 @@ public ResponseEntity emailConfig(@Validated @RequestBody EmailConfig emailConfi return new ResponseEntity(HttpStatus.OK); } - @PreAuthorize("hasAnyRole('ADMIN')") @Log(description = "发送邮件") @PostMapping(value = "/email") public ResponseEntity send(@Validated @RequestBody EmailVo emailVo) throws Exception { diff --git a/src/main/java/me/zhengjie/tools/rest/QiniuController.java b/src/main/java/me/zhengjie/tools/rest/QiniuController.java new file mode 100644 index 000000000..806c37ec6 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/rest/QiniuController.java @@ -0,0 +1,108 @@ +package me.zhengjie.tools.rest; + +import lombok.extern.slf4j.Slf4j; +import me.zhengjie.common.aop.log.Log; +import me.zhengjie.tools.domain.QiniuConfig; +import me.zhengjie.tools.domain.QiniuContent; +import me.zhengjie.tools.service.QiNiuService; +import me.zhengjie.tools.service.query.QiNiuQueryService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Pageable; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.UnsupportedEncodingException; +import java.util.HashMap; +import java.util.Map; + +/** + * 发送邮件 + * @author 郑杰 + * @date 2018/09/28 6:55:53 + */ +@Slf4j +@RestController +@RequestMapping("api") +public class QiniuController { + + @Autowired + private QiNiuService qiNiuService; + + @Autowired + private QiNiuQueryService qiNiuQueryService; + + @GetMapping(value = "/qiNiuConfig") + public ResponseEntity get(){ + return new ResponseEntity(qiNiuService.find(), HttpStatus.OK); + } + + @Log(description = "配置七牛云存储") + @PutMapping(value = "/qiNiuConfig") + public ResponseEntity emailConfig(@Validated @RequestBody QiniuConfig qiniuConfig){ + qiNiuService.update(qiniuConfig); + return new ResponseEntity(HttpStatus.OK); + } + + @Log(description = "查询文件") + @GetMapping(value = "/qiNiuContent") + public ResponseEntity getRoles(QiniuContent resources, Pageable pageable){ + return new ResponseEntity(qiNiuQueryService.queryAll(resources,pageable),HttpStatus.OK); + } + + /** + * 上传文件到七牛云 + * @param file + * @return + */ + @Log(description ="上传文件") + @PostMapping(value = "/qiNiuContent") + public ResponseEntity upload(@RequestParam MultipartFile file){ + QiniuContent qiniuContent = qiNiuService.upload(file,qiNiuService.find()); + Map map = new HashMap(); + map.put("errno",0); + map.put("id",qiniuContent.getId()); + map.put("data",new String[]{qiniuContent.getUrl()}); + return new ResponseEntity(map,HttpStatus.OK); + } + + /** + * 同步七牛云数据到数据库 + * @return + */ + @Log(description ="同步七牛云数据") + @PostMapping(value = "/qiNiuContent/synchronize") + public ResponseEntity synchronize(){ + log.warn("REST request to synchronize qiNiu : {}"); + qiNiuService.synchronize(qiNiuService.find()); + return new ResponseEntity(HttpStatus.OK); + } + + /** + * 下载七牛云文件 + * @param id + * @return + * @throws Exception + */ + @Log(description ="下载文件") + @GetMapping(value = "/qiNiuContent/download/{id}") + public ResponseEntity download(@PathVariable Long id){ + return new ResponseEntity(qiNiuService.download(qiNiuService.findByContentId(id),qiNiuService.find()),HttpStatus.OK); + } + + /** + * 删除七牛云文件 + * @param id + * @return + * @throws Exception + */ + @Log(description ="删除文件") + @DeleteMapping(value = "/qiNiuContent/{id}") + public ResponseEntity delete(@PathVariable Long id){ + qiNiuService.delete(qiNiuService.findByContentId(id),qiNiuService.find()); + return new ResponseEntity(HttpStatus.OK); + } +} diff --git a/src/main/java/me/zhengjie/tools/service/AlipayService.java b/src/main/java/me/zhengjie/tools/service/AlipayService.java new file mode 100644 index 000000000..68a284062 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/service/AlipayService.java @@ -0,0 +1,48 @@ +package me.zhengjie.tools.service; + +import me.zhengjie.tools.domain.AlipayConfig; +import me.zhengjie.tools.domain.vo.TradeVo; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; + +/** + * @author jie + * @date 2018-12-31 + */ +@CacheConfig(cacheNames = "alipay") +public interface AlipayService { + + /** + * 处理来自PC的交易请求 + * @param alipay + * @param trade + * @return + * @throws Exception + */ + String toPayAsPC(AlipayConfig alipay, TradeVo trade) throws Exception; + + /** + * 处理来自手机网页的交易请求 + * @param alipay + * @param trade + * @return + * @throws Exception + */ + String toPayAsWeb(AlipayConfig alipay, TradeVo trade) throws Exception; + + /** + * 查询配置 + * @return + */ + @Cacheable(key = "'1'") + AlipayConfig find(); + + /** + * 更新配置 + * @param alipayConfig + * @return + */ + @CachePut(key = "'1'") + AlipayConfig update(AlipayConfig alipayConfig); +} diff --git a/src/main/java/me/zhengjie/tools/service/QiNiuService.java b/src/main/java/me/zhengjie/tools/service/QiNiuService.java new file mode 100644 index 000000000..179083855 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/service/QiNiuService.java @@ -0,0 +1,73 @@ +package me.zhengjie.tools.service; + +import me.zhengjie.tools.domain.QiniuConfig; +import me.zhengjie.tools.domain.QiniuContent; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.CachePut; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.web.multipart.MultipartFile; +import java.io.UnsupportedEncodingException; + +/** + * @author jie + * @date 2018-12-31 + */ +@CacheConfig(cacheNames = "qiNiu") +public interface QiNiuService { + + /** + * 查配置 + * @return + */ + @Cacheable(key = "'1'") + QiniuConfig find(); + + /** + * 修改配置 + * @param qiniuConfig + * @return + */ + @CachePut(key = "'1'") + QiniuConfig update(QiniuConfig qiniuConfig); + + /** + * 上传文件 + * @param file + * @param qiniuConfig + */ + @CacheEvict(allEntries = true) + QiniuContent upload(MultipartFile file, QiniuConfig qiniuConfig); + + /** + * 查询文件 + * @param id + * @return + */ + @Cacheable(key = "'content:'+#p0") + QiniuContent findByContentId(Long id); + + /** + * 下载文件 + * @param content + * @param config + * @return + */ + String download(QiniuContent content, QiniuConfig config); + + /** + * 删除文件 + * @param content + * @param config + * @return + */ + @CacheEvict(allEntries = true) + void delete(QiniuContent content, QiniuConfig config); + + /** + * 同步数据 + * @param config + */ + @CacheEvict(allEntries = true) + void synchronize(QiniuConfig config); +} diff --git a/src/main/java/me/zhengjie/tools/service/impl/AlipayServiceImpl.java b/src/main/java/me/zhengjie/tools/service/impl/AlipayServiceImpl.java new file mode 100644 index 000000000..d52af8d42 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/service/impl/AlipayServiceImpl.java @@ -0,0 +1,135 @@ +package me.zhengjie.tools.service.impl; + +import com.alipay.api.AlipayClient; +import com.alipay.api.DefaultAlipayClient; +import com.alipay.api.request.AlipayTradePagePayRequest; +import com.alipay.api.request.AlipayTradeWapPayRequest; +import me.zhengjie.common.exception.BadRequestException; +import me.zhengjie.tools.domain.AlipayConfig; +import me.zhengjie.tools.domain.vo.TradeVo; +import me.zhengjie.tools.repository.AlipayRepository; +import me.zhengjie.tools.service.AlipayService; +import me.zhengjie.tools.util.AlipayUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Optional; + +/** + * @author jie + * @date 2018-12-31 + */ +@Service +@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) +public class AlipayServiceImpl implements AlipayService { + + @Autowired + AlipayUtils alipayUtils; + + @Autowired + private AlipayRepository alipayRepository; + + @Override + public String toPayAsPC(AlipayConfig alipay, TradeVo trade) throws Exception { + + if(alipay.getId() == null){ + throw new BadRequestException("请先添加相应配置,再操作"); + } + AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppID(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType()); + + double money = Double.parseDouble(trade.getTotalAmount()); + if(money <= 0 || money>=5000){ + throw new BadRequestException("测试金额过大"); + } + + /** + * 创建API对应的request(电脑网页版) + */ + AlipayTradePagePayRequest request = new AlipayTradePagePayRequest(); + + /** + * 订单完成后返回的页面和异步通知地址 + */ + request.setReturnUrl(alipay.getReturnUrl()); + request.setNotifyUrl(alipay.getNotifyUrl()); + /** + * 填充订单参数 + */ + request.setBizContent("{" + + " \"out_trade_no\":\""+trade.getOutTradeNo()+"\"," + + " \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," + + " \"total_amount\":"+trade.getTotalAmount()+"," + + " \"subject\":\""+trade.getSubject()+"\"," + + " \"body\":\""+trade.getBody()+"\"," + + " \"extend_params\":{" + + " \"sys_service_provider_id\":\""+alipay.getSysServiceProviderId()+"\"" + + " }"+ + " }");//填充业务参数 + /** + * 调用SDK生成表单 + * 通过GET方式,口可以获取url + */ + return alipayClient.pageExecute(request, "GET").getBody(); + + } + + @Override + public String toPayAsWeb(AlipayConfig alipay, TradeVo trade) throws Exception { + if(alipay.getId() == null){ + throw new BadRequestException("请先添加相应配置,再操作"); + } + AlipayClient alipayClient = new DefaultAlipayClient(alipay.getGatewayUrl(), alipay.getAppID(), alipay.getPrivateKey(), alipay.getFormat(), alipay.getCharset(), alipay.getPublicKey(), alipay.getSignType()); + + double money = Double.parseDouble(trade.getTotalAmount()); + if(money <= 0 || money >= 5000){ + throw new BadRequestException("测试金额过大"); + } + + /** + * 创建API对应的request(手机网页版) + */ + AlipayTradeWapPayRequest request = new AlipayTradeWapPayRequest(); + + /** + * 订单完成后返回的页面和异步通知地址 + */ + request.setReturnUrl(alipay.getReturnUrl()); + request.setNotifyUrl(alipay.getNotifyUrl()); + /** + * 填充订单参数 + */ + request.setBizContent("{" + + " \"out_trade_no\":\""+trade.getOutTradeNo()+"\"," + + " \"product_code\":\"FAST_INSTANT_TRADE_PAY\"," + + " \"total_amount\":"+trade.getTotalAmount()+"," + + " \"subject\":\""+trade.getSubject()+"\"," + + " \"body\":\""+trade.getBody()+"\"," + + " \"extend_params\":{" + + " \"sys_service_provider_id\":\""+alipay.getSysServiceProviderId()+"\"" + + " }"+ + " }");//填充业务参数 + /** + * 调用SDK生成表单 + * 通过GET方式,口可以获取url + */ + return alipayClient.pageExecute(request, "GET").getBody(); + } + + @Override + public AlipayConfig find() { + Optional alipayConfig = alipayRepository.findById(1L); + if (alipayConfig.isPresent()){ + return alipayConfig.get(); + } else { + return new AlipayConfig(); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public AlipayConfig update(AlipayConfig alipayConfig) { + return alipayRepository.saveAndFlush(alipayConfig); + } +} diff --git a/src/main/java/me/zhengjie/tools/service/impl/EmailServiceImpl.java b/src/main/java/me/zhengjie/tools/service/impl/EmailServiceImpl.java index ffc80a92c..cd01e30bf 100644 --- a/src/main/java/me/zhengjie/tools/service/impl/EmailServiceImpl.java +++ b/src/main/java/me/zhengjie/tools/service/impl/EmailServiceImpl.java @@ -3,6 +3,7 @@ import cn.hutool.extra.mail.MailAccount; import cn.hutool.extra.mail.MailUtil; import me.zhengjie.common.exception.BadRequestException; +import me.zhengjie.common.utils.ElAdminConstant; import me.zhengjie.core.utils.EncryptUtils; import me.zhengjie.tools.domain.EmailConfig; import me.zhengjie.tools.domain.vo.EmailVo; @@ -72,7 +73,7 @@ public void send(EmailVo emailVo, EmailConfig emailConfig){ account.setFrom(emailConfig.getUser()+"<"+emailConfig.getFromUser()+">"); //ssl方式发送 account.setStartttlsEnable(true); - String content = emailVo.getContent()+ "

----- 邮件来自 eladmin 后台管理系统

"; + String content = emailVo.getContent()+ ElAdminConstant.EMAIL_CONTENT; /** * 发送 */ diff --git a/src/main/java/me/zhengjie/tools/service/impl/PictureServiceImpl.java b/src/main/java/me/zhengjie/tools/service/impl/PictureServiceImpl.java index 3deec4f9a..c5c11c48b 100644 --- a/src/main/java/me/zhengjie/tools/service/impl/PictureServiceImpl.java +++ b/src/main/java/me/zhengjie/tools/service/impl/PictureServiceImpl.java @@ -70,7 +70,7 @@ public Picture upload(MultipartFile multipartFile, String username) { picture = JSON.parseObject(jsonObject.get("data").toString(), Picture.class); picture.setSize(FileUtil.getSize(Integer.valueOf(picture.getSize()))); picture.setUsername(username); - picture.setFilename(FileUtil.getFileNameNoEx(multipartFile.getOriginalFilename())); + picture.setFilename(FileUtil.getFileNameNoEx(multipartFile.getOriginalFilename())+FileUtil.getExtensionName(multipartFile.getOriginalFilename())); pictureRepository.save(picture); //删除临时文件 FileUtil.deleteFile(file); diff --git a/src/main/java/me/zhengjie/tools/service/impl/QiNiuServiceImpl.java b/src/main/java/me/zhengjie/tools/service/impl/QiNiuServiceImpl.java new file mode 100644 index 000000000..f123321c2 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/service/impl/QiNiuServiceImpl.java @@ -0,0 +1,179 @@ +package me.zhengjie.tools.service.impl; + +import com.google.gson.Gson; +import com.qiniu.common.QiniuException; +import com.qiniu.http.Response; +import com.qiniu.storage.BucketManager; +import com.qiniu.storage.Configuration; +import com.qiniu.storage.UploadManager; +import com.qiniu.storage.model.DefaultPutRet; +import com.qiniu.storage.model.FileInfo; +import com.qiniu.util.Auth; +import me.zhengjie.common.exception.BadRequestException; +import me.zhengjie.common.utils.FileUtil; +import me.zhengjie.common.utils.ValidationUtil; +import me.zhengjie.tools.domain.QiniuConfig; +import me.zhengjie.tools.domain.QiniuContent; +import me.zhengjie.tools.repository.QiNiuConfigRepository; +import me.zhengjie.tools.repository.QiniuContentRepository; +import me.zhengjie.tools.service.QiNiuService; +import me.zhengjie.tools.util.QiNiuUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; +import java.io.UnsupportedEncodingException; +import java.util.Optional; + +/** + * @author jie + * @date 2018-12-31 + */ +@Service +@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) +public class QiNiuServiceImpl implements QiNiuService { + + @Autowired + private QiNiuConfigRepository qiNiuConfigRepository; + + @Autowired + private QiniuContentRepository qiniuContentRepository; + + @Value("${qiniu.max-size}") + private Long maxSize; + + private final String TYPE = "公开"; + + @Override + public QiniuConfig find() { + Optional qiniuConfig = qiNiuConfigRepository.findById(1L); + if(qiniuConfig.isPresent()){ + return qiniuConfig.get(); + } else { + return new QiniuConfig(); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public QiniuConfig update(QiniuConfig qiniuConfig) { + if (!(qiniuConfig.getHost().toLowerCase().startsWith("http://")||qiniuConfig.getHost().toLowerCase().startsWith("https://"))) { + throw new BadRequestException("外链域名必须以http://或者https://开头"); + } + qiniuConfig.setId(1L); + return qiNiuConfigRepository.save(qiniuConfig); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public QiniuContent upload(MultipartFile file, QiniuConfig qiniuConfig) { + + Long size = maxSize * 1024 * 1024; + if(file.getSize() > size){ + throw new BadRequestException("文件超出规定大小"); + } + if(qiniuConfig.getId() == null){ + throw new BadRequestException("请先添加相应配置,再操作"); + } + /** + * 构造一个带指定Zone对象的配置类 + */ + Configuration cfg = QiNiuUtil.getConfiguration(qiniuConfig.getZone()); + UploadManager uploadManager = new UploadManager(cfg); + Auth auth = Auth.create(qiniuConfig.getAccessKey(), qiniuConfig.getSecretKey()); + String upToken = auth.uploadToken(qiniuConfig.getBucket()); + try { + Response response = uploadManager.put(file.getBytes(), QiNiuUtil.getKey(file.getOriginalFilename()), upToken); + //解析上传成功的结果 + DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class); + //存入数据库 + QiniuContent qiniuContent = new QiniuContent(); + qiniuContent.setBucket(qiniuConfig.getBucket()); + qiniuContent.setType(qiniuConfig.getType()); + qiniuContent.setKey(putRet.key); + qiniuContent.setUrl(qiniuConfig.getHost()+"/"+putRet.key); + qiniuContent.setSize(FileUtil.getSize(Integer.parseInt(file.getSize()+""))); + return qiniuContentRepository.save(qiniuContent); + } catch (Exception e) { + throw new BadRequestException(e.getMessage()); + } + } + + @Override + public QiniuContent findByContentId(Long id) { + Optional qiniuContent = qiniuContentRepository.findById(id); + ValidationUtil.isNull(qiniuContent,"QiniuContent", "id",id); + return qiniuContent.get(); + } + + @Override + public String download(QiniuContent content,QiniuConfig config){ + String finalUrl = null; + if(TYPE.equals(content.getType())){ + finalUrl = content.getUrl(); + } else { + Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey()); + /** + * 1小时,可以自定义链接过期时间 + */ + long expireInSeconds = 3600; + finalUrl = auth.privateDownloadUrl(content.getUrl(), expireInSeconds); + } + return finalUrl; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void delete(QiniuContent content, QiniuConfig config) { + //构造一个带指定Zone对象的配置类 + Configuration cfg = QiNiuUtil.getConfiguration(config.getZone()); + Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey()); + BucketManager bucketManager = new BucketManager(auth, cfg); + try { + bucketManager.delete(content.getBucket(), content.getKey()); + qiniuContentRepository.delete(content); + } catch (QiniuException ex) { + System.err.println(ex.code()); + System.err.println(ex.response.toString()); + } + } + + @Override + @Transactional(rollbackFor = Exception.class) + public void synchronize(QiniuConfig config) { + if(config.getId() == null){ + throw new BadRequestException("请先添加相应配置,再操作"); + } + //构造一个带指定Zone对象的配置类 + Configuration cfg = QiNiuUtil.getConfiguration(config.getZone()); + Auth auth = Auth.create(config.getAccessKey(), config.getSecretKey()); + BucketManager bucketManager = new BucketManager(auth, cfg); + //文件名前缀 + String prefix = ""; + //每次迭代的长度限制,最大1000,推荐值 1000 + int limit = 1000; + //指定目录分隔符,列出所有公共前缀(模拟列出目录效果)。缺省值为空字符串 + String delimiter = ""; + //列举空间文件列表 + BucketManager.FileListIterator fileListIterator = bucketManager.createFileListIterator(config.getBucket(), prefix, limit, delimiter); + while (fileListIterator.hasNext()) { + //处理获取的file list结果 + QiniuContent qiniuContent = null; + FileInfo[] items = fileListIterator.next(); + for (FileInfo item : items) { + if(qiniuContentRepository.findByKey(item.key) == null){ + qiniuContent = new QiniuContent(); + qiniuContent.setSize(FileUtil.getSize(Integer.parseInt(item.fsize+""))); + qiniuContent.setKey(item.key); + qiniuContent.setType(config.getType()); + qiniuContent.setBucket(config.getBucket()); + qiniuContent.setUrl(config.getHost()+"/"+item.key); + qiniuContentRepository.save(qiniuContent); + } + } + } + + } +} diff --git a/src/main/java/me/zhengjie/tools/service/query/QiNiuQueryService.java b/src/main/java/me/zhengjie/tools/service/query/QiNiuQueryService.java new file mode 100644 index 000000000..d284fc708 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/service/query/QiNiuQueryService.java @@ -0,0 +1,66 @@ +package me.zhengjie.tools.service.query; + +import me.zhengjie.common.utils.PageUtil; +import me.zhengjie.tools.domain.QiniuContent; +import me.zhengjie.tools.repository.QiniuContentRepository; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cache.annotation.CacheConfig; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.ObjectUtils; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.List; + +/** + * @author jie + * @date 2018-12-31 + */ +@Service +@CacheConfig(cacheNames = "qiNiu") +@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) +public class QiNiuQueryService { + + @Autowired + private QiniuContentRepository qiniuContentRepository; + + /** + * 分页 + */ + @Cacheable(keyGenerator = "keyGenerator") + public Object queryAll(QiniuContent qiniuContent, Pageable pageable){ + return PageUtil.toPage(qiniuContentRepository.findAll(new Spec(qiniuContent),pageable)); + } + + class Spec implements Specification { + + private QiniuContent qiniuContent; + + public Spec(QiniuContent qiniuContent){ + this.qiniuContent = qiniuContent; + } + + @Override + public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder cb) { + + List list = new ArrayList(); + + if(!ObjectUtils.isEmpty(qiniuContent.getKey())){ + /** + * 模糊 + */ + list.add(cb.like(root.get("key").as(String.class),"%"+qiniuContent.getKey()+"%")); + } + + Predicate[] p = new Predicate[list.size()]; + return cb.and(list.toArray(p)); + } + } +} diff --git a/src/main/java/me/zhengjie/tools/util/AliPayStatusEnum.java b/src/main/java/me/zhengjie/tools/util/AliPayStatusEnum.java new file mode 100644 index 000000000..a61f38296 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/util/AliPayStatusEnum.java @@ -0,0 +1,41 @@ +package me.zhengjie.tools.util; + +/** + * 支付状态 + * @author zhengjie + * @date 2018/08/01 16:45:43 + */ +public enum AliPayStatusEnum { + + /** + * 交易成功 + */ + FINISHED("交易成功", "TRADE_FINISHED"), + + /** + * 支付成功 + */ + SUCCESS("支付成功", "TRADE_SUCCESS"), + + /** + * 交易创建 + */ + BUYER_PAY("交易创建", "WAIT_BUYER_PAY"), + + /** + * 交易关闭 + */ + CLOSED("交易关闭", "TRADE_CLOSED"); + + private String name; + private String value; + + AliPayStatusEnum(String name, String value) { + this.name = name; + this.value = value; + } + + public String getValue() { + return value; + } +} diff --git a/src/main/java/me/zhengjie/tools/util/AlipayUtils.java b/src/main/java/me/zhengjie/tools/util/AlipayUtils.java new file mode 100644 index 000000000..fbdccb18e --- /dev/null +++ b/src/main/java/me/zhengjie/tools/util/AlipayUtils.java @@ -0,0 +1,79 @@ +package me.zhengjie.tools.util; + +import cn.hutool.core.util.StrUtil; +import com.alipay.api.AlipayApiException; +import com.alipay.api.internal.util.AlipaySignature; +import me.zhengjie.tools.domain.AlipayConfig; +import org.springframework.stereotype.Component; +import javax.servlet.http.HttpServletRequest; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * 支付宝工具类 + * @author zhengjie + * @date 2018/09/30 14:04:35 + */ +@Component +public class AlipayUtils { + + /** + * 生成订单号 + * @return + */ + public String getOrderCode() { + SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + int a = (int)(Math.random() * 9000.0D) + 1000; + System.out.println(a); + Date date = new Date(); + String str = sdf.format(date); + String[] split = str.split("-"); + String s = split[0] + split[1] + split[2]; + String[] split1 = s.split(" "); + String s1 = split1[0] + split1[1]; + String[] split2 = s1.split(":"); + String s2 = split2[0] + split2[1] + split2[2] + a; + return s2; + } + + /** + * 校验签名 + * @param request + * @return + */ + public boolean rsaCheck(HttpServletRequest request, AlipayConfig alipay){ + + /** + * 获取支付宝POST过来反馈信息 + */ + Map params = new HashMap<>(1); + Map requestParams = request.getParameterMap(); + for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext();) { + String name = (String) iter.next(); + String[] values = (String[]) requestParams.get(name); + String valueStr = ""; + for (int i = 0; i < values.length; i++) { + valueStr = (i == values.length - 1) ? valueStr + values[i] + : valueStr + values[i] + ","; + } + params.put(name, valueStr); + } + + try { + boolean verifyResult = AlipaySignature.rsaCheckV1(params, + alipay.getPublicKey(), + alipay.getCharset(), + alipay.getSignType()); + return verifyResult; + } catch (AlipayApiException e) { + return false; + } + } + + public boolean isEmpty(String str){ + return StrUtil.isEmpty(str); + } +} diff --git a/src/main/java/me/zhengjie/tools/util/QiNiuUtil.java b/src/main/java/me/zhengjie/tools/util/QiNiuUtil.java new file mode 100644 index 000000000..c75b3e0d9 --- /dev/null +++ b/src/main/java/me/zhengjie/tools/util/QiNiuUtil.java @@ -0,0 +1,60 @@ +package me.zhengjie.tools.util; + +import com.qiniu.common.Zone; +import com.qiniu.storage.Configuration; +import me.zhengjie.common.utils.FileUtil; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * 七牛云存储工具类 + * @author jie + * @date 2018-12-31 + */ +public class QiNiuUtil { + + public static final String HUAD = "华东"; + + public static final String HUAB = "华北"; + + public static final String HUAN = "华南"; + + public static final String BEIM = "北美"; + + /** + * 得到机房的对应关系 + * @param zone + * @return + */ + public static Configuration getConfiguration(String zone){ + + if(HUAD.equals(zone)){ + return new Configuration(Zone.zone0()); + } else if(HUAB.equals(zone)){ + return new Configuration(Zone.zone1()); + } else if(HUAN.equals(zone)){ + return new Configuration(Zone.zone2()); + } else if (BEIM.equals(zone)){ + return new Configuration(Zone.zoneNa0()); + + // 否则就是东南亚 + } else { + return new Configuration(Zone.zoneAs0()); + } + } + + /** + * 默认不指定key的情况下,以文件内容的hash值作为文件名 + * @param file + * @return + */ + public static String getKey(String file){ + StringBuffer key = new StringBuffer(FileUtil.getFileNameNoEx(file)); + SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); + Date date = new Date(); + key.append(sdf.format(date)); + key.append("."); + key.append(FileUtil.getExtensionName(file)); + return key.toString(); + } +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 1f1c81e87..ff424c862 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -80,11 +80,20 @@ spring: jwt: header: Authorization secret: mySecret - # token 过期时间 1个小时 - expiration: 3600000 + # token 过期时间 2个小时 + expiration: 7200000 # expiration: 60000 auth: # 授权路径 path: /login # 获取用户信息 - account: /info \ No newline at end of file + account: /info + +#七牛云 +qiniu: + # 文件大小 /M + max-size: 5 + +#验证码有效时间/分钟 +code: + expiration: 5 \ No newline at end of file