mirror of https://github.com/elunez/eladmin
v1.3 版本发布,详细信息查看发行版说明
parent
d329b0c8b0
commit
1ec10e3d38
22
README.md
22
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 @@
|
|||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://i.loli.net/2018/12/22/5c1e10c7a9f7d.png"/></td>
|
||||
<td><img src="https://i.imgur.com/FzVaAlS.png"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><img src="https://i.imgur.com/ah3X2HG.png"/></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
#### 反馈交流
|
||||
|
||||
- QQ交流群:891137268
|
||||
- QQ交流群:<a target="_blank" href="//shang.qq.com/wpa/qunwpa?idkey=90830191a40600e3a07acdcc4864890fca50c8e3ca1772e7e288a561d576f6c4"><img border="0" src="//pub.idqqimg.com/wpa/images/group.png" alt="Quella/el-admin" title="Quella/el-admin"></a>
|
||||
|
||||
- 作者邮箱:elunez@qq.com
|
||||
|
|
14
pom.xml
14
pom.xml
|
@ -161,6 +161,20 @@
|
|||
<version>1.4.7</version>
|
||||
</dependency>
|
||||
|
||||
<!--七牛云存储-->
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>[7.2.0, 7.2.99]</version>
|
||||
</dependency>
|
||||
|
||||
<!--支付宝依赖-->
|
||||
<dependency>
|
||||
<groupId>com.alipay.sdk</groupId>
|
||||
<artifactId>alipay-sdk-java</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
|
|
111
sql/eladmin.sql
111
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;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of picture
|
||||
-- Table structure for qiniu_config
|
||||
-- ----------------------------
|
||||
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_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;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for qiniu_content
|
||||
-- ----------------------------
|
||||
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;
|
||||
|
|
|
@ -13,6 +13,9 @@ import org.aspectj.lang.annotation.Pointcut;
|
|||
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
|
||||
|
|
|
@ -3,6 +3,8 @@ package me.zhengjie.common.exception;
|
|||
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 @@ import org.springframework.http.HttpStatus;
|
|||
*/
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,14 @@ import me.zhengjie.common.exception.EntityExistException;
|
|||
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 @@ import static org.springframework.http.HttpStatus.NOT_FOUND;
|
|||
@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<ApiError> 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 class GlobalExceptionHandler {
|
|||
*/
|
||||
@ExceptionHandler(value = EntityExistException.class)
|
||||
public ResponseEntity<ApiError> 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 class GlobalExceptionHandler {
|
|||
*/
|
||||
@ExceptionHandler(value = EntityNotFoundException.class)
|
||||
public ResponseEntity<ApiError> 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 class GlobalExceptionHandler {
|
|||
*/
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public ResponseEntity<ApiError> 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 class GlobalExceptionHandler {
|
|||
private ResponseEntity<ApiError> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,21 +7,13 @@ package me.zhengjie.common.utils;
|
|||
*/
|
||||
public class ElAdminConstant {
|
||||
|
||||
/**
|
||||
* 用于七牛云zone与机房对应关系
|
||||
*/
|
||||
public static class QiNiu{
|
||||
public static final String RESET_PASS = "重置密码";
|
||||
|
||||
public static final String HUAD = "华东";
|
||||
public static final String RESET_MAIL = "重置邮箱";
|
||||
|
||||
public static final String HUAB = "华北";
|
||||
public static final String EMAIL_CODE = "<p>你的验证码为:";
|
||||
|
||||
public static final String HUAN = "华南";
|
||||
|
||||
public static final String BEIM = "北美";
|
||||
|
||||
public static final String DNY = "东南亚";
|
||||
}
|
||||
public static final String EMAIL_CONTENT = "<p style='text-align: right;'>----- 邮件来自<span style='color: rgb(194, 79, 74);'> <a href='http://auauz.net' target='_blank'>eladmin</a></span> 后台管理系统,系统邮件请勿回复</p>";
|
||||
|
||||
/**
|
||||
* 常用接口
|
||||
|
|
|
@ -78,12 +78,18 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
.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 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||
@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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,8 @@ import lombok.AllArgsConstructor;
|
|||
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;
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ public class JwtUserDetailsService implements UserDetailsService {
|
|||
user.getEmail(),
|
||||
mapToGrantedAuthorities(user.getRoles(),permissionRepository),
|
||||
user.getEnabled(),
|
||||
user.getCreateTime(),
|
||||
user.getLastPasswordResetTime()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,12 +5,10 @@ import io.jsonwebtoken.impl.DefaultClock;
|
|||
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.HashMap;
|
|||
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 class JwtTokenUtil implements Serializable {
|
|||
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 class JwtTokenUtil implements Serializable {
|
|||
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;
|
||||
|
|
|
@ -20,19 +20,12 @@ public class LogFilter extends Filter<ILoggingEvent>{
|
|||
public FilterReply decide(ILoggingEvent event) {
|
||||
String exception = "";
|
||||
IThrowableProxy iThrowableProxy1 = event.getThrowableProxy();
|
||||
if(iThrowableProxy1!=null){
|
||||
exception = "<span class='excehtext'>"+iThrowableProxy1.getClassName()+" "+iThrowableProxy1.getMessage()+"</span></br>";
|
||||
for(int i=0; i<iThrowableProxy1.getStackTraceElementProxyArray().length;i++){
|
||||
exception += "<span class='excetext'>"+iThrowableProxy1.getStackTraceElementProxyArray()[i].toString()+"</span></br>";
|
||||
}
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -45,6 +45,10 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
|||
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("<pre>"+log.getBody()+"</pre>");
|
||||
}
|
||||
if(log.getClassName().equals("jdbc.resultsettable")){
|
||||
log.setBody("<br><pre>"+log.getBody()+"</pre>");
|
||||
}
|
||||
|
|
|
@ -16,5 +16,4 @@ public class LogMessage {
|
|||
private String threadName;
|
||||
private String className;
|
||||
private String level;
|
||||
private String exception;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -83,7 +83,9 @@ public class LoggingServiceImpl implements LoggingService {
|
|||
username = user.getUsername();
|
||||
|
||||
}
|
||||
logging.setMethod(methodName);
|
||||
if (params.length() > 1000){
|
||||
params = params.substring(0,999);
|
||||
}
|
||||
logging.setUsername(username);
|
||||
logging.setParams(params + " }");
|
||||
loggingRepository.save(logging);
|
||||
|
|
|
@ -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 @@ import java.sql.Timestamp;
|
|||
*/
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package me.zhengjie.system.repository;
|
|||
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<User, Long>, 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);
|
||||
}
|
||||
|
|
|
@ -9,4 +9,12 @@ import org.springframework.data.jpa.repository.JpaRepository;
|
|||
*/
|
||||
public interface VerificationCodeRepository extends JpaRepository<VerificationCode, Long> {
|
||||
|
||||
/**
|
||||
* 获取有效的验证码
|
||||
* @param scenes 业务场景,如重置密码,重置邮箱等等
|
||||
* @param type
|
||||
* @param value
|
||||
* @return
|
||||
*/
|
||||
VerificationCode findByScenesAndTypeAndValueAndStatusIsTrue(String scenes,String type,String value);
|
||||
}
|
||||
|
|
|
@ -2,17 +2,31 @@ package me.zhengjie.system.rest;
|
|||
|
||||
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 class UserController {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
/**
|
||||
* 验证
|
||||
|
|
|
@ -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 class MenuServiceImpl implements MenuService {
|
|||
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 class MenuServiceImpl implements MenuService {
|
|||
Optional<Menu> 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());
|
||||
|
|
|
@ -4,6 +4,7 @@ import me.zhengjie.common.exception.BadRequestException;
|
|||
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 class UserServiceImpl implements UserService {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() + "</p>";
|
||||
emailVo = new EmailVo(Arrays.asList(code.getValue()),"eladmin后台管理系统",content);
|
||||
timedDestruction(verificationCodeRepository.save(code));
|
||||
// 存在就再次发送原来的验证码
|
||||
} else {
|
||||
content = ElAdminConstant.EMAIL_CODE + verificationCode.getCode() + "</p>";
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -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 = "公开";
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 @@ import java.util.List;
|
|||
* @date 2018/09/28 12:02:14
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class EmailVo {
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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<AlipayConfig,Long> {
|
||||
}
|
|
@ -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<QiniuConfig,Long> {
|
||||
}
|
|
@ -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<QiniuContent,Long>, JpaSpecificationExecutor {
|
||||
|
||||
/**
|
||||
* 根据key查询
|
||||
* @param key
|
||||
* @return
|
||||
*/
|
||||
QiniuContent findByKey(String key);
|
||||
}
|
|
@ -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<String, String[]> 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);
|
||||
}
|
||||
}
|
|
@ -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 class EmailController {
|
|||
return new ResponseEntity(HttpStatus.OK);
|
||||
}
|
||||
|
||||
@PreAuthorize("hasAnyRole('ADMIN')")
|
||||
@Log(description = "发送邮件")
|
||||
@PostMapping(value = "/email")
|
||||
public ResponseEntity send(@Validated @RequestBody EmailVo emailVo) throws Exception {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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> 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);
|
||||
}
|
||||
}
|
|
@ -3,6 +3,7 @@ package me.zhengjie.tools.service.impl;
|
|||
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 class EmailServiceImpl implements EmailService {
|
|||
account.setFrom(emailConfig.getUser()+"<"+emailConfig.getFromUser()+">");
|
||||
//ssl方式发送
|
||||
account.setStartttlsEnable(true);
|
||||
String content = emailVo.getContent()+ "<p style='text-align: right;'>----- 邮件来自<span style='color: rgb(194, 79, 74);'> <a href='http://auauz.net' target='_blank'>eladmin</a></span> 后台管理系统</p>";
|
||||
String content = emailVo.getContent()+ ElAdminConstant.EMAIL_CONTENT;
|
||||
/**
|
||||
* 发送
|
||||
*/
|
||||
|
|
|
@ -70,7 +70,7 @@ public class PictureServiceImpl implements PictureService {
|
|||
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);
|
||||
|
|
|
@ -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> 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> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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<QiniuContent> {
|
||||
|
||||
private QiniuContent qiniuContent;
|
||||
|
||||
public Spec(QiniuContent qiniuContent){
|
||||
this.qiniuContent = qiniuContent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate toPredicate(Root<QiniuContent> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
|
||||
|
||||
List<Predicate> list = new ArrayList<Predicate>();
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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<String,String> 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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
#七牛云
|
||||
qiniu:
|
||||
# 文件大小 /M
|
||||
max-size: 5
|
||||
|
||||
#验证码有效时间/分钟
|
||||
code:
|
||||
expiration: 5
|
Loading…
Reference in New Issue