mirror of https://github.com/elunez/eladmin
v1.4 版本发布,修复bug、优化细节、新增定时任务管理,详细信息查看发行版说明
parent
588bff0219
commit
68e62678fc
13
README.md
13
README.md
|
@ -24,6 +24,18 @@
|
|||
|
||||
- 密码: 123456
|
||||
|
||||
#### 开发环境
|
||||
|
||||
- JDK:8
|
||||
|
||||
- IDE:IntelliJ IDEA (后端)
|
||||
|
||||
- IDE:JetBrains WebStorm (前端)
|
||||
|
||||
- 依赖管理:Maven
|
||||
|
||||
- 数据库:MySQL 5.5.59
|
||||
|
||||
#### 系统功能模块
|
||||
|
||||
- 用户管理 提供用户的相关配置
|
||||
|
@ -36,6 +48,7 @@
|
|||
- redis管理 将redis的操作可视化,提供对redis的基本操作
|
||||
- redis限流 对系统的流量进行控制,由[everhopingandwaiting](https://github.com/everhopingandwaiting)提供
|
||||
- SQL监控 采用 druid 监控数据库访问性能
|
||||
- 定时任务管理 整合quartz做定时任务
|
||||
- 三方工具: 邮件工具,sm.ms免费图床,支付宝支付,七牛云存储
|
||||
- 富文本编辑器
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
Target Server Version : 50559
|
||||
File Encoding : 65001
|
||||
|
||||
Date: 06/01/2019 13:09:59
|
||||
Date: 08/01/2019 16:17:02
|
||||
*/
|
||||
|
||||
SET NAMES utf8mb4;
|
||||
|
@ -71,7 +71,7 @@ CREATE TABLE `log` (
|
|||
`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 = 4553 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 5066 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for menu
|
||||
|
@ -88,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 = 25 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 29 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of menu
|
||||
|
@ -105,17 +105,19 @@ INSERT INTO `menu` VALUES (9, '2018-12-18 15:19:34', b'1', 'SQL监控', NULL, 6,
|
|||
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');
|
||||
INSERT INTO `menu` VALUES (13, '2018-12-27 10:11:26', b'0', '三方工具', '', 0, 20, 'tools', 'tools');
|
||||
INSERT INTO `menu` VALUES (14, '2018-12-27 10:13:09', b'0', '邮件工具', 'tools/email/index', 13, 21, 'email', 'email');
|
||||
INSERT INTO `menu` VALUES (13, '2018-12-27 10:11:26', b'0', '三方工具', '', 0, 30, 'tools', 'tools');
|
||||
INSERT INTO `menu` VALUES (14, '2018-12-27 10:13:09', b'0', '邮件工具', 'tools/email/index', 13, 31, 'email', 'email');
|
||||
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 (16, '2018-12-28 09:36:53', b'0', 'SM.MS图床', 'tools/picture/index', 13, 32, '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');
|
||||
INSERT INTO `menu` VALUES (21, '2019-01-04 16:22:03', b'0', '多级菜单', '', 0, 900, 'menu', 'menu1');
|
||||
INSERT INTO `menu` VALUES (22, '2019-01-04 16:23:29', b'0', '二级菜单1', '', 21, 999, 'menu', 'menu1-1');
|
||||
INSERT INTO `menu` VALUES (23, '2019-01-04 16:23:57', b'0', '二级菜单2', '', 21, 999, 'menu', 'menu1-2');
|
||||
INSERT INTO `menu` VALUES (24, '2019-01-04 16:24:48', b'1', '三级菜单', '', 22, 999, 'chain', 'https://github.com/elunez/eladmin');
|
||||
INSERT INTO `menu` VALUES (18, '2018-12-31 11:12:15', b'0', '七牛云存储', 'tools/qiniu/index', 13, 33, 'qiniu', 'qiniu');
|
||||
INSERT INTO `menu` VALUES (19, '2018-12-31 14:52:38', b'0', '支付宝工具', 'tools/aliPay/index', 13, 34, 'alipay', 'aliPay');
|
||||
INSERT INTO `menu` VALUES (21, '2019-01-04 16:22:03', b'0', '多级菜单', '', 0, 900, 'menu', 'nested');
|
||||
INSERT INTO `menu` VALUES (22, '2019-01-04 16:23:29', b'0', '二级菜单1', 'nested/menu1/index', 21, 999, 'menu', 'menu1');
|
||||
INSERT INTO `menu` VALUES (23, '2019-01-04 16:23:57', b'0', '二级菜单2', 'nested/menu2/index', 21, 999, 'menu', 'menu2');
|
||||
INSERT INTO `menu` VALUES (24, '2019-01-04 16:24:48', b'0', '三级菜单1', 'nested/menu1/menu1-1', 22, 999, 'menu', 'menu1-1');
|
||||
INSERT INTO `menu` VALUES (27, '2019-01-07 17:27:32', b'0', '三级菜单2', 'nested/menu1/menu1-2', 22, 999, 'menu', 'menu1-2');
|
||||
INSERT INTO `menu` VALUES (28, '2019-01-07 20:34:40', b'0', '定时任务', 'system/timing/index', 1, 6, 'timing', 'timing');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for menus_roles
|
||||
|
@ -156,6 +158,8 @@ INSERT INTO `menus_roles` VALUES (21, 1);
|
|||
INSERT INTO `menus_roles` VALUES (22, 1);
|
||||
INSERT INTO `menus_roles` VALUES (23, 1);
|
||||
INSERT INTO `menus_roles` VALUES (24, 1);
|
||||
INSERT INTO `menus_roles` VALUES (27, 1);
|
||||
INSERT INTO `menus_roles` VALUES (28, 1);
|
||||
INSERT INTO `menus_roles` VALUES (1, 2);
|
||||
INSERT INTO `menus_roles` VALUES (2, 2);
|
||||
INSERT INTO `menus_roles` VALUES (3, 2);
|
||||
|
@ -174,6 +178,8 @@ INSERT INTO `menus_roles` VALUES (21, 2);
|
|||
INSERT INTO `menus_roles` VALUES (22, 2);
|
||||
INSERT INTO `menus_roles` VALUES (23, 2);
|
||||
INSERT INTO `menus_roles` VALUES (24, 2);
|
||||
INSERT INTO `menus_roles` VALUES (27, 2);
|
||||
INSERT INTO `menus_roles` VALUES (28, 2);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for permission
|
||||
|
@ -186,7 +192,7 @@ CREATE TABLE `permission` (
|
|||
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`pid` int(11) NOT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 35 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 40 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of permission
|
||||
|
@ -221,6 +227,11 @@ INSERT INTO `permission` VALUES (30, '菜单查询', '2018-12-28 17:34:41', 'MEN
|
|||
INSERT INTO `permission` VALUES (31, '菜单创建', '2018-12-28 17:34:52', 'MENU_CREATE', 29);
|
||||
INSERT INTO `permission` VALUES (32, '菜单编辑', '2018-12-28 17:35:20', 'MENU_EDIT', 29);
|
||||
INSERT INTO `permission` VALUES (33, '菜单删除', '2018-12-28 17:35:29', 'MENU_DELETE', 29);
|
||||
INSERT INTO `permission` VALUES (35, '定时任务管理', '2019-01-08 14:59:57', 'JOB_ALL', 0);
|
||||
INSERT INTO `permission` VALUES (36, '任务查询', '2019-01-08 15:00:09', 'JOB_SELECT', 35);
|
||||
INSERT INTO `permission` VALUES (37, '任务创建', '2019-01-08 15:00:20', 'JOB_CREATE', 35);
|
||||
INSERT INTO `permission` VALUES (38, '任务编辑', '2019-01-08 15:00:33', 'JOB_EDIT', 35);
|
||||
INSERT INTO `permission` VALUES (39, '任务删除', '2019-01-08 15:01:13', 'JOB_DELETE', 35);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for picture
|
||||
|
@ -269,6 +280,48 @@ CREATE TABLE `qiniu_content` (
|
|||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for quartz_job
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `quartz_job`;
|
||||
CREATE TABLE `quartz_job` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`bean_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`is_pause` bit(1) NULL DEFAULT NULL,
|
||||
`jobName` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`params` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`updateTime` datetime NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Records of quartz_job
|
||||
-- ----------------------------
|
||||
INSERT INTO `quartz_job` VALUES (1, 'visitsTask', '0 0 0 * * ?', b'0', '更新访客记录', 'run', NULL, '每日0点创建新的访客记录', '2019-01-08 14:53:31');
|
||||
INSERT INTO `quartz_job` VALUES (2, 'testTask', '0/5 * * * * ?', b'1', '测试1', 'run1', 'test', '带参测试,多参使用json', '2019-01-08 14:53:25');
|
||||
INSERT INTO `quartz_job` VALUES (3, 'testTask', '0/5 * * * * ?', b'1', '测试', 'run', '', '不带参测试', '2019-01-08 15:56:54');
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for quartz_log
|
||||
-- ----------------------------
|
||||
DROP TABLE IF EXISTS `quartz_log`;
|
||||
CREATE TABLE `quartz_log` (
|
||||
`id` bigint(20) NOT NULL AUTO_INCREMENT,
|
||||
`baen_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`createTime` datetime NULL DEFAULT NULL,
|
||||
`cron_expression` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`exceptionDetail` text CHARACTER SET utf8 COLLATE utf8_general_ci NULL,
|
||||
`is_success` bit(1) NULL DEFAULT NULL,
|
||||
`job_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`method_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`params` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
|
||||
`time` bigint(20) NULL DEFAULT NULL,
|
||||
PRIMARY KEY (`id`) USING BTREE
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 90 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for role
|
||||
-- ----------------------------
|
||||
|
@ -310,6 +363,7 @@ INSERT INTO `roles_permissions` VALUES (2, 14);
|
|||
INSERT INTO `roles_permissions` VALUES (2, 19);
|
||||
INSERT INTO `roles_permissions` VALUES (2, 23);
|
||||
INSERT INTO `roles_permissions` VALUES (2, 30);
|
||||
INSERT INTO `roles_permissions` VALUES (2, 36);
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for user
|
||||
|
@ -332,7 +386,7 @@ CREATE TABLE `user` (
|
|||
-- ----------------------------
|
||||
-- Records of user
|
||||
-- ----------------------------
|
||||
INSERT INTO `user` VALUES (1, 'https://i.loli.net/2018/12/31/5c297270b20e2.jpg', '2018-08-23 09:11:56', 'admin@qq.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'admin', '2018-11-23 10:12:36');
|
||||
INSERT INTO `user` VALUES (1, 'https://i.loli.net/2018/12/31/5c297270b20e2.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/30/5c2871d6aa101.jpg', '2018-12-27 20:05:26', 'test@qq.com', 1, '14e1b600b1fd579f47433b88e8d85291', 'test', NULL);
|
||||
|
||||
-- ----------------------------
|
||||
|
@ -367,7 +421,7 @@ CREATE TABLE `verification_code` (
|
|||
`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 = 33 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 34 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
-- ----------------------------
|
||||
-- Table structure for visits
|
||||
|
@ -381,6 +435,6 @@ CREATE TABLE `visits` (
|
|||
`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 = 51 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
) ENGINE = InnoDB AUTO_INCREMENT = 54 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS = 1;
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
package me.zhengjie;
|
||||
|
||||
import me.zhengjie.common.utils.SpringContextHolder;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker;
|
||||
|
||||
|
@ -11,7 +12,6 @@ import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBr
|
|||
* @date 2018/11/15 9:20:19
|
||||
*/
|
||||
@SpringBootApplication
|
||||
@EnableScheduling
|
||||
@EnableTransactionManagement
|
||||
@EnableWebSocketMessageBroker
|
||||
public class AppRun {
|
||||
|
@ -19,4 +19,9 @@ public class AppRun {
|
|||
public static void main(String[] args) {
|
||||
SpringApplication.run(AppRun.class, args);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SpringContextHolder springContextHolder() {
|
||||
return new SpringContextHolder();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
package me.zhengjie.common.config;
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-08
|
||||
*/
|
||||
@Configuration
|
||||
public class ThreadPoolConfig {
|
||||
|
||||
@Bean
|
||||
public ExecutorService getThreadPool(){
|
||||
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("thread-call-runner-%d").build();
|
||||
int size = 2;
|
||||
ExecutorService executorService = new ThreadPoolExecutor(size,size,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),namedThreadFactory);
|
||||
return executorService;
|
||||
}
|
||||
}
|
|
@ -76,7 +76,7 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||
public RedisCacheConfiguration redisCacheConfiguration(){
|
||||
FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<>(Object.class);
|
||||
RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
|
||||
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofDays(30));
|
||||
configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2));
|
||||
return configuration;
|
||||
}
|
||||
|
||||
|
@ -95,6 +95,7 @@ public class RedisConfig extends CachingConfigurerSupport {
|
|||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.system.service.dto");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.system.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.tools.domain");
|
||||
ParserConfig.getGlobalInstance().addAccept("me.zhengjie.quartz.domain");
|
||||
// key的序列化采用StringRedisSerializer
|
||||
template.setKeySerializer(new StringRedisSerializer());
|
||||
template.setHashKeySerializer(new StringRedisSerializer());
|
||||
|
|
|
@ -26,7 +26,12 @@ import java.util.List;
|
|||
|
||||
@Configuration
|
||||
@EnableSwagger2
|
||||
@ComponentScan(basePackages = {"me.zhengjie.core.rest","me.zhengjie.system.rest","me.zhengjie.system.monitor"})
|
||||
@ComponentScan(basePackages = {
|
||||
"me.zhengjie.core.rest",
|
||||
"me.zhengjie.system.rest",
|
||||
"me.zhengjie.monitor.rest",
|
||||
"me.zhengjie.quartz.rest",
|
||||
"me.zhengjie.tools.rest",})
|
||||
public class SwaggerConfig {
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
package me.zhengjie.common.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
/**
|
||||
* @author
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
|
||||
|
||||
private static ApplicationContext applicationContext = null;
|
||||
|
||||
/**
|
||||
* 取得存储在静态变量中的ApplicationContext.
|
||||
*/
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
assertContextInjected();
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(String name) {
|
||||
assertContextInjected();
|
||||
return (T) applicationContext.getBean(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
|
||||
*/
|
||||
public static <T> T getBean(Class<T> requiredType) {
|
||||
assertContextInjected();
|
||||
return applicationContext.getBean(requiredType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查ApplicationContext不为空.
|
||||
*/
|
||||
private static void assertContextInjected() {
|
||||
if (applicationContext == null) {
|
||||
throw new IllegalStateException("applicaitonContext属性未注入, 请在applicationContext" +
|
||||
".xml中定义SpringContextHolder或在SpringBoot启动类中注册SpringContextHolder.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 清除SpringContextHolder中的ApplicationContext为Null.
|
||||
*/
|
||||
public static void clearHolder() {
|
||||
log.debug("清除SpringContextHolder中的ApplicationContext:"
|
||||
+ applicationContext);
|
||||
applicationContext = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
SpringContextHolder.clearHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
if (SpringContextHolder.applicationContext != null) {
|
||||
log.warn("SpringContextHolder中的ApplicationContext被覆盖, 原有ApplicationContext为:" + SpringContextHolder.applicationContext);
|
||||
}
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ public class LoggerQueue {
|
|||
|
||||
/**
|
||||
* 消息入队
|
||||
*
|
||||
* @param log
|
||||
* @return
|
||||
*/
|
||||
|
|
|
@ -1,18 +1,17 @@
|
|||
package me.zhengjie.monitor.config;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.monitor.service.VisitsService;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 初始化站点统计
|
||||
* @author jie
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
public class VisitsInitialization {
|
||||
|
||||
public VisitsInitialization(VisitsService visitsService){
|
||||
log.info("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------");
|
||||
System.out.println("--------------- 初始化站点统计,如果存在今日统计则跳过 ---------------");
|
||||
visitsService.save();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package me.zhengjie.monitor.config;
|
||||
|
||||
|
||||
import com.google.common.util.concurrent.ThreadFactoryBuilder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.monitor.domain.LogMessage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -9,8 +10,7 @@ import org.springframework.messaging.simp.SimpMessagingTemplate;
|
|||
import org.springframework.web.socket.config.annotation.StompEndpointRegistry;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
/**
|
||||
* 配置WebSocket消息代理端点,即stomp服务端
|
||||
|
@ -24,6 +24,9 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
|||
@Autowired
|
||||
private SimpMessagingTemplate messagingTemplate;
|
||||
|
||||
@Autowired
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Override
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/websocket")
|
||||
|
@ -36,9 +39,7 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
|||
*/
|
||||
@PostConstruct
|
||||
public void pushLogger(){
|
||||
ExecutorService executorService= Executors.newFixedThreadPool(2);
|
||||
Runnable runnable=new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
while (true) {
|
||||
|
@ -63,6 +64,5 @@ public class WebSocketConfig implements WebSocketMessageBrokerConfigurer {
|
|||
}
|
||||
};
|
||||
executorService.submit(runnable);
|
||||
executorService.submit(runnable);
|
||||
}
|
||||
}
|
|
@ -46,10 +46,10 @@ public class RedisController {
|
|||
}
|
||||
|
||||
@Log(description = "删除Redis缓存")
|
||||
@DeleteMapping(value = "/redis/{key}")
|
||||
@DeleteMapping(value = "/redis")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','REDIS_ALL','REDIS_DELETE')")
|
||||
public ResponseEntity delete(@PathVariable String key){
|
||||
redisService.delete(key);
|
||||
public ResponseEntity delete(@RequestBody RedisVo resources){
|
||||
redisService.delete(resources.getKey());
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package me.zhengjie.quartz.config;
|
||||
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import me.zhengjie.quartz.repository.QuartzJobRepository;
|
||||
import me.zhengjie.quartz.utils.QuartzManage;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.ApplicationArguments;
|
||||
import org.springframework.boot.ApplicationRunner;
|
||||
import org.springframework.stereotype.Component;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Component
|
||||
public class JobRunner implements ApplicationRunner {
|
||||
|
||||
@Autowired
|
||||
private QuartzJobRepository quartzJobRepository;
|
||||
|
||||
@Autowired
|
||||
private QuartzManage quartzManage;
|
||||
|
||||
/**
|
||||
* 项目启动时重新激活启用的定时任务
|
||||
* @param applicationArguments
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void run(ApplicationArguments applicationArguments){
|
||||
System.out.println("--------------------注入定时任务---------------------");
|
||||
List<QuartzJob> quartzJobs = quartzJobRepository.findByIsPauseIsFalse();
|
||||
quartzJobs.forEach(quartzJob -> {
|
||||
quartzManage.addJob(quartzJob);
|
||||
});
|
||||
System.out.println("--------------------定时任务注入完成---------------------");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package me.zhengjie.quartz.config;
|
||||
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.spi.TriggerFiredBundle;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.quartz.AdaptableJobFactory;
|
||||
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 定时任务配置
|
||||
* @author
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Configuration
|
||||
public class QuartzConfig {
|
||||
|
||||
/**
|
||||
* 解决Job中注入Spring Bean为null的问题
|
||||
*/
|
||||
@Component("quartzJobFactory")
|
||||
public class QuartzJobFactory extends AdaptableJobFactory {
|
||||
|
||||
@Autowired
|
||||
private AutowireCapableBeanFactory capableBeanFactory;
|
||||
|
||||
@Override
|
||||
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
|
||||
|
||||
//调用父类的方法
|
||||
Object jobInstance = super.createJobInstance(bundle);
|
||||
capableBeanFactory.autowireBean(jobInstance);
|
||||
return jobInstance;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入scheduler到spring
|
||||
* @param quartzJobFactory
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
@Bean(name = "scheduler")
|
||||
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
|
||||
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
|
||||
factoryBean.setJobFactory(quartzJobFactory);
|
||||
factoryBean.afterPropertiesSet();
|
||||
Scheduler scheduler=factoryBean.getScheduler();
|
||||
scheduler.start();
|
||||
return scheduler;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
package me.zhengjie.quartz.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import javax.persistence.*;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Data
|
||||
@Entity
|
||||
@Table(name = "quartz_job")
|
||||
public class QuartzJob implements Serializable {
|
||||
|
||||
public static final String JOB_KEY = "JOB_KEY";
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 定时器名称
|
||||
*/
|
||||
private String jobName;
|
||||
|
||||
/**
|
||||
* Bean名称
|
||||
*/
|
||||
@Column(name = "bean_name")
|
||||
@NotBlank
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
@Column(name = "method_name")
|
||||
@NotBlank
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
@Column(name = "params")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* cron表达式
|
||||
*/
|
||||
@Column(name = "cron_expression")
|
||||
@NotBlank
|
||||
private String cronExpression;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@Column(name = "is_pause")
|
||||
private Boolean isPause = false;
|
||||
|
||||
/**
|
||||
* 备注
|
||||
*/
|
||||
@Column(name = "remark")
|
||||
@NotBlank
|
||||
private String remark;
|
||||
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
@UpdateTimestamp
|
||||
private Timestamp updateTime;
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
package me.zhengjie.quartz.domain;
|
||||
|
||||
import lombok.Data;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import javax.persistence.*;
|
||||
import java.io.Serializable;
|
||||
import java.sql.Timestamp;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Entity
|
||||
@Data
|
||||
@Table(name = "quartz_log")
|
||||
public class QuartzLog implements Serializable {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 任务名称
|
||||
*/
|
||||
@Column(name = "job_name")
|
||||
private String jobName;
|
||||
|
||||
/**
|
||||
* Bean名称
|
||||
*/
|
||||
@Column(name = "baen_name")
|
||||
private String beanName;
|
||||
|
||||
/**
|
||||
* 方法名称
|
||||
*/
|
||||
@Column(name = "method_name")
|
||||
private String methodName;
|
||||
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
@Column(name = "params")
|
||||
private String params;
|
||||
|
||||
/**
|
||||
* cron表达式
|
||||
*/
|
||||
@Column(name = "cron_expression")
|
||||
private String cronExpression;
|
||||
|
||||
/**
|
||||
* 状态
|
||||
*/
|
||||
@Column(name = "is_success")
|
||||
private Boolean isSuccess;
|
||||
|
||||
/**
|
||||
* 异常详细
|
||||
*/
|
||||
@Column(columnDefinition = "text")
|
||||
private String exceptionDetail;
|
||||
|
||||
/**
|
||||
* 耗时(毫秒)
|
||||
*/
|
||||
private Long time;
|
||||
|
||||
/**
|
||||
* 创建日期
|
||||
*/
|
||||
@CreationTimestamp
|
||||
private Timestamp createTime;
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package me.zhengjie.quartz.repository;
|
||||
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
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.transaction.annotation.Transactional;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
public interface QuartzJobRepository extends JpaRepository<QuartzJob,Long>, JpaSpecificationExecutor {
|
||||
|
||||
/**
|
||||
* 更新状态
|
||||
* @param id
|
||||
*/
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
@Modifying
|
||||
@Query(value = "update quartz_job set is_pause = 1 where id = ?1",nativeQuery = true)
|
||||
void updateIsPause(Long id);
|
||||
|
||||
/**
|
||||
* 查询不是启用的任务
|
||||
* @return
|
||||
*/
|
||||
List<QuartzJob> findByIsPauseIsFalse();
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
package me.zhengjie.quartz.repository;
|
||||
|
||||
import me.zhengjie.quartz.domain.QuartzLog;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
public interface QuartzLogRepository extends JpaRepository<QuartzLog,Long>, JpaSpecificationExecutor {
|
||||
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
package me.zhengjie.quartz.rest;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.common.aop.log.Log;
|
||||
import me.zhengjie.common.exception.BadRequestException;
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import me.zhengjie.quartz.domain.QuartzLog;
|
||||
import me.zhengjie.quartz.service.QuartzJobService;
|
||||
import me.zhengjie.quartz.service.query.QuartzJobQueryService;
|
||||
import me.zhengjie.quartz.service.query.QuartzLogQueryService;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@RestController
|
||||
@RequestMapping("/api")
|
||||
public class QuartzJobController {
|
||||
|
||||
private static final String ENTITY_NAME = "quartzJob";
|
||||
|
||||
@Autowired
|
||||
private QuartzJobService quartzJobService;
|
||||
|
||||
@Autowired
|
||||
private QuartzJobQueryService quartzJobQueryService;
|
||||
|
||||
@Autowired
|
||||
private QuartzLogQueryService quartzLogQueryService;
|
||||
|
||||
@Log(description = "查询定时任务")
|
||||
@GetMapping(value = "/jobs")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')")
|
||||
public ResponseEntity getJobs(QuartzJob resources, Pageable pageable){
|
||||
return new ResponseEntity(quartzJobQueryService.queryAll(resources,pageable), HttpStatus.OK);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询定时任务日志
|
||||
* @param resources
|
||||
* @param pageable
|
||||
* @return
|
||||
*/
|
||||
@GetMapping(value = "/jobLogs")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_SELECT')")
|
||||
public ResponseEntity getJobLogs(QuartzLog resources, Pageable pageable){
|
||||
return new ResponseEntity(quartzLogQueryService.queryAll(resources,pageable), HttpStatus.OK);
|
||||
}
|
||||
|
||||
@Log(description = "新增定时任务")
|
||||
@PostMapping(value = "/jobs")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_CREATE')")
|
||||
public ResponseEntity create(@Validated @RequestBody QuartzJob resources){
|
||||
if (resources.getId() != null) {
|
||||
throw new BadRequestException("A new "+ ENTITY_NAME +" cannot already have an ID");
|
||||
}
|
||||
return new ResponseEntity(quartzJobService.create(resources),HttpStatus.CREATED);
|
||||
}
|
||||
|
||||
@Log(description = "修改定时任务")
|
||||
@PutMapping(value = "/jobs")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
|
||||
public ResponseEntity update(@Validated @RequestBody QuartzJob resources){
|
||||
if (resources.getId() == null) {
|
||||
throw new BadRequestException(ENTITY_NAME +" ID Can not be empty");
|
||||
}
|
||||
quartzJobService.update(resources);
|
||||
return new ResponseEntity(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log(description = "更改定时任务状态")
|
||||
@PutMapping(value = "/jobs/{id}")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
|
||||
public ResponseEntity updateIsPause(@PathVariable Long id){
|
||||
quartzJobService.updateIsPause(quartzJobService.findById(id));
|
||||
return new ResponseEntity(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log(description = "执行定时任务")
|
||||
@PutMapping(value = "/jobs/exec/{id}")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_EDIT')")
|
||||
public ResponseEntity execution(@PathVariable Long id){
|
||||
quartzJobService.execution(quartzJobService.findById(id));
|
||||
return new ResponseEntity(HttpStatus.NO_CONTENT);
|
||||
}
|
||||
|
||||
@Log(description = "删除定时任务")
|
||||
@DeleteMapping(value = "/jobs/{id}")
|
||||
@PreAuthorize("hasAnyRole('ADMIN','JOB_ALL','JOB_DELETE')")
|
||||
public ResponseEntity delete(@PathVariable Long id){
|
||||
quartzJobService.delete(quartzJobService.findById(id));
|
||||
return new ResponseEntity(HttpStatus.OK);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package me.zhengjie.quartz.service;
|
||||
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
/**
|
||||
* @author 郑杰
|
||||
* @date 2018/10/05 19:17:38
|
||||
*/
|
||||
@CacheConfig(cacheNames = "quartzJob")
|
||||
public interface QuartzJobService {
|
||||
|
||||
/**
|
||||
* create
|
||||
* @param resources
|
||||
* @return
|
||||
*/
|
||||
@CacheEvict(allEntries = true)
|
||||
QuartzJob create(QuartzJob resources);
|
||||
|
||||
/**
|
||||
* update
|
||||
* @param resources
|
||||
* @return
|
||||
*/
|
||||
@CacheEvict(allEntries = true)
|
||||
void update(QuartzJob resources);
|
||||
|
||||
/**
|
||||
* del
|
||||
* @param quartzJob
|
||||
*/
|
||||
@CacheEvict(allEntries = true)
|
||||
void delete(QuartzJob quartzJob);
|
||||
|
||||
/**
|
||||
* findById
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@Cacheable(key = "#p0")
|
||||
QuartzJob findById(Long id);
|
||||
|
||||
/**
|
||||
* 更改定时任务状态
|
||||
* @param quartzJob
|
||||
*/
|
||||
@CacheEvict(allEntries = true)
|
||||
void updateIsPause(QuartzJob quartzJob);
|
||||
|
||||
/**
|
||||
* 立即执行定时任务
|
||||
* @param quartzJob
|
||||
*/
|
||||
void execution(QuartzJob quartzJob);
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
package me.zhengjie.quartz.service.impl;
|
||||
|
||||
import me.zhengjie.common.exception.BadRequestException;
|
||||
import me.zhengjie.common.utils.ValidationUtil;
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import me.zhengjie.quartz.repository.QuartzJobRepository;
|
||||
import me.zhengjie.quartz.service.QuartzJobService;
|
||||
import me.zhengjie.quartz.utils.QuartzManage;
|
||||
import org.quartz.CronExpression;
|
||||
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 2019-01-07
|
||||
*/
|
||||
@Service(value = "quartzJobService")
|
||||
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
|
||||
public class QuartzJobServiceImpl implements QuartzJobService {
|
||||
|
||||
@Autowired
|
||||
private QuartzJobRepository quartzJobRepository;
|
||||
|
||||
@Autowired
|
||||
private QuartzManage quartzManage;
|
||||
|
||||
@Override
|
||||
public QuartzJob findById(Long id) {
|
||||
Optional<QuartzJob> quartzJob = quartzJobRepository.findById(id);
|
||||
ValidationUtil.isNull(quartzJob,"QuartzJob","id",id);
|
||||
return quartzJob.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public QuartzJob create(QuartzJob resources) {
|
||||
if (!CronExpression.isValidExpression(resources.getCronExpression())){
|
||||
throw new BadRequestException("cron表达式格式错误");
|
||||
}
|
||||
resources = quartzJobRepository.save(resources);
|
||||
quartzManage.addJob(resources);
|
||||
return resources;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(QuartzJob resources) {
|
||||
if(resources.getId().equals(1L)){
|
||||
throw new BadRequestException("该任务不可操作");
|
||||
}
|
||||
if (!CronExpression.isValidExpression(resources.getCronExpression())){
|
||||
throw new BadRequestException("cron表达式格式错误");
|
||||
}
|
||||
resources = quartzJobRepository.save(resources);
|
||||
quartzManage.updateJobCron(resources);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateIsPause(QuartzJob quartzJob) {
|
||||
if(quartzJob.getId().equals(1L)){
|
||||
throw new BadRequestException("该任务不可操作");
|
||||
}
|
||||
if (quartzJob.getIsPause()) {
|
||||
quartzManage.resumeJob(quartzJob);
|
||||
quartzJob.setIsPause(false);
|
||||
} else {
|
||||
quartzManage.pauseJob(quartzJob);
|
||||
quartzJob.setIsPause(true);
|
||||
}
|
||||
quartzJobRepository.save(quartzJob);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execution(QuartzJob quartzJob) {
|
||||
if(quartzJob.getId().equals(1L)){
|
||||
throw new BadRequestException("该任务不可操作");
|
||||
}
|
||||
quartzManage.runAJobNow(quartzJob);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(QuartzJob quartzJob) {
|
||||
if(quartzJob.getId().equals(1L)){
|
||||
throw new BadRequestException("该任务不可操作");
|
||||
}
|
||||
quartzManage.deleteJob(quartzJob);
|
||||
quartzJobRepository.delete(quartzJob);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package me.zhengjie.quartz.service.query;
|
||||
|
||||
import me.zhengjie.common.utils.PageUtil;
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import me.zhengjie.quartz.repository.QuartzJobRepository;
|
||||
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 2019-01-07
|
||||
*/
|
||||
@Service
|
||||
@CacheConfig(cacheNames = "quartzJob")
|
||||
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
|
||||
public class QuartzJobQueryService {
|
||||
|
||||
@Autowired
|
||||
private QuartzJobRepository quartzJobRepository;
|
||||
|
||||
@Cacheable(keyGenerator = "keyGenerator")
|
||||
public Object queryAll(QuartzJob quartzJob, Pageable pageable){
|
||||
return PageUtil.toPage(quartzJobRepository.findAll(new Spec(quartzJob),pageable));
|
||||
}
|
||||
|
||||
class Spec implements Specification<QuartzJob> {
|
||||
|
||||
private QuartzJob quartzJob;
|
||||
|
||||
public Spec(QuartzJob quartzJob){
|
||||
this.quartzJob = quartzJob;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate toPredicate(Root<QuartzJob> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
|
||||
|
||||
List<Predicate> list = new ArrayList<Predicate>();
|
||||
|
||||
if(!ObjectUtils.isEmpty(quartzJob.getJobName())){
|
||||
|
||||
/**
|
||||
* 模糊
|
||||
*/
|
||||
list.add(cb.like(root.get("jobName").as(String.class),"%"+quartzJob.getJobName()+"%"));
|
||||
}
|
||||
|
||||
Predicate[] p = new Predicate[list.size()];
|
||||
return cb.and(list.toArray(p));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package me.zhengjie.quartz.service.query;
|
||||
|
||||
import me.zhengjie.common.utils.PageUtil;
|
||||
import me.zhengjie.quartz.domain.QuartzLog;
|
||||
import me.zhengjie.quartz.repository.QuartzLogRepository;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
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 2019-01-07
|
||||
*/
|
||||
@Service
|
||||
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
|
||||
public class QuartzLogQueryService {
|
||||
|
||||
@Autowired
|
||||
private QuartzLogRepository quartzLogRepository;
|
||||
|
||||
public Object queryAll(QuartzLog quartzLog, Pageable pageable){
|
||||
return PageUtil.toPage(quartzLogRepository.findAll(new Spec(quartzLog),pageable));
|
||||
}
|
||||
|
||||
class Spec implements Specification<QuartzLog> {
|
||||
|
||||
private QuartzLog quartzLog;
|
||||
|
||||
public Spec(QuartzLog quartzLog){
|
||||
this.quartzLog = quartzLog;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate toPredicate(Root<QuartzLog> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
|
||||
|
||||
List<Predicate> list = new ArrayList<Predicate>();
|
||||
|
||||
if(!ObjectUtils.isEmpty(quartzLog.getJobName())){
|
||||
|
||||
/**
|
||||
* 模糊
|
||||
*/
|
||||
list.add(cb.like(root.get("jobName").as(String.class),"%"+quartzLog.getJobName()+"%"));
|
||||
}
|
||||
|
||||
if (!ObjectUtils.isEmpty(quartzLog.getIsSuccess())) {
|
||||
list.add(cb.equal(root.get("isSuccess").as(Boolean.class), quartzLog.getIsSuccess()));
|
||||
}
|
||||
|
||||
Predicate[] p = new Predicate[list.size()];
|
||||
return cb.and(list.toArray(p));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package me.zhengjie.quartz.task;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 测试用
|
||||
* @author jie
|
||||
* @date 2019-01-08
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class TestTask {
|
||||
|
||||
public void run(){
|
||||
log.info("执行成功");
|
||||
}
|
||||
|
||||
public void run1(String str){
|
||||
log.info("执行成功,参数为: {}" + str);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,7 @@
|
|||
package me.zhengjie.monitor.config;
|
||||
package me.zhengjie.quartz.task;
|
||||
|
||||
import me.zhengjie.monitor.service.VisitsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
|
@ -11,17 +9,12 @@ import org.springframework.stereotype.Component;
|
|||
* @date 2018-12-25
|
||||
*/
|
||||
@Component
|
||||
@Async
|
||||
public class VisitsScheduling {
|
||||
public class VisitsTask {
|
||||
|
||||
@Autowired
|
||||
private VisitsService visitsService;
|
||||
|
||||
/**
|
||||
* 每天0点运行
|
||||
*/
|
||||
@Scheduled(cron = "0 0 0 * * ?")
|
||||
public void save(){
|
||||
public void run(){
|
||||
visitsService.save();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package me.zhengjie.quartz.utils;
|
||||
|
||||
import me.zhengjie.common.utils.SpringContextHolder;
|
||||
import me.zhengjie.common.utils.ThrowableUtil;
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import me.zhengjie.quartz.domain.QuartzLog;
|
||||
import me.zhengjie.quartz.repository.QuartzLogRepository;
|
||||
import me.zhengjie.quartz.service.QuartzJobService;
|
||||
import org.quartz.JobExecutionContext;
|
||||
import org.quartz.Scheduler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.scheduling.quartz.QuartzJobBean;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
|
||||
/**
|
||||
* 参考人人开源,https://gitee.com/renrenio/renren-security
|
||||
* @author
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Async
|
||||
public class ExecutionJob extends QuartzJobBean {
|
||||
|
||||
@Resource(name = "scheduler")
|
||||
private Scheduler scheduler;
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Autowired
|
||||
private ExecutorService executorService;
|
||||
|
||||
@Override
|
||||
protected void executeInternal(JobExecutionContext context) {
|
||||
QuartzJob quartzJob = (QuartzJob) context.getMergedJobDataMap().get(QuartzJob.JOB_KEY);
|
||||
// 获取spring bean
|
||||
QuartzLogRepository quartzLogRepository = SpringContextHolder.getBean("quartzLogRepository");
|
||||
QuartzJobService quartzJobService = SpringContextHolder.getBean("quartzJobService");
|
||||
QuartzManage quartzManage = SpringContextHolder.getBean("quartzManage");
|
||||
|
||||
QuartzLog log = new QuartzLog();
|
||||
log.setJobName(quartzJob.getJobName());
|
||||
log.setBeanName(quartzJob.getBeanName());
|
||||
log.setMethodName(quartzJob.getMethodName());
|
||||
log.setParams(quartzJob.getParams());
|
||||
long startTime = System.currentTimeMillis();
|
||||
log.setCronExpression(quartzJob.getCronExpression());
|
||||
try {
|
||||
// 执行任务
|
||||
logger.info("任务准备执行,任务名称:{}", quartzJob.getJobName());
|
||||
QuartzRunnable task = new QuartzRunnable(quartzJob.getBeanName(), quartzJob.getMethodName(),
|
||||
quartzJob.getParams());
|
||||
Future<?> future = executorService.submit(task);
|
||||
future.get();
|
||||
long times = System.currentTimeMillis() - startTime;
|
||||
log.setTime(times);
|
||||
// 任务状态
|
||||
log.setIsSuccess(true);
|
||||
logger.info("任务执行完毕,任务名称:{} 总共耗时:{} 毫秒", quartzJob.getJobName(), times);
|
||||
} catch (Exception e) {
|
||||
logger.error("任务执行失败,任务名称:{}" + quartzJob.getJobName(), e);
|
||||
long times = System.currentTimeMillis() - startTime;
|
||||
log.setTime(times);
|
||||
// 任务状态 0:成功 1:失败
|
||||
log.setIsSuccess(false);
|
||||
log.setExceptionDetail(ThrowableUtil.getStackTrace(e));
|
||||
//出错就暂停任务
|
||||
quartzManage.pauseJob(quartzJob);
|
||||
//更新状态
|
||||
quartzJobService.updateIsPause(quartzJob);
|
||||
} finally {
|
||||
quartzLogRepository.save(log);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,156 @@
|
|||
package me.zhengjie.quartz.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.common.exception.BadRequestException;
|
||||
import me.zhengjie.quartz.domain.QuartzJob;
|
||||
import org.quartz.*;
|
||||
import org.quartz.impl.triggers.CronTriggerImpl;
|
||||
import org.springframework.stereotype.Component;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Date;
|
||||
import static org.quartz.TriggerBuilder.newTrigger;
|
||||
|
||||
/**
|
||||
* @author jie
|
||||
* @date 2019-01-07
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class QuartzManage {
|
||||
|
||||
private static final String JOB_NAME = "TASK_";
|
||||
|
||||
@Resource(name = "scheduler")
|
||||
private Scheduler scheduler;
|
||||
|
||||
public void addJob(QuartzJob quartzJob){
|
||||
try {
|
||||
// 构建job信息
|
||||
JobDetail jobDetail = JobBuilder.newJob(ExecutionJob.class).
|
||||
withIdentity(JOB_NAME + quartzJob.getId()).build();
|
||||
|
||||
//通过触发器名和cron 表达式创建 Trigger
|
||||
Trigger cronTrigger = newTrigger()
|
||||
.withIdentity(JOB_NAME + quartzJob.getId())
|
||||
.startNow()
|
||||
.withSchedule(CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression()))
|
||||
.build();
|
||||
|
||||
cronTrigger.getJobDataMap().put(QuartzJob.JOB_KEY, quartzJob);
|
||||
|
||||
//重置启动时间
|
||||
((CronTriggerImpl)cronTrigger).setStartTime(new Date());
|
||||
|
||||
//执行定时任务
|
||||
scheduler.scheduleJob(jobDetail,cronTrigger);
|
||||
|
||||
// 暂停任务
|
||||
if (quartzJob.getIsPause()) {
|
||||
pauseJob(quartzJob);
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("创建定时任务失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新job cron表达式
|
||||
* @param quartzJob
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public void updateJobCron(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
|
||||
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
|
||||
//重置启动时间
|
||||
((CronTriggerImpl)trigger).setStartTime(new Date());
|
||||
|
||||
scheduler.rescheduleJob(triggerKey, trigger);
|
||||
// 暂停任务
|
||||
if (quartzJob.getIsPause()) {
|
||||
pauseJob(quartzJob);
|
||||
}
|
||||
} catch (Exception e){
|
||||
log.error("更新定时任务失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除一个job
|
||||
* @param quartzJob
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public void deleteJob(QuartzJob quartzJob){
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.deleteJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("删除定时任务失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复一个job
|
||||
* @param quartzJob
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public void resumeJob(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// 如果不存在则创建一个定时任务
|
||||
if(trigger == null){
|
||||
addJob(quartzJob);
|
||||
}
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.resumeJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("恢复定时任务失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 立即执行job
|
||||
* @param quartzJob
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public void runAJobNow(QuartzJob quartzJob){
|
||||
try {
|
||||
TriggerKey triggerKey = TriggerKey.triggerKey(JOB_NAME + quartzJob.getId());
|
||||
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
|
||||
// 如果不存在则创建一个定时任务
|
||||
if(trigger == null){
|
||||
addJob(quartzJob);
|
||||
}
|
||||
JobDataMap dataMap = new JobDataMap();
|
||||
dataMap.put(QuartzJob.JOB_KEY, quartzJob);
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.triggerJob(jobKey,dataMap);
|
||||
} catch (Exception e){
|
||||
log.error("定时任务执行失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 暂停一个job
|
||||
* @param quartzJob
|
||||
* @throws SchedulerException
|
||||
*/
|
||||
public void pauseJob(QuartzJob quartzJob){
|
||||
try {
|
||||
JobKey jobKey = JobKey.jobKey(JOB_NAME + quartzJob.getId());
|
||||
scheduler.pauseJob(jobKey);
|
||||
} catch (Exception e){
|
||||
log.error("定时任务暂停失败", e);
|
||||
throw new BadRequestException(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package me.zhengjie.quartz.utils;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.zhengjie.common.utils.SpringContextHolder;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* 执行定时任务
|
||||
* @author
|
||||
*/
|
||||
@Slf4j
|
||||
public class QuartzRunnable implements Runnable {
|
||||
|
||||
private Object target;
|
||||
private Method method;
|
||||
private String params;
|
||||
|
||||
QuartzRunnable(String beanName, String methodName, String params)
|
||||
throws NoSuchMethodException, SecurityException {
|
||||
this.target = SpringContextHolder.getBean(beanName);
|
||||
this.params = params;
|
||||
|
||||
if (StringUtils.isNotBlank(params)) {
|
||||
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
|
||||
} else {
|
||||
this.method = target.getClass().getDeclaredMethod(methodName);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
ReflectionUtils.makeAccessible(method);
|
||||
if (StringUtils.isNotBlank(params)) {
|
||||
method.invoke(target, params);
|
||||
} else {
|
||||
method.invoke(target);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("定时任务执行失败",e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -162,13 +162,15 @@ public class MenuServiceImpl implements MenuService {
|
|||
if(menuDTO.getPid().equals(0L)){
|
||||
//一级目录需要加斜杠,不然访问不了
|
||||
menuVo.setPath("/" + menuDTO.getPath());
|
||||
menuVo.setRedirect("noredirect");
|
||||
menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent());
|
||||
}else if(!StrUtil.isEmpty(menuDTO.getComponent())){
|
||||
menuVo.setComponent(menuDTO.getComponent());
|
||||
}
|
||||
menuVo.setComponent(StrUtil.isEmpty(menuDTO.getComponent())?"Layout":menuDTO.getComponent());
|
||||
}
|
||||
menuVo.setMeta(new MenuMetaVo(menuDTO.getName(),menuDTO.getIcon()));
|
||||
if(menuDTOList!=null && menuDTOList.size()!=0){
|
||||
menuVo.setAlwaysShow(true);
|
||||
menuVo.setRedirect("noredirect");
|
||||
menuVo.setChildren(buildMenus(menuDTOList));
|
||||
// 处理是一级菜单并且没有子菜单的情况
|
||||
} else if(menuDTO.getPid().equals(0L)){
|
||||
|
|
|
@ -13,6 +13,7 @@ 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.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.ScheduledExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
|
|
@ -46,7 +46,6 @@ spring:
|
|||
jpa:
|
||||
properties:
|
||||
hibernate:
|
||||
show_sql: true
|
||||
dialect: org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
hibernate:
|
||||
ddl-auto: update
|
||||
|
|
Loading…
Reference in New Issue