From 354fe5ccf51b5192dec7b4417e916daab9b4ddd4 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Thu, 22 Dec 2022 18:01:49 +0800 Subject: [PATCH 01/26] feat: schedule compare job --- .../monitor/job/service/JobServiceImpl.java | 4 +- .../xq/project/monitor/job/task/RyTask.java | 21 ++-- .../monitor/job/util/AbstractQuartzJob.java | 19 ++- .../monitor/job/util/JobInvokeUtil.java | 99 ++++++---------- .../QuartzDisallowConcurrentExecution.java | 3 +- .../monitor/job/util/QuartzJobExecution.java | 3 +- .../monitor/job/util/ScheduleUtils.java | 108 +++++++++++++----- .../controller/JobConfigController.java | 13 ++- .../jobconfig/service/IJobconfigService.java | 4 +- .../service/JobconfigServiceImpl.java | 37 +++++- .../templates/system/jobconfig/add.html | 44 ++++++- 11 files changed, 230 insertions(+), 125 deletions(-) diff --git a/src/main/java/com/vince/xq/project/monitor/job/service/JobServiceImpl.java b/src/main/java/com/vince/xq/project/monitor/job/service/JobServiceImpl.java index 427ef4c..8517d94 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/service/JobServiceImpl.java +++ b/src/main/java/com/vince/xq/project/monitor/job/service/JobServiceImpl.java @@ -39,12 +39,12 @@ public class JobServiceImpl implements IJobService @PostConstruct public void init() throws SchedulerException, TaskException { - scheduler.clear(); + /*scheduler.clear(); List jobList = jobMapper.selectJobAll(); for (Job job : jobList) { ScheduleUtils.createScheduleJob(scheduler, job); - } + }*/ } /** diff --git a/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java b/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java index 5e17ede..0930006 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java +++ b/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java @@ -1,28 +1,31 @@ package com.vince.xq.project.monitor.job.task; import com.vince.xq.common.utils.StringUtils; +import com.vince.xq.project.system.instance.service.IInstanceService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 定时任务调度测试 - * + * * @author ruoyi */ @Component("ryTask") -public class RyTask -{ - public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) - { +public class RyTask { + + @Autowired + private IInstanceService instanceService; + + public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) { System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i)); } - public void ryParams(String params) - { + public void ryParams(String params) throws Exception { System.out.println("执行有参方法:" + params); + instanceService.runJob(params); } - public void ryNoParams() - { + public void ryNoParams() { System.out.println("执行无参方法"); } } diff --git a/src/main/java/com/vince/xq/project/monitor/job/util/AbstractQuartzJob.java b/src/main/java/com/vince/xq/project/monitor/job/util/AbstractQuartzJob.java index d5f7bf5..0c95605 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/util/AbstractQuartzJob.java +++ b/src/main/java/com/vince/xq/project/monitor/job/util/AbstractQuartzJob.java @@ -7,6 +7,7 @@ import com.vince.xq.common.utils.StringUtils; import com.vince.xq.common.utils.bean.BeanUtils; import com.vince.xq.common.utils.spring.SpringUtils; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.slf4j.Logger; @@ -33,7 +34,7 @@ public abstract class AbstractQuartzJob implements org.quartz.Job @Override public void execute(JobExecutionContext context) throws JobExecutionException { - Job job = new Job(); + Jobconfig job = new Jobconfig(); BeanUtils.copyBeanProp(job, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES)); try { @@ -55,9 +56,8 @@ public void execute(JobExecutionContext context) throws JobExecutionException * 执行前 * * @param context 工作执行上下文对象 - * @param sysJob 系统计划任务 */ - protected void before(JobExecutionContext context, Job job) + protected void before(JobExecutionContext context, Jobconfig job) { threadLocal.set(new Date()); } @@ -66,17 +66,16 @@ protected void before(JobExecutionContext context, Job job) * 执行后 * * @param context 工作执行上下文对象 - * @param sysScheduleJob 系统计划任务 */ - protected void after(JobExecutionContext context, Job job, Exception e) + protected void after(JobExecutionContext context, Jobconfig job, Exception e) { Date startTime = threadLocal.get(); threadLocal.remove(); final JobLog jobLog = new JobLog(); - jobLog.setJobName(job.getJobName()); - jobLog.setJobGroup(job.getJobGroup()); - jobLog.setInvokeTarget(job.getInvokeTarget()); + jobLog.setJobName(job.getId().toString()); + jobLog.setJobGroup("test-job"); + //jobLog.setInvokeTarget(job.getInvokeTarget()); jobLog.setStartTime(startTime); jobLog.setEndTime(new Date()); long runMs = jobLog.getEndTime().getTime() - jobLog.getStartTime().getTime(); @@ -93,7 +92,7 @@ protected void after(JobExecutionContext context, Job job, Exception e) } // 写入数据库当中 - SpringUtils.getBean(IJobLogService.class).addJobLog(jobLog); + //SpringUtils.getBean(IJobLogService.class).addJobLog(jobLog); } /** @@ -103,5 +102,5 @@ protected void after(JobExecutionContext context, Job job, Exception e) * @param job 系统计划任务 * @throws Exception 执行过程中的异常 */ - protected abstract void doExecute(JobExecutionContext context, Job job) throws Exception; + protected abstract void doExecute(JobExecutionContext context, Jobconfig job) throws Exception; } \ No newline at end of file diff --git a/src/main/java/com/vince/xq/project/monitor/job/util/JobInvokeUtil.java b/src/main/java/com/vince/xq/project/monitor/job/util/JobInvokeUtil.java index 9318a6b..ffc9d60 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/util/JobInvokeUtil.java +++ b/src/main/java/com/vince/xq/project/monitor/job/util/JobInvokeUtil.java @@ -8,33 +8,27 @@ import com.vince.xq.common.utils.StringUtils; import com.vince.xq.common.utils.spring.SpringUtils; import com.vince.xq.project.monitor.job.domain.Job; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; /** * 任务执行工具 * * @author ruoyi */ -public class JobInvokeUtil -{ +public class JobInvokeUtil { /** * 执行方法 - * - * @param sysJob 系统任务 */ - public static void invokeMethod(Job job) throws Exception - { - String invokeTarget = job.getInvokeTarget(); + public static void invokeMethod(Jobconfig job) throws Exception { + String invokeTarget = "ryTask.ryParams('" + job.getId() + "')"; String beanName = getBeanName(invokeTarget); String methodName = getMethodName(invokeTarget); List methodParams = getMethodParams(invokeTarget); - if (!isValidClassName(beanName)) - { + if (!isValidClassName(beanName)) { Object bean = SpringUtils.getBean(beanName); invokeMethod(bean, methodName, methodParams); - } - else - { + } else { Object bean = Class.forName(beanName).newInstance(); invokeMethod(bean, methodName, methodParams); } @@ -43,21 +37,17 @@ public static void invokeMethod(Job job) throws Exception /** * 调用任务方法 * - * @param bean 目标对象 - * @param methodName 方法名称 + * @param bean 目标对象 + * @param methodName 方法名称 * @param methodParams 方法参数 */ private static void invokeMethod(Object bean, String methodName, List methodParams) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, - InvocationTargetException - { - if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) - { + InvocationTargetException { + if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0) { Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams)); method.invoke(bean, getMethodParamsValue(methodParams)); - } - else - { + } else { Method method = bean.getClass().getMethod(methodName); method.invoke(bean); } @@ -65,81 +55,70 @@ private static void invokeMethod(Object bean, String methodName, List /** * 校验是否为为class包名 - * + * * @param invokeTarget 名称 * @return true是 false否 */ - public static boolean isValidClassName(String invokeTarget) - { + public static boolean isValidClassName(String invokeTarget) { return StringUtils.countMatches(invokeTarget, ".") > 1; } /** * 获取bean名称 - * + * * @param invokeTarget 目标字符串 * @return bean名称 */ - public static String getBeanName(String invokeTarget) - { + public static String getBeanName(String invokeTarget) { String beanName = StringUtils.substringBefore(invokeTarget, "("); return StringUtils.substringBeforeLast(beanName, "."); } /** * 获取bean方法 - * + * * @param invokeTarget 目标字符串 * @return method方法 */ - public static String getMethodName(String invokeTarget) - { + public static String getMethodName(String invokeTarget) { String methodName = StringUtils.substringBefore(invokeTarget, "("); return StringUtils.substringAfterLast(methodName, "."); } /** * 获取method方法参数相关列表 - * + * * @param invokeTarget 目标字符串 * @return method方法相关参数列表 */ - public static List getMethodParams(String invokeTarget) - { + public static List getMethodParams(String invokeTarget) { String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")"); - if (StringUtils.isEmpty(methodStr)) - { + if (StringUtils.isEmpty(methodStr)) { return null; } String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)"); List classs = new LinkedList<>(); - for (int i = 0; i < methodParams.length; i++) - { + for (int i = 0; i < methodParams.length; i++) { String str = StringUtils.trimToEmpty(methodParams[i]); // String字符串类型,以'或"开头 - if (StringUtils.startsWithAny(str, "'", "\"")) - { - classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class }); + if (StringUtils.startsWithAny(str, "'", "\"")) { + classs.add(new Object[]{StringUtils.substring(str, 1, str.length() - 1), String.class}); } // boolean布尔类型,等于true或者false - else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) - { - classs.add(new Object[] { Boolean.valueOf(str), Boolean.class }); + else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str)) { + classs.add(new Object[]{Boolean.valueOf(str), Boolean.class}); } // long长整形,以L结尾 - else if (StringUtils.endsWith(str, "L")) - { - classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class }); + else if (StringUtils.endsWith(str, "L")) { + classs.add(new Object[]{Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class}); } // double浮点类型,以D结尾 - else if (StringUtils.endsWith(str, "D")) - { - classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class }); + else if (StringUtils.endsWith(str, "D")) { + classs.add(new Object[]{Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class}); } // 其他类型归类为整形 - else - { - classs.add(new Object[] { Integer.valueOf(str), Integer.class }); + else { + classs.add(new Object[]{Integer.valueOf(str), Integer.class}); } } return classs; @@ -147,16 +126,14 @@ else if (StringUtils.endsWith(str, "D")) /** * 获取参数类型 - * + * * @param methodParams 参数相关列表 * @return 参数类型列表 */ - public static Class[] getMethodParamsType(List methodParams) - { + public static Class[] getMethodParamsType(List methodParams) { Class[] classs = new Class[methodParams.size()]; int index = 0; - for (Object[] os : methodParams) - { + for (Object[] os : methodParams) { classs[index] = (Class) os[1]; index++; } @@ -165,16 +142,14 @@ public static Class[] getMethodParamsType(List methodParams) /** * 获取参数值 - * + * * @param methodParams 参数相关列表 * @return 参数值列表 */ - public static Object[] getMethodParamsValue(List methodParams) - { + public static Object[] getMethodParamsValue(List methodParams) { Object[] classs = new Object[methodParams.size()]; int index = 0; - for (Object[] os : methodParams) - { + for (Object[] os : methodParams) { classs[index] = (Object) os[0]; index++; } diff --git a/src/main/java/com/vince/xq/project/monitor/job/util/QuartzDisallowConcurrentExecution.java b/src/main/java/com/vince/xq/project/monitor/job/util/QuartzDisallowConcurrentExecution.java index c926163..999bdb6 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/util/QuartzDisallowConcurrentExecution.java +++ b/src/main/java/com/vince/xq/project/monitor/job/util/QuartzDisallowConcurrentExecution.java @@ -1,5 +1,6 @@ package com.vince.xq.project.monitor.job.util; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import org.quartz.DisallowConcurrentExecution; import org.quartz.JobExecutionContext; import com.vince.xq.project.monitor.job.domain.Job; @@ -14,7 +15,7 @@ public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob { @Override - protected void doExecute(JobExecutionContext context, Job job) throws Exception + protected void doExecute(JobExecutionContext context, Jobconfig job) throws Exception { JobInvokeUtil.invokeMethod(job); } diff --git a/src/main/java/com/vince/xq/project/monitor/job/util/QuartzJobExecution.java b/src/main/java/com/vince/xq/project/monitor/job/util/QuartzJobExecution.java index f120202..a3d5dde 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/util/QuartzJobExecution.java +++ b/src/main/java/com/vince/xq/project/monitor/job/util/QuartzJobExecution.java @@ -1,5 +1,6 @@ package com.vince.xq.project.monitor.job.util; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import org.quartz.JobExecutionContext; import com.vince.xq.project.monitor.job.domain.Job; @@ -12,7 +13,7 @@ public class QuartzJobExecution extends AbstractQuartzJob { @Override - protected void doExecute(JobExecutionContext context, Job job) throws Exception + protected void doExecute(JobExecutionContext context, Jobconfig job) throws Exception { JobInvokeUtil.invokeMethod(job); } diff --git a/src/main/java/com/vince/xq/project/monitor/job/util/ScheduleUtils.java b/src/main/java/com/vince/xq/project/monitor/job/util/ScheduleUtils.java index e1561bb..1fc3424 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/util/ScheduleUtils.java +++ b/src/main/java/com/vince/xq/project/monitor/job/util/ScheduleUtils.java @@ -3,6 +3,7 @@ import com.vince.xq.common.constant.Constants; import com.vince.xq.common.utils.StringUtils; import com.vince.xq.common.utils.spring.SpringUtils; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import org.quartz.CronScheduleBuilder; import org.quartz.CronTrigger; import org.quartz.JobBuilder; @@ -19,45 +20,80 @@ /** * 定时任务工具类 - * - * @author ruoyi * + * @author ruoyi */ -public class ScheduleUtils -{ +public class ScheduleUtils { /** * 得到quartz任务类 * - * @param sysJob 执行计划 * @return 具体执行任务类 */ - private static Class getQuartzJobClass(Job job) - { + private static Class getQuartzJobClass(Job job) { boolean isConcurrent = "0".equals(job.getConcurrent()); return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; } + private static Class getQuartzJobClass(Jobconfig job) { + boolean isConcurrent = "0".equals("1"); + return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class; + } + /** * 构建任务触发对象 */ - public static TriggerKey getTriggerKey(Long jobId, String jobGroup) - { + public static TriggerKey getTriggerKey(Long jobId, String jobGroup) { return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); } /** * 构建任务键对象 */ - public static JobKey getJobKey(Long jobId, String jobGroup) - { + public static JobKey getJobKey(Long jobId, String jobGroup) { return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup); } + public static void createScheduleJob(Scheduler scheduler, Jobconfig job) throws SchedulerException, TaskException { + Class jobClass = getQuartzJobClass(job); + // 构建job信息 + Long jobId = job.getId(); + String jobGroup = "test-job"; + JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build(); + + // 表达式调度构建器 + CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getSchduleTime()); + cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder); + + // 按新的cronExpression表达式构建一个新的trigger + CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup)) + .withSchedule(cronScheduleBuilder).build(); + + // 放入参数,运行时的方法可以获取 + jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); + + // 判断是否存在 + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) { + // 防止创建时存在数据问题 先移除,然后在执行创建操作 + scheduler.deleteJob(getJobKey(jobId, jobGroup)); + } + + // 判断任务是否过期 + if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getSchduleTime()))) { + // 执行调度任务 + scheduler.scheduleJob(jobDetail, trigger); + } + + // 暂停任务 + if (job.getSchduleStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) { + scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); + } + } + + /** * 创建定时任务 */ - public static void createScheduleJob(Scheduler scheduler, Job job) throws SchedulerException, TaskException - { + public static void createScheduleJob(Scheduler scheduler, Job job) throws SchedulerException, TaskException { Class jobClass = getQuartzJobClass(job); // 构建job信息 Long jobId = job.getJobId(); @@ -76,33 +112,31 @@ public static void createScheduleJob(Scheduler scheduler, Job job) throws Schedu jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job); // 判断是否存在 - if (scheduler.checkExists(getJobKey(jobId, jobGroup))) - { + if (scheduler.checkExists(getJobKey(jobId, jobGroup))) { // 防止创建时存在数据问题 先移除,然后在执行创建操作 scheduler.deleteJob(getJobKey(jobId, jobGroup)); } // 判断任务是否过期 - if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) - { + if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression()))) { // 执行调度任务 scheduler.scheduleJob(jobDetail, trigger); } // 暂停任务 - if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) - { + if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue())) { scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup)); } } + /** * 设置定时任务策略 */ - public static CronScheduleBuilder handleCronScheduleMisfirePolicy(Job job, CronScheduleBuilder cb) - throws TaskException - { - switch (job.getMisfirePolicy()) + public static CronScheduleBuilder handleCronScheduleMisfirePolicy(Jobconfig job, CronScheduleBuilder cb) + throws TaskException { + return cb; + /*switch (job.getMisfirePolicy()) { case ScheduleConstants.MISFIRE_DEFAULT: return cb; @@ -115,21 +149,39 @@ public static CronScheduleBuilder handleCronScheduleMisfirePolicy(Job job, CronS default: throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); + }*/ + } + + /** + * 设置定时任务策略 + */ + public static CronScheduleBuilder handleCronScheduleMisfirePolicy(Job job, CronScheduleBuilder cb) + throws TaskException { + switch (job.getMisfirePolicy()) { + case ScheduleConstants.MISFIRE_DEFAULT: + return cb; + case ScheduleConstants.MISFIRE_IGNORE_MISFIRES: + return cb.withMisfireHandlingInstructionIgnoreMisfires(); + case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED: + return cb.withMisfireHandlingInstructionFireAndProceed(); + case ScheduleConstants.MISFIRE_DO_NOTHING: + return cb.withMisfireHandlingInstructionDoNothing(); + default: + throw new TaskException("The task misfire policy '" + job.getMisfirePolicy() + + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR); } } /** * 检查包名是否为白名单配置 - * + * * @param invokeTarget 目标字符串 * @return 结果 */ - public static boolean whiteList(String invokeTarget) - { + public static boolean whiteList(String invokeTarget) { String packageName = StringUtils.substringBefore(invokeTarget, "("); int count = StringUtils.countMatches(packageName, "."); - if (count > 1) - { + if (count > 1) { return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR); } Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]); diff --git a/src/main/java/com/vince/xq/project/system/jobconfig/controller/JobConfigController.java b/src/main/java/com/vince/xq/project/system/jobconfig/controller/JobConfigController.java index a515e78..36d58a4 100644 --- a/src/main/java/com/vince/xq/project/system/jobconfig/controller/JobConfigController.java +++ b/src/main/java/com/vince/xq/project/system/jobconfig/controller/JobConfigController.java @@ -1,7 +1,11 @@ package com.vince.xq.project.system.jobconfig.controller; +import com.vince.xq.common.constant.ScheduleConstants; import com.vince.xq.framework.aspectj.lang.annotation.Log; import com.vince.xq.framework.aspectj.lang.enums.BusinessType; +import com.vince.xq.project.monitor.job.domain.Job; +import com.vince.xq.project.monitor.job.util.CronUtils; +import com.vince.xq.project.monitor.job.util.ScheduleUtils; import com.vince.xq.project.system.jobconfig.service.IJobconfigService; import com.vince.xq.framework.web.controller.BaseController; import com.vince.xq.framework.web.domain.AjaxResult; @@ -10,6 +14,7 @@ import com.vince.xq.project.system.instance.service.IInstanceService; import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.quartz.Scheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -99,7 +104,13 @@ public String add(ModelMap mmap) { @ResponseBody public AjaxResult addSave(@Validated Jobconfig jobconfig) { try { - return toAjax(jobconfigService.insertJobconfig(jobconfig)); + if (jobconfig.getSchduleStatus().equals("0")) {//定时调度 + if (!CronUtils.isValid(jobconfig.getSchduleTime())) { + return error("新增任务失败,Cron表达式不正确"); + } + } + jobconfigService.insertJobconfig(jobconfig); + return success(); } catch (Exception e) { e.printStackTrace(); return error(e.getMessage()); diff --git a/src/main/java/com/vince/xq/project/system/jobconfig/service/IJobconfigService.java b/src/main/java/com/vince/xq/project/system/jobconfig/service/IJobconfigService.java index 04095cc..5be86fe 100644 --- a/src/main/java/com/vince/xq/project/system/jobconfig/service/IJobconfigService.java +++ b/src/main/java/com/vince/xq/project/system/jobconfig/service/IJobconfigService.java @@ -1,6 +1,8 @@ package com.vince.xq.project.system.jobconfig.service; +import com.vince.xq.common.exception.job.TaskException; import com.vince.xq.project.system.jobconfig.domain.Jobconfig; +import org.quartz.SchedulerException; import java.util.List; @@ -23,7 +25,7 @@ public interface IJobconfigService public int deleteJobconfigByIds(String ids); - public int insertJobconfig(Jobconfig dbconfig); + public void insertJobconfig(Jobconfig dbconfig) throws TaskException, SchedulerException; public int updateJobconfig(Jobconfig dbconfig); diff --git a/src/main/java/com/vince/xq/project/system/jobconfig/service/JobconfigServiceImpl.java b/src/main/java/com/vince/xq/project/system/jobconfig/service/JobconfigServiceImpl.java index 5d1628b..fcf5900 100644 --- a/src/main/java/com/vince/xq/project/system/jobconfig/service/JobconfigServiceImpl.java +++ b/src/main/java/com/vince/xq/project/system/jobconfig/service/JobconfigServiceImpl.java @@ -1,16 +1,24 @@ package com.vince.xq.project.system.jobconfig.service; import com.vince.xq.common.constant.Constants; +import com.vince.xq.common.constant.ScheduleConstants; +import com.vince.xq.common.exception.job.TaskException; import com.vince.xq.common.utils.security.ShiroUtils; import com.vince.xq.common.utils.text.Convert; +import com.vince.xq.project.monitor.job.domain.Job; +import com.vince.xq.project.monitor.job.mapper.JobMapper; +import com.vince.xq.project.monitor.job.util.ScheduleUtils; import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import com.vince.xq.project.system.jobconfig.mapper.JobconfigMapper; import com.vince.xq.project.common.DbTypeEnum; import com.vince.xq.project.system.dbconfig.domain.Dbconfig; import com.vince.xq.project.system.dbconfig.mapper.DbconfigMapper; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import javax.annotation.PostConstruct; import java.sql.*; import java.util.ArrayList; import java.util.List; @@ -29,6 +37,25 @@ public class JobconfigServiceImpl implements IJobconfigService { @Autowired private DbconfigMapper dbconfigMapper; + @Autowired + private JobMapper jobMapper; + + @Autowired + private Scheduler scheduler; + + @PostConstruct + public void init() throws SchedulerException, TaskException + { + scheduler.clear(); + List jobList = jobconfigMapper.selectJobconfigAll(); + for (Jobconfig job : jobList) + { + if (job.getSchduleStatus().equals("0")){ + ScheduleUtils.createScheduleJob(scheduler, job); + } + } + } + @Override public List selectJobconfigList(Jobconfig dbconfig) { return jobconfigMapper.selectJobconfigList(dbconfig); @@ -89,12 +116,14 @@ public int deleteJobconfigByIds(String ids) { @Override - public int insertJobconfig(Jobconfig dbconfig) { - dbconfig.setCreateBy(ShiroUtils.getLoginName()); - return jobconfigMapper.insertJobconfig(dbconfig); + public void insertJobconfig(Jobconfig jobconfig) throws TaskException, SchedulerException { + jobconfig.setCreateBy(ShiroUtils.getLoginName()); + int rows = jobconfigMapper.insertJobconfig(jobconfig); + if (rows > 0) { + ScheduleUtils.createScheduleJob(scheduler, jobconfig); + } } - @Override public int updateJobconfig(Jobconfig dbconfig) { dbconfig.setCreateBy(ShiroUtils.getLoginName()); diff --git a/src/main/resources/templates/system/jobconfig/add.html b/src/main/resources/templates/system/jobconfig/add.html index d97f105..6e61d79 100644 --- a/src/main/resources/templates/system/jobconfig/add.html +++ b/src/main/resources/templates/system/jobconfig/add.html @@ -50,7 +50,7 @@
+ >
@@ -59,9 +59,21 @@
+ >
+ +
+ +
+ +
+
+
@@ -78,27 +90,38 @@
- +
- +
- +
- + +
+
+ +
@@ -111,6 +134,15 @@ + + +
+ + + + + + + + + +
+ dataCompare平台邮件 +
+
+ +

+ + + 对比结果: + +

+ +

量级对比校验通过:{0}


+

一致性对比校验通过:{1}


+

详细对比信息去dataCompare平台进行查看


+
+
+

dataCompare平台发送,请勿回复
+ Please do not reply to this system email +

+ +
+
+
+
+
+ + \ No newline at end of file diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 0b690be..b34f7ae 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -1,7 +1,7 @@ # 项目相关配置 ruoyi: # 名称 - name: RuoYi + name: dataComapre # 版本 version: 4.7.5 # 版权年份 @@ -45,6 +45,18 @@ user: # Spring配置 spring: + mail: + enabled: false + host: smtp.qq.com + username: xxx@qq.com + password: xxx + properties: + mail: + smtp: + auth: true + starttls: + enable: true + required: true # 模板引擎 thymeleaf: mode: HTML @@ -64,7 +76,7 @@ spring: druid: # 主库数据源 master: - url: jdbc:mysql://127.0.0.1:3306/dataCompare?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + url: jdbc:mysql://ip:3306/dataCompare?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 username: root password: 123456 # 从库数据源 diff --git a/src/test/java/SpringBootApplicationTest.java b/src/test/java/SpringBootApplicationTest.java new file mode 100644 index 0000000..0875476 --- /dev/null +++ b/src/test/java/SpringBootApplicationTest.java @@ -0,0 +1,94 @@ +import com.vince.xq.DataCompareApplication; +import com.vince.xq.common.constant.Constants; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; +import org.springframework.mail.SimpleMailMessage; +import org.springframework.mail.javamail.JavaMailSender; +import org.springframework.mail.javamail.MimeMessageHelper; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import javax.mail.MessagingException; +import javax.mail.internet.MimeMessage; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.text.MessageFormat; + +@RunWith(SpringJUnit4ClassRunner.class) +@SpringBootTest(classes = DataCompareApplication.class) +public class SpringBootApplicationTest { + + @Autowired + private JavaMailSender javaMailSender; + + @Value("${spring.mail.username}") + private String fromEmail; + + @Test + public void sendHtmlMail() throws MessagingException { + String content = buildTemplate(true, true); + MimeMessage mimeMessage = javaMailSender.createMimeMessage(); + try { + MimeMessageHelper helper = new MimeMessageHelper(mimeMessage, true); + helper.setFrom(fromEmail); + helper.setTo("xiaoqiu2017wy@163.com"); + helper.setSubject(Constants.EMAIL_TITLE); + // 设置邮件内容,第二个参数设置是否支持 text/html 类型 + helper.setText(content, true); + javaMailSender.send(mimeMessage); + } catch (MessagingException e) { + e.printStackTrace(); + } + } + + @Test + public void sendMail() { + SimpleMailMessage message = new SimpleMailMessage(); + message.setFrom(fromEmail); + message.setTo("xiaoqiu2017wy@163.com"); + message.setSubject("主题:简单邮件"); + message.setText("测试邮件内容"); + javaMailSender.send(message); + } + + private String buildTemplate(boolean numFlag, boolean consistencyFlag) { + //加载邮件html模板 + Resource resource = new ClassPathResource("EmailTemplate.txt"); + InputStream inputStream = null; + BufferedReader fileReader = null; + StringBuffer buffer = new StringBuffer(); + String line = ""; + try { + inputStream = resource.getInputStream(); + fileReader = new BufferedReader(new InputStreamReader(inputStream)); + while ((line = fileReader.readLine()) != null) { + buffer.append(line); + } + } catch (Exception e) { + } finally { + if (fileReader != null) { + try { + fileReader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + //替换html模板中的参数 + return MessageFormat.format(buffer.toString(), numFlag, consistencyFlag); + } + +} \ No newline at end of file From 2e0b8f99a2320678e44a5600c65ef05233c821e2 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Fri, 17 Mar 2023 17:37:26 +0800 Subject: [PATCH 08/26] feat:profiling feat --- .../com/vince/xq/project/common/RunUtil.java | 141 +++++++++++++- .../xq/project/monitor/job/task/RyTask.java | 2 +- .../ProbeJobInstanceController.java | 96 ++++++++++ .../domain/ProbeJobInstance.java | 107 +++++++++++ .../domain/ProbeJobInstanceResult.java | 178 ++++++++++++++++++ .../mapper/ProbeJobInstanceMapper.java | 19 ++ .../service/IProbeJobInstanceService.java | 32 ++++ .../service/ProbeJobInstanceServiceImpl.java | 158 ++++++++++++++++ .../controller/ProbeJobConfigController.java | 147 +++++++++++++++ .../probeJobConfig/domain/Probejobconfig.java | 119 ++++++++++++ .../mapper/ProbeJobconfigMapper.java | 25 +++ .../service/IProbeJobconfigService.java | 36 ++++ .../service/ProbeJobconfigServiceImpl.java | 141 ++++++++++++++ .../mybatis/system/ProbeJobInstanceMapper.xml | 87 +++++++++ .../mybatis/system/ProbeJobconfigMapper.xml | 79 ++++++++ .../templates/system/probeJobConfig/add.html | 108 +++++++++++ .../templates/system/probeJobConfig/edit.html | 86 +++++++++ .../system/probeJobConfig/probeJobConfig.html | 111 +++++++++++ .../system/probeJobInstance/add.html | 108 +++++++++++ .../system/probeJobInstance/detail.html | 137 ++++++++++++++ .../system/probeJobInstance/edit.html | 86 +++++++++ .../probeJobInstance/probeJobInstance.html | 92 +++++++++ 22 files changed, 2088 insertions(+), 7 deletions(-) create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/controller/ProbeJobInstanceController.java create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/mapper/ProbeJobInstanceMapper.java create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/IProbeJobInstanceService.java create mode 100644 src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java create mode 100644 src/main/java/com/vince/xq/project/system/probeJobConfig/controller/ProbeJobConfigController.java create mode 100644 src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java create mode 100644 src/main/java/com/vince/xq/project/system/probeJobConfig/mapper/ProbeJobconfigMapper.java create mode 100644 src/main/java/com/vince/xq/project/system/probeJobConfig/service/IProbeJobconfigService.java create mode 100644 src/main/java/com/vince/xq/project/system/probeJobConfig/service/ProbeJobconfigServiceImpl.java create mode 100644 src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml create mode 100644 src/main/resources/mybatis/system/ProbeJobconfigMapper.xml create mode 100644 src/main/resources/templates/system/probeJobConfig/add.html create mode 100644 src/main/resources/templates/system/probeJobConfig/edit.html create mode 100644 src/main/resources/templates/system/probeJobConfig/probeJobConfig.html create mode 100644 src/main/resources/templates/system/probeJobInstance/add.html create mode 100644 src/main/resources/templates/system/probeJobInstance/detail.html create mode 100644 src/main/resources/templates/system/probeJobInstance/edit.html create mode 100644 src/main/resources/templates/system/probeJobInstance/probeJobInstance.html diff --git a/src/main/java/com/vince/xq/project/common/RunUtil.java b/src/main/java/com/vince/xq/project/common/RunUtil.java index 45b65b7..4222220 100644 --- a/src/main/java/com/vince/xq/project/common/RunUtil.java +++ b/src/main/java/com/vince/xq/project/common/RunUtil.java @@ -1,9 +1,13 @@ package com.vince.xq.project.common; +import com.alibaba.fastjson.JSONObject; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance; import com.vince.xq.project.system.instance.controller.InstanceController; import com.vince.xq.project.system.jobconfig.domain.Jobconfig; import com.vince.xq.project.system.dbconfig.domain.Dbconfig; import com.vince.xq.project.system.instance.domain.Instance; +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; +import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -140,9 +144,9 @@ public static Instance run(Dbconfig dbconfig, Jobconfig jobconfig) throws Except String compareNumSql = String.format(PV_UV_SQL, jobconfig.getOriginTablePrimary(), jobconfig.getOriginTableName(), Optional.ofNullable(jobconfig.getOriginTableFilter()).orElse("") , jobconfig.getToTablePrimary(), jobconfig.getToTableName(), Optional.ofNullable(jobconfig.getToTableFilter()).orElse("")); - log.info("====compareNumSql===="); + /*log.info("====compareNumSql===="); log.info(compareNumSql); - log.info("====compareNumSql===="); + log.info("====compareNumSql====");*/ String[] fileds = jobconfig.getOriginTableFields().split(","); List originColumns = new ArrayList<>(); @@ -172,9 +176,9 @@ public static Instance run(Dbconfig dbconfig, Jobconfig jobconfig) throws Except jobconfig.getToTableName(), Optional.ofNullable(jobconfig.getToTableFilter()).orElse("")); - log.info("====consistencyNumSql===="); + /*log.info("====consistencyNumSql===="); log.info(consistencyNumSql); - log.info("====consistencyNumSql===="); + log.info("====consistencyNumSql====");*/ Instance instance = runNum(dbconfig, dbTypeEnum.getConnectDriver(), compareNumSql, consistencyNumSql); instance.setMagnitudeSql(compareNumSql); @@ -199,9 +203,9 @@ public static List> runDiffDetail(Dbconfig dbconfi .replaceAll("fields_list_check_filter", String.join(" or ", fields_list_filter)) .replaceAll("fields_list_check", String.join(",", fields_list)); - log.info("====check_sql===="); + /*log.info("====check_sql===="); log.info(check_sql); - log.info("====check_sql===="); + log.info("====check_sql====");*/ DbTypeEnum dbTypeEnum = DbTypeEnum.findEnumByType(dbconfig.getType()); try { @@ -274,4 +278,129 @@ public static Instance runNum(Dbconfig dbconfig, String connectDriver, String co } return instance; } + + public static final String mainTemplateSql = "select count(distinct column) as distinct_cnt," + + "count(*) as cnt" + + " from tableName filter"; + + public static final String emptyTemplateSql = "select count(*) as cnt,column_dict as dict from (\n" + + "select *,\n" + + "case when column is null then 0\n" + + "else 1\n" + + "end as column_dict\n" + + "from tableName\n" + + "filter\n" + + ")t group by column_dict;"; + + public static final String enumTemplateSql = "select cnt,dict from (\n" + + "select count(*) as cnt,column as dict\n" + + "from tableName\n" + + "filter\n" + + "group by column\n" + + ")t order by cnt desc limit 20;"; + + public static ProbeJobInstance runProbeJob(Dbconfig dbconfig, Probejobconfig probejobconfig) throws Exception { + DbTypeEnum dbTypeEnum = DbTypeEnum.findEnumByType(dbconfig.getType()); + String filter = probejobconfig.getFilter(); + String mainSql = ""; + ProbeJobInstance instance = new ProbeJobInstance(); + if (StringUtils.isNotBlank(probejobconfig.getTablePrimary())) { + String primaryField = probejobconfig.getTablePrimary(); + mainSql = mainTemplateSql.replaceAll("column", primaryField).replace("tableName", probejobconfig.getTableName()).replace("filter", Optional.ofNullable(filter).orElse("")); + Map primaryResult = runProbJobPrimaryKey(dbconfig, dbTypeEnum.getConnectDriver(), mainSql); + if (primaryResult != null) { + Map> mainResult = new HashMap<>(); + mainResult.put(probejobconfig.getTablePrimary(), primaryResult); + instance.setPrimaryResult(JSONObject.toJSONString(mainResult)); + } + } + if (StringUtils.isNotBlank(probejobconfig.getTableNullFields())) { + String[] emptyFieldArr = probejobconfig.getTableNullFields().split(","); + Map>> emptyResult = new HashMap<>(); + for (String emptyField : emptyFieldArr) { + String sql = emptyTemplateSql.replaceAll("column", emptyField).replace("tableName", probejobconfig.getTableName()).replace("filter", Optional.ofNullable(filter).orElse("")); + List> emptyList = runProbJobField(dbconfig, dbTypeEnum.getConnectDriver(), sql); + emptyResult.put(emptyField, emptyList); + } + instance.setNullResult(JSONObject.toJSONString(emptyResult)); + } + if (StringUtils.isNotBlank(probejobconfig.getTableEnumFields())) { + String[] enumFieldArr = probejobconfig.getTableEnumFields().split(","); + Map>> enumResult = new HashMap<>(); + for (String enumField : enumFieldArr) { + String sql = enumTemplateSql.replaceAll("column", enumField).replace("tableName", probejobconfig.getTableName()).replace("filter", Optional.ofNullable(filter).orElse("")); + List> enumList = runProbJobField(dbconfig, dbTypeEnum.getConnectDriver(), sql); + enumResult.put(enumField, enumList); + } + instance.setEnumResult(JSONObject.toJSONString(enumResult)); + } + return instance; + } + + private static Map runProbJobPrimaryKey(Dbconfig dbconfig, String connectDriver, String sql) throws Exception { + try { + Class.forName(connectDriver); + } catch (ClassNotFoundException e) { + throw new Exception("注册驱动失败"); + } + Connection conn = null; + try { + conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd()); + Statement stat = conn.createStatement(); + if (StringUtils.isNotBlank(sql)) { + log.info("=====sql:{}=======", sql); + ResultSet re = stat.executeQuery(sql); + Map hashMap = new HashMap<>(); + while (re.next()) { + hashMap.put("distinct_cnt", re.getString(1)); + hashMap.put("cnt", re.getString(2)); + } + re.close(); + return hashMap; + } + stat.close(); + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + throw new Exception("连接数据库失败"); + } + return null; + } + + private static List> runProbJobField(Dbconfig dbconfig, String connectDriver, String sql) throws Exception { + try { + Class.forName(connectDriver); + } catch (ClassNotFoundException e) { + throw new Exception("注册驱动失败"); + } + Connection conn = null; + try { + conn = DriverManager.getConnection(dbconfig.getUrl(), dbconfig.getUserName(), dbconfig.getPwd()); + Statement stat = conn.createStatement(); + if (StringUtils.isNotBlank(sql)) { + log.info("=====sql:{}=======", sql); + ResultSet re = stat.executeQuery(sql); + ResultSetMetaData metaData = re.getMetaData(); //获取列集 + int columnCount = metaData.getColumnCount(); //获取列的数量 + List> list = new ArrayList<>(); + while (re.next()) { + LinkedHashMap hashMap = new LinkedHashMap(); + for (int i = 0; i < columnCount; i++) { //循环列 + String columnName = metaData.getColumnName(i + 1); //通过序号获取列名,起始值为1 + String columnValue = re.getString(columnName); //通过列名获取值.如果列值为空,columnValue为null,不是字符型 + hashMap.put(columnName, columnValue); + } + list.add(hashMap); + } + re.close(); + return list; + } + stat.close(); + conn.close(); + } catch (SQLException e) { + e.printStackTrace(); + throw new Exception("连接数据库失败"); + } + return null; + } } diff --git a/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java b/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java index 0930006..bdb6705 100644 --- a/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java +++ b/src/main/java/com/vince/xq/project/monitor/job/task/RyTask.java @@ -21,7 +21,7 @@ public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i) { } public void ryParams(String params) throws Exception { - System.out.println("执行有参方法:" + params); + //System.out.println("执行有参方法:" + params); instanceService.runJob(params); } diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/controller/ProbeJobInstanceController.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/controller/ProbeJobInstanceController.java new file mode 100644 index 0000000..f85b5ed --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/controller/ProbeJobInstanceController.java @@ -0,0 +1,96 @@ +package com.vince.xq.project.system.ProbeJobInstance.controller; + +import com.alibaba.fastjson.JSONObject; +import com.vince.xq.framework.aspectj.lang.annotation.Log; +import com.vince.xq.framework.aspectj.lang.enums.BusinessType; +import com.vince.xq.framework.web.controller.BaseController; +import com.vince.xq.framework.web.domain.AjaxResult; +import com.vince.xq.framework.web.page.TableDataInfo; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstanceResult; +import com.vince.xq.project.system.ProbeJobInstance.service.IProbeJobInstanceService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/system/probeJobInstance") +public class ProbeJobInstanceController extends BaseController { + private static final Logger log = LoggerFactory.getLogger(ProbeJobInstanceController.class); + + private String prefix = "system/probeJobInstance"; + + @Autowired + private IProbeJobInstanceService instanceService; + + @RequiresPermissions("system:probeJobInstance:view") + @GetMapping() + public String operlog() { + return prefix + "/probeJobInstance"; + } + + @RequiresPermissions("system:probeJobInstance:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(ProbeJobInstance Instance) { + startPage(); + List list = instanceService.selectInstanceList(Instance); + return getDataTable(list); + } + + @RequiresPermissions("system:probeJobInstance:insert") + @Log(title = "instance管理", businessType = BusinessType.INSERT) + @PostMapping("/insert") + @ResponseBody + public AjaxResult insert(ProbeJobInstance instance) { + try { + return toAjax(instanceService.insertInstance(instance)); + } catch (Exception e) { + return error(e.getMessage()); + } + } + + /** + * 新增保存 + */ + @RequiresPermissions("system:probeJobInstance:add") + @Log(title = "add", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(@Validated ProbeJobInstance Instance) { + try { + return toAjax(instanceService.insertInstance(Instance)); + } catch (Exception e) { + e.printStackTrace(); + return error(e.getMessage()); + } + } + + @RequiresPermissions("system:probeJobInstance:detail") + @GetMapping("/detail/{id}") + public String edit(@PathVariable("id") Long id, ModelMap mmap) { + ProbeJobInstanceResult instance = instanceService.selectInstanceById(id); + mmap.put("Instance", instance); + /*boolean numFlag = instance.getPvDiff().equals("0") && instance.getUvDiff().equals("0") ? true : false; + boolean consistencyFlag = instance.getCountDiff().equals(instance.getOriginTableCount()) && instance.getCountDiff().equals(instance.getToTableCount()) ? true : false; + mmap.put("Instance", instance); + mmap.put("numFlag", numFlag); + mmap.put("consistencyFlag", consistencyFlag);*/ + return prefix + "/detail"; + } + +} diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java new file mode 100644 index 0000000..46b6474 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java @@ -0,0 +1,107 @@ +package com.vince.xq.project.system.ProbeJobInstance.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.vince.xq.framework.aspectj.lang.annotation.Excel; + +import java.io.Serializable; +import java.util.Date; + +/** + * 岗位表 sys_post + * + * @author ruoyi + */ +public class ProbeJobInstance implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** id */ + @Excel(name = "id", cellType = Excel.ColumnType.NUMERIC) + private Long id; + + @Excel(name = "jobconfigId") + private Long jobconfigId; + + @Excel(name = "tableName") + private String tableName; + + @Excel(name = "primaryResult") + private String primaryResult; + + @Excel(name = "enumResult") + private String enumResult; + + @Excel(name = "nullResult") + private String nullResult; + + @Excel(name = "filter") + private String filter; + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public Long getJobconfigId() { + return jobconfigId; + } + + public void setJobconfigId(Long jobconfigId) { + this.jobconfigId = jobconfigId; + } + + public String getPrimaryResult() { + return primaryResult; + } + + public void setPrimaryResult(String primaryResult) { + this.primaryResult = primaryResult; + } + + public String getEnumResult() { + return enumResult; + } + + public void setEnumResult(String enumResult) { + this.enumResult = enumResult; + } + + public String getNullResult() { + return nullResult; + } + + public void setNullResult(String nullResult) { + this.nullResult = nullResult; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java new file mode 100644 index 0000000..951cf2f --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java @@ -0,0 +1,178 @@ +package com.vince.xq.project.system.ProbeJobInstance.domain; + +import com.vince.xq.framework.aspectj.lang.annotation.Excel; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; + +public class ProbeJobInstanceResult implements Serializable +{ + private static final long serialVersionUID = 1L; + + @Excel(name = "id", cellType = Excel.ColumnType.NUMERIC) + private Long id; + + @Excel(name = "jobconfigId") + private Long jobconfigId; + + @Excel(name = "tableName") + private String tableName; + + @Excel(name = "primaryResult") + private PrimaryResult primaryResult; + + @Excel(name = "enumResultMap") + private Map> enumResultMap; + + @Excel(name = "nullResultList") + private List nullResultList; + + @Excel(name = "filter") + private String filter; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getJobconfigId() { + return jobconfigId; + } + + public void setJobconfigId(Long jobconfigId) { + this.jobconfigId = jobconfigId; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public PrimaryResult getPrimaryResult() { + return primaryResult; + } + + public void setPrimaryResult(PrimaryResult primaryResult) { + this.primaryResult = primaryResult; + } + + public Map> getEnumResultMap() { + return enumResultMap; + } + + public void setEnumResultMap(Map> enumResultMap) { + this.enumResultMap = enumResultMap; + } + + public List getNullResultList() { + return nullResultList; + } + + public void setNullResultList(List nullResultList) { + this.nullResultList = nullResultList; + } + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } + + public static class NullResult{ + private String nullField; + + private Long totalCnt; + + private Long nullCnt; + + public String getNullField() { + return nullField; + } + + public void setNullField(String nullField) { + this.nullField = nullField; + } + + public Long getTotalCnt() { + return totalCnt; + } + + public void setTotalCnt(Long totalCnt) { + this.totalCnt = totalCnt; + } + + public Long getNullCnt() { + return nullCnt; + } + + public void setNullCnt(Long nullCnt) { + this.nullCnt = nullCnt; + } + } + + public static class EnumResult{ + private String enumValue; + + private Long cnt; + + public String getEnumValue() { + return enumValue; + } + + public void setEnumValue(String enumValue) { + this.enumValue = enumValue; + } + + public Long getCnt() { + return cnt; + } + + public void setCnt(Long cnt) { + this.cnt = cnt; + } + } + + public static class PrimaryResult{ + + private String primaryField; + + private Long cnt; + + private Long distinctCnt; + + public String getPrimaryField() { + return primaryField; + } + + public void setPrimaryField(String primaryField) { + this.primaryField = primaryField; + } + + public Long getCnt() { + return cnt; + } + + public void setCnt(Long cnt) { + this.cnt = cnt; + } + + public Long getDistinctCnt() { + return distinctCnt; + } + + public void setDistinctCnt(Long distinctCnt) { + this.distinctCnt = distinctCnt; + } + } + + +} diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/mapper/ProbeJobInstanceMapper.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/mapper/ProbeJobInstanceMapper.java new file mode 100644 index 0000000..7c1adf0 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/mapper/ProbeJobInstanceMapper.java @@ -0,0 +1,19 @@ +package com.vince.xq.project.system.ProbeJobInstance.mapper; + +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance; + +import java.util.List; + + +public interface ProbeJobInstanceMapper { + + public List selectInstanceList(ProbeJobInstance Instance); + + public List selectInstanceAll(); + + public ProbeJobInstance selectInstanceById(Long id); + + public int insertInstance(ProbeJobInstance Instance); + + public List selectInstancesByUser(String createBy); +} diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/IProbeJobInstanceService.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/IProbeJobInstanceService.java new file mode 100644 index 0000000..c5d7486 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/IProbeJobInstanceService.java @@ -0,0 +1,32 @@ +package com.vince.xq.project.system.ProbeJobInstance.service; + +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstanceResult; + +import java.util.LinkedHashMap; +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author ruoyi + */ +public interface IProbeJobInstanceService { + + public List selectInstanceList(ProbeJobInstance instance); + + public List selectInstanceAll(); + + public ProbeJobInstanceResult selectInstanceById(Long id); + + public List selectDbTypesAll(); + + public int insertInstance(ProbeJobInstance instance); + + public int countUserPostById(Long postId); + + public void runJob(String ids) throws Exception; + + //public List> getDiffDetail(Long id) throws Exception; + +} diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java new file mode 100644 index 0000000..3c1f0e4 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java @@ -0,0 +1,158 @@ +package com.vince.xq.project.system.ProbeJobInstance.service; + +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.vince.xq.common.utils.text.Convert; +import com.vince.xq.project.common.DbTypeEnum; +import com.vince.xq.project.common.RunUtil; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstance; +import com.vince.xq.project.system.ProbeJobInstance.domain.ProbeJobInstanceResult; +import com.vince.xq.project.system.ProbeJobInstance.mapper.ProbeJobInstanceMapper; +import com.vince.xq.project.system.dbconfig.domain.Dbconfig; +import com.vince.xq.project.system.dbconfig.mapper.DbconfigMapper; +import com.vince.xq.project.system.email.service.IEmailService; +import com.vince.xq.project.system.jobconfig.domain.Jobconfig; +import com.vince.xq.project.system.jobconfig.mapper.JobconfigMapper; +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; +import com.vince.xq.project.system.probeJobConfig.mapper.ProbeJobconfigMapper; +import com.vince.xq.project.system.user.domain.User; +import com.vince.xq.project.system.user.mapper.UserMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; + +/** + * 岗位信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class ProbeJobInstanceServiceImpl implements IProbeJobInstanceService { + + @Autowired + private ProbeJobInstanceMapper instanceMapper; + + @Autowired + private DbconfigMapper dbconfigMapper; + + @Autowired + private ProbeJobconfigMapper jobconfigMapper; + + @Autowired + private UserMapper userMapper; + + @Autowired + private IEmailService emailService; + + @Override + public List selectInstanceList(ProbeJobInstance instance) { + return instanceMapper.selectInstanceList(instance); + } + + @Override + public List selectInstanceAll() { + return instanceMapper.selectInstanceAll(); + } + + @Override + public ProbeJobInstanceResult selectInstanceById(Long id) { + ProbeJobInstance probeJobInstance = instanceMapper.selectInstanceById(id); + return extract(probeJobInstance); + } + + private ProbeJobInstanceResult extract(ProbeJobInstance instance) { + ProbeJobInstanceResult probeJobInstanceResult = new ProbeJobInstanceResult(); + probeJobInstanceResult.setId(instance.getId()); + probeJobInstanceResult.setTableName(instance.getTableName()); + probeJobInstanceResult.setFilter(instance.getFilter()); + + JSONObject primaryResultObj = JSONObject.parseObject(instance.getPrimaryResult()); + for (String key : primaryResultObj.keySet()) { + ProbeJobInstanceResult.PrimaryResult primaryResult = new ProbeJobInstanceResult.PrimaryResult(); + primaryResult.setPrimaryField(key); + JSONObject jsonObject = JSONObject.parseObject(primaryResultObj.getString(key)); + primaryResult.setCnt(jsonObject.getLong("cnt")); + primaryResult.setDistinctCnt(jsonObject.getLong("distinct_cnt")); + probeJobInstanceResult.setPrimaryResult(primaryResult); + } + + JSONObject nullResultObj = JSONObject.parseObject(instance.getNullResult()); + List nullResultList = new ArrayList<>(); + for (String key : nullResultObj.keySet()) { + ProbeJobInstanceResult.NullResult nullResult = new ProbeJobInstanceResult.NullResult(); + nullResult.setNullField(key); + JSONArray jsonArray = JSONObject.parseArray(nullResultObj.getString(key)); + long totalCnt = 0; + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); + if (jsonObject.getString("dict").equals("0")) { + nullResult.setNullCnt(jsonObject.getLong("cnt")); + } + totalCnt += jsonObject.getLong("cnt"); + } + nullResult.setTotalCnt(totalCnt); + nullResultList.add(nullResult); + } + probeJobInstanceResult.setNullResultList(nullResultList); + + JSONObject enumObj = JSONObject.parseObject(instance.getEnumResult()); + Map> enumResultMap = new HashMap<>(); + for (String key : enumObj.keySet()) { + JSONArray jsonArray = JSONObject.parseArray(enumObj.getString(key)); + List list = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); + ProbeJobInstanceResult.EnumResult enumResult = new ProbeJobInstanceResult.EnumResult(); + enumResult.setEnumValue(jsonObject.getString("dict")); + enumResult.setCnt(jsonObject.getLong("cnt")); + list.add(enumResult); + } + enumResultMap.put(key, list); + } + probeJobInstanceResult.setEnumResultMap(enumResultMap); + return probeJobInstanceResult; + } + + @Override + public List selectDbTypesAll() { + List list = new ArrayList<>(); + for (DbTypeEnum dbTypeEnum : DbTypeEnum.values()) { + list.add(dbTypeEnum.getType()); + } + return list; + } + + + @Override + public int insertInstance(ProbeJobInstance instance) { + return instanceMapper.insertInstance(instance); + } + + + @Override + public int countUserPostById(Long postId) { + return 0; + } + + @Override + public void runJob(String ids) throws Exception { + Long[] idsArray = Convert.toLongArray(ids); + for (Long id : idsArray) { + Probejobconfig jobconfig = jobconfigMapper.selectJobconfigById(id); + Dbconfig dbconfig = dbconfigMapper.selectDbconfigById(jobconfig.getDbConfigId()); + ProbeJobInstance instance = RunUtil.runProbeJob(dbconfig, jobconfig); + instance.setJobconfigId(id); + instanceMapper.insertInstance(instance); + } + } + + /*@Override + public List> getDiffDetail(Long id) throws Exception { + ProbeJobInstance instance = instanceMapper.selectInstanceById(id); + Probejobconfig jobconfig = jobconfigMapper.selectJobconfigById(instance.getJobconfigId()); + Dbconfig dbconfig = dbconfigMapper.selectDbconfigById(jobconfig.getDbConfigId()); + List> list = RunUtil.runDiffDetail(dbconfig, jobconfig); + return list; + }*/ +} diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/controller/ProbeJobConfigController.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/controller/ProbeJobConfigController.java new file mode 100644 index 0000000..78e0ad6 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/controller/ProbeJobConfigController.java @@ -0,0 +1,147 @@ +package com.vince.xq.project.system.probeJobConfig.controller; + +import com.vince.xq.framework.aspectj.lang.annotation.Log; +import com.vince.xq.framework.aspectj.lang.enums.BusinessType; +import com.vince.xq.framework.web.controller.BaseController; +import com.vince.xq.framework.web.domain.AjaxResult; +import com.vince.xq.framework.web.page.TableDataInfo; +import com.vince.xq.project.monitor.job.util.CronUtils; +import com.vince.xq.project.system.ProbeJobInstance.service.IProbeJobInstanceService; +import com.vince.xq.project.system.dbconfig.service.IDbconfigService; +import com.vince.xq.project.system.instance.service.IInstanceService; +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; +import com.vince.xq.project.system.probeJobConfig.service.IProbeJobconfigService; +import org.apache.shiro.authz.annotation.RequiresPermissions; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 岗位信息操作处理 + * + * @author ruoyi + */ +@Controller +@RequestMapping("/system/probeJobConfig") +public class ProbeJobConfigController extends BaseController { + private static final Logger log = LoggerFactory.getLogger(ProbeJobConfigController.class); + + private String prefix = "system/probeJobConfig"; + + @Autowired + private IProbeJobconfigService probeJobconfigService; + + @Autowired + private IDbconfigService dbconfigService; + + @Autowired + private IProbeJobInstanceService instanceService; + + @RequiresPermissions("system:probeJobConfig:view") + @GetMapping() + public String operlog() { + return prefix + "/probeJobConfig"; + } + + @RequiresPermissions("system:probeJobConfig:list") + @PostMapping("/list") + @ResponseBody + public TableDataInfo list(Probejobconfig jobconfig) { + startPage(); + List list = probeJobconfigService.selectJobconfigList(jobconfig); + return getDataTable(list); + } + + @RequiresPermissions("system:probeJobConfig:remove") + @Log(title = "job管理", businessType = BusinessType.DELETE) + @PostMapping("/remove") + @ResponseBody + public AjaxResult remove(String ids) { + try { + return toAjax(probeJobconfigService.deleteJobconfigByIds(ids)); + } catch (Exception e) { + return error(e.getMessage()); + } + } + + @RequiresPermissions("system:probeJobConfig:run") + @Log(title = "job管理", businessType = BusinessType.RUN) + @PostMapping("/run") + @ResponseBody + public AjaxResult run(String ids) { + try { + instanceService.runJob(ids); + return success(); + } catch (Exception e) { + return error(e.getMessage()); + } + } + + /** + * 新增 + */ + @GetMapping("/add") + public String add(ModelMap mmap) { + mmap.put("dbConfigList", dbconfigService.selectDbconfigAll()); + return prefix + "/add"; + } + + /** + * 新增保存 + */ + @RequiresPermissions("system:probeJobConfig:add") + @Log(title = "add", businessType = BusinessType.INSERT) + @PostMapping("/add") + @ResponseBody + public AjaxResult addSave(@Validated Probejobconfig jobconfig) { + try { + /*if (jobconfig.getSchduleStatus().equals("0")) {//定时调度 + if (!CronUtils.isValid(jobconfig.getSchduleTime())) { + return error("新增任务失败,Cron表达式不正确"); + } + }*/ + probeJobconfigService.insertJobconfig(jobconfig); + return success(); + } catch (Exception e) { + e.printStackTrace(); + return error(e.getMessage()); + } + } + + /*@RequiresPermissions("system:probeJobConfig:edit") + @GetMapping("/edit/{id}") + public String edit(@PathVariable("id") Long id, ModelMap mmap) { + Probejobconfig jobconfig = probeJobconfigService.selectJobconfigById(id); + mmap.put("jobconfig", jobconfig); + return prefix + "/edit"; + }*/ + + + /*@RequiresPermissions("system:probeJobConfig:edit") + @Log(title = "job管理", businessType = BusinessType.UPDATE) + @PostMapping("/edit") + @ResponseBody + public AjaxResult editSave(@Validated Probejobconfig jobconfig) { + return toAjax(probeJobconfigService.updateJobconfig(jobconfig)); + }*/ + + /*@RequestMapping(value = "/checkTableName", method = RequestMethod.POST) + @ResponseBody + public AjaxResult checkTableName(Probejobconfig jobconfig) { + try { + log.info("========checkTableName=========="); + jobconfigService.checkTableName(jobconfig); + } catch (Exception e) { + e.printStackTrace(); + return error("错误信息:" + e.getMessage()); + } + return success("表和字段校验成功"); + }*/ + +} diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java new file mode 100644 index 0000000..9b4fc23 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java @@ -0,0 +1,119 @@ +package com.vince.xq.project.system.probeJobConfig.domain; + +import com.fasterxml.jackson.annotation.JsonFormat; +import com.vince.xq.framework.aspectj.lang.annotation.Excel; + +import java.io.Serializable; +import java.util.Date; + +/** + * 岗位表 sys_post + * + * @author ruoyi + */ +public class Probejobconfig implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** id */ + @Excel(name = "id", cellType = Excel.ColumnType.NUMERIC) + private Long id; + + @Excel(name = "tableName") + private String tableName; + + @Excel(name = "tablePrimary") + private String tablePrimary; + + @Excel(name = "tableEnumFields") + private String tableEnumFields; + + @Excel(name = "tableNullFields") + private String tableNullFields; + + /** createBy */ + @Excel(name = "createBy") + private String createBy; + + @Excel(name = "filter") + private String filter; + + /** 创建时间 */ + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private Date createTime; + + @Excel(name = "dbConfigId") + private Long dbConfigId; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getFilter() { + return filter; + } + + public void setFilter(String filter) { + this.filter = filter; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getTablePrimary() { + return tablePrimary; + } + + public void setTablePrimary(String tablePrimary) { + this.tablePrimary = tablePrimary; + } + + public String getTableEnumFields() { + return tableEnumFields; + } + + public void setTableEnumFields(String tableEnumFields) { + this.tableEnumFields = tableEnumFields; + } + + public String getTableNullFields() { + return tableNullFields; + } + + public void setTableNullFields(String tableNullFields) { + this.tableNullFields = tableNullFields; + } + + public String getCreateBy() { + return createBy; + } + + public void setCreateBy(String createBy) { + this.createBy = createBy; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Long getDbConfigId() { + return dbConfigId; + } + + public void setDbConfigId(Long dbConfigId) { + this.dbConfigId = dbConfigId; + } +} diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/mapper/ProbeJobconfigMapper.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/mapper/ProbeJobconfigMapper.java new file mode 100644 index 0000000..b856245 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/mapper/ProbeJobconfigMapper.java @@ -0,0 +1,25 @@ +package com.vince.xq.project.system.probeJobConfig.mapper; + +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; + +import java.util.List; + + +public interface ProbeJobconfigMapper +{ + + public List selectJobconfigList(Probejobconfig dbconfig); + + public List selectJobconfigAll(); + + public Probejobconfig selectJobconfigById(Long id); + + public int deleteJobconfigByIds(Long[] ids); + + //public int updateJobconfig(Probejobconfig dbconfig); + + public int insertJobconfig(Probejobconfig dbconfig); + + + public List selectJobconfigsByUser(String createBy); +} diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/service/IProbeJobconfigService.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/service/IProbeJobconfigService.java new file mode 100644 index 0000000..f903b9e --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/service/IProbeJobconfigService.java @@ -0,0 +1,36 @@ +package com.vince.xq.project.system.probeJobConfig.service; + +import com.vince.xq.common.exception.job.TaskException; +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; +import org.quartz.SchedulerException; + +import java.util.List; + +/** + * 岗位信息 服务层 + * + * @author ruoyi + */ +public interface IProbeJobconfigService +{ + public List selectJobconfigList(Probejobconfig dbconfig); + + public List selectJobconfigAll(); + + /*public List selectJobconfigsByUserId(Long userId);*/ + + public Probejobconfig selectJobconfigById(Long id); + + public List selectDbTypesAll(); + + public int deleteJobconfigByIds(String ids); + + public void insertJobconfig(Probejobconfig dbconfig) throws TaskException, SchedulerException; + + public int updateJobconfig(Probejobconfig dbconfig); + + public int countUserPostById(Long postId); + + public void checkTableName(Probejobconfig jobconfig) throws Exception; + +} diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/service/ProbeJobconfigServiceImpl.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/service/ProbeJobconfigServiceImpl.java new file mode 100644 index 0000000..43b8472 --- /dev/null +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/service/ProbeJobconfigServiceImpl.java @@ -0,0 +1,141 @@ +package com.vince.xq.project.system.probeJobConfig.service; + +import com.vince.xq.common.constant.Constants; +import com.vince.xq.common.exception.job.TaskException; +import com.vince.xq.common.utils.security.ShiroUtils; +import com.vince.xq.common.utils.text.Convert; +import com.vince.xq.project.common.DbTypeEnum; +import com.vince.xq.project.monitor.job.mapper.JobMapper; +import com.vince.xq.project.monitor.job.util.ScheduleUtils; +import com.vince.xq.project.system.dbconfig.domain.Dbconfig; +import com.vince.xq.project.system.dbconfig.mapper.DbconfigMapper; +import com.vince.xq.project.system.probeJobConfig.domain.Probejobconfig; +import com.vince.xq.project.system.probeJobConfig.mapper.ProbeJobconfigMapper; +import com.vince.xq.project.system.probeJobConfig.mapper.ProbeJobconfigMapper; +import org.quartz.Scheduler; +import org.quartz.SchedulerException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; + +/** + * 岗位信息 服务层处理 + * + * @author ruoyi + */ +@Service +public class ProbeJobconfigServiceImpl implements IProbeJobconfigService { + + @Autowired + private ProbeJobconfigMapper probeJobconfigMapper; + + @Autowired + private DbconfigMapper dbconfigMapper; + + @Autowired + private JobMapper jobMapper; + + @Autowired + private Scheduler scheduler; + + @PostConstruct + public void init() throws SchedulerException, TaskException { + /*scheduler.clear(); + List jobList = probeJobconfigMapper.selectJobconfigAll(); + for (Probejobconfig job : jobList) { + if (job.getSchduleStatus().equals("0")) { + ScheduleUtils.createScheduleJob(scheduler, job); + } + }*/ + } + + @Override + public List selectJobconfigList(Probejobconfig dbconfig) { + return probeJobconfigMapper.selectJobconfigList(dbconfig); + } + + @Override + public List selectJobconfigAll() { + return probeJobconfigMapper.selectJobconfigAll(); + } + + /*@Override + public List selectJobconfigsByUserId(Long userId) + { + List userJobconfigs = probeJobconfigMapper.selectJobconfigsByUserId(userId); + List dbconfigs = probeJobconfigMapper.selectJobconfigAll(); + for (Jobconfig dbconfig : dbconfigs) + { + for (Jobconfig userJobconfig : userJobconfigs) + { + if (dbconfig.getId().longValue() == userJobconfig.getId().longValue()) + { + dbconfig.setFlag(true); + break; + } + } + } + return dbconfigs; + }*/ + + + @Override + public Probejobconfig selectJobconfigById(Long id) { + return probeJobconfigMapper.selectJobconfigById(id); + } + + @Override + public List selectDbTypesAll() { + List list = new ArrayList<>(); + for (DbTypeEnum dbTypeEnum : DbTypeEnum.values()) { + list.add(dbTypeEnum.getType()); + } + return list; + } + + @Override + public int deleteJobconfigByIds(String ids) { + Long[] idsArray = Convert.toLongArray(ids); + /*for (Long id : idsArray) + { + Jobconfig dbconfig = selectJobconfigById(id); + if (countUserPostById(dbconfig) > 0) + { + throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName())); + } + }*/ + return probeJobconfigMapper.deleteJobconfigByIds(idsArray); + } + + + @Override + public void insertJobconfig(Probejobconfig jobconfig) throws TaskException, SchedulerException { + jobconfig.setCreateBy(ShiroUtils.getLoginName()); + int rows = probeJobconfigMapper.insertJobconfig(jobconfig); + /*if (rows > 0 && jobconfig.getSchduleStatus().equals("0")) { + ScheduleUtils.createScheduleJob(scheduler, jobconfig); + }*/ + } + + @Override + public int updateJobconfig(Probejobconfig dbconfig) { + /*dbconfig.setCreateBy(ShiroUtils.getLoginName()); + return probeJobconfigMapper.updateJobconfig(dbconfig);*/ + return 0; + } + + @Override + public int countUserPostById(Long postId) { + return 0; + } + + @Override + public void checkTableName(Probejobconfig jobconfig) throws Exception { + Dbconfig dbconfig = dbconfigMapper.selectDbconfigById(jobconfig.getDbConfigId()); + //checkTableNameSql(dbconfig, DbTypeEnum.findEnumByType(dbconfig.getType()).getConnectDriver(), jobconfig); + } +} diff --git a/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml b/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml new file mode 100644 index 0000000..d987429 --- /dev/null +++ b/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + select a.id, + a.job_config_id, + a.primary_result, + a.enum_result, + a.null_result, + a.create_time, + b.`table_name`, + b.filter + from probe_job_instance a + join probe_job_config b on a.job_config_id = b.id + + + + + + + + + + delete from probe_job_instance where id in + + #{id} + + + + + insert into probe_job_instance( + job_config_id, + primary_result, + enum_result, + null_result, + create_time + )values( + #{jobconfigId}, + #{primaryResult}, + #{enumResult}, + #{nullResult}, + sysdate() + ) + + + + + \ No newline at end of file diff --git a/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml b/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml new file mode 100644 index 0000000..3766fc1 --- /dev/null +++ b/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml @@ -0,0 +1,79 @@ + + + + + + + + + + + + + + + + + + select id, `table_name`,table_primary, table_enum_fields, table_null_fields,db_config_id,filter, + create_by, create_time + from probe_job_config + + + + + + + + + + delete from probe_job_config where id in + + #{id} + + + + + insert into probe_job_config( + `table_name`, + table_primary, + table_enum_fields, + table_null_fields, + + db_config_id, + filter, + create_by, + create_time + )values( + #{tableName}, + #{tablePrimary}, + #{tableEnumFields}, + #{tableNullFields}, + #{dbConfigId}, + #{filter}, + #{createBy}, + sysdate() + ) + + + + + \ No newline at end of file diff --git a/src/main/resources/templates/system/probeJobConfig/add.html b/src/main/resources/templates/system/probeJobConfig/add.html new file mode 100644 index 0000000..4aaadc0 --- /dev/null +++ b/src/main/resources/templates/system/probeJobConfig/add.html @@ -0,0 +1,108 @@ + + + + + + + +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + diff --git a/src/main/resources/templates/system/probeJobConfig/edit.html b/src/main/resources/templates/system/probeJobConfig/edit.html new file mode 100644 index 0000000..1050abc --- /dev/null +++ b/src/main/resources/templates/system/probeJobConfig/edit.html @@ -0,0 +1,86 @@ + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ + + + diff --git a/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html b/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html new file mode 100644 index 0000000..b917d2d --- /dev/null +++ b/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html @@ -0,0 +1,111 @@ + + + + + + +
+
+
+
+
+ +
+
+
+ + + +
+
+
+
+
+ + + + \ No newline at end of file diff --git a/src/main/resources/templates/system/probeJobInstance/add.html b/src/main/resources/templates/system/probeJobInstance/add.html new file mode 100644 index 0000000..4aaadc0 --- /dev/null +++ b/src/main/resources/templates/system/probeJobInstance/add.html @@ -0,0 +1,108 @@ + + + + + + + +
+
+ +
+ +
+ +
+
+ +
+ +
+
+ +
+
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+ + + + + + diff --git a/src/main/resources/templates/system/probeJobInstance/detail.html b/src/main/resources/templates/system/probeJobInstance/detail.html new file mode 100644 index 0000000..cff8c84 --- /dev/null +++ b/src/main/resources/templates/system/probeJobInstance/detail.html @@ -0,0 +1,137 @@ + + + + + + +
+ +
+ + +
+ +
+
+ +
+ + + + + + + + + + + + + + +
表名
过滤条件
+ +
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + +
主键
总行数
主键去重总行数
+ +
+ +
+ +
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
字段名
空值行数
总行数
空值占比
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+
+ + + + + + + + + + + + + + + +
enum_value
num
+ +
+ + +
+ +
+
+ + + + diff --git a/src/main/resources/templates/system/probeJobInstance/edit.html b/src/main/resources/templates/system/probeJobInstance/edit.html new file mode 100644 index 0000000..1050abc --- /dev/null +++ b/src/main/resources/templates/system/probeJobInstance/edit.html @@ -0,0 +1,86 @@ + + + + + + +
+
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+
+
+ + + + diff --git a/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html b/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html new file mode 100644 index 0000000..6e88348 --- /dev/null +++ b/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html @@ -0,0 +1,92 @@ + + + + + + +
+
+
+
+
+ +
+
+
+ +
+
+
+
+
+ + + + \ No newline at end of file From d59b40e8cb66bd78e2378d978431d2a4b8cd2300 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Fri, 17 Mar 2023 17:58:25 +0800 Subject: [PATCH 09/26] feat:ui style --- src/main/resources/templates/system/jobconfig/add.html | 8 +++----- .../resources/templates/system/probeJobConfig/add.html | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/resources/templates/system/jobconfig/add.html b/src/main/resources/templates/system/jobconfig/add.html index 6e61d79..b469c7c 100644 --- a/src/main/resources/templates/system/jobconfig/add.html +++ b/src/main/resources/templates/system/jobconfig/add.html @@ -23,10 +23,8 @@
-
- -
+
@@ -138,7 +136,7 @@ var field = $("#schduleStatus").val(); if (field == 0) { $("#cronDiv").css("display", "block"); - }else { + } else { $("#cronDiv").css("display", "none"); } } diff --git a/src/main/resources/templates/system/probeJobConfig/add.html b/src/main/resources/templates/system/probeJobConfig/add.html index 4aaadc0..32da64c 100644 --- a/src/main/resources/templates/system/probeJobConfig/add.html +++ b/src/main/resources/templates/system/probeJobConfig/add.html @@ -22,10 +22,8 @@
-
- -
+
From d71127d3ad6bdedd4f35988f7e15548556f3dd6a Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Fri, 17 Mar 2023 18:18:36 +0800 Subject: [PATCH 10/26] feat:profiling sql --- sql/dataCompare.sql | 302 ++++++++------------------------------------ 1 file changed, 55 insertions(+), 247 deletions(-) diff --git a/sql/dataCompare.sql b/sql/dataCompare.sql index 907ebd8..bc53752 100644 --- a/sql/dataCompare.sql +++ b/sql/dataCompare.sql @@ -1,3 +1,4 @@ + SET FOREIGN_KEY_CHECKS=0; -- ---------------------------- @@ -14,7 +15,7 @@ CREATE TABLE `db_config` ( `create_time` datetime DEFAULT NULL COMMENT 'create_time', `create_by` varchar(255) DEFAULT NULL COMMENT 'create_by', PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='db config'; +) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8 COMMENT='db config'; -- ---------------------------- -- Table structure for gen_table @@ -104,7 +105,7 @@ CREATE TABLE `job_config` ( `origin_table_group` text, `to_table_group` text, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8 COMMENT='job_config'; +) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8 COMMENT='job_config'; -- ---------------------------- -- Table structure for job_instance @@ -127,7 +128,42 @@ CREATE TABLE `job_instance` ( `dt` varchar(255) DEFAULT NULL COMMENT 'dt', `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8 COMMENT='job_instance'; +) ENGINE=InnoDB AUTO_INCREMENT=7259 DEFAULT CHARSET=utf8 COMMENT='job_instance'; + +-- ---------------------------- +-- Records of job_instance +-- ---------------------------- + +-- ---------------------------- +-- Table structure for probe_job_config +-- ---------------------------- +DROP TABLE IF EXISTS `probe_job_config`; +CREATE TABLE `probe_job_config` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `table_name` varchar(255) NOT NULL, + `table_primary` varchar(255) DEFAULT NULL, + `table_enum_fields` varchar(255) NOT NULL COMMENT 'table_enum_fields', + `table_null_fields` varchar(255) NOT NULL COMMENT 'table_null_fields', + `filter` varchar(255) DEFAULT NULL COMMENT 'filter', + `db_config_id` int(11) DEFAULT NULL, + `create_time` datetime DEFAULT NULL, + `create_by` varchar(255) DEFAULT NULL COMMENT 'create_by', + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COMMENT='probe_job_config'; + +-- ---------------------------- +-- Table structure for probe_job_instance +-- ---------------------------- +DROP TABLE IF EXISTS `probe_job_instance`; +CREATE TABLE `probe_job_instance` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `job_config_id` int(11) NOT NULL, + `primary_result` text COMMENT 'primary_result', + `enum_result` text COMMENT 'enum_result', + `null_result` text COMMENT 'null_result', + `create_time` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='probe_job_instance'; -- ---------------------------- -- Table structure for QRTZ_BLOB_TRIGGERS @@ -525,7 +561,7 @@ CREATE TABLE `sys_job` ( -- ---------------------------- -- Records of sys_job -- ---------------------------- -INSERT INTO `sys_job` VALUES ('1', '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2022-11-25 05:04:10', '', null, ''); +INSERT INTO `sys_job` VALUES ('1', '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '0/10 * * * * ?', '3', '1', '1', 'admin', '2022-11-25 05:04:10', '', '2022-12-21 07:34:33', ''); INSERT INTO `sys_job` VALUES ('2', '系统默认(有参)', 'DEFAULT', 'ryTask.ryParams(\'ry\')', '0/15 * * * * ?', '3', '1', '1', 'admin', '2022-11-25 05:04:10', '', null, ''); INSERT INTO `sys_job` VALUES ('3', '系统默认(多参)', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)', '0/20 * * * * ?', '3', '1', '1', 'admin', '2022-11-25 05:04:10', '', null, ''); @@ -543,12 +579,7 @@ CREATE TABLE `sys_job_log` ( `exception_info` varchar(2000) DEFAULT '' COMMENT '异常信息', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`job_log_id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='定时任务调度日志表'; - --- ---------------------------- --- Records of sys_job_log --- ---------------------------- -INSERT INTO `sys_job_log` VALUES ('1', '系统默认(无参)', 'DEFAULT', 'ryTask.ryNoParams', '系统默认(无参) 总共耗时:2毫秒', '0', '', '2022-11-25 05:08:23'); +) ENGINE=InnoDB AUTO_INCREMENT=209 DEFAULT CHARSET=utf8 COMMENT='定时任务调度日志表'; -- ---------------------------- -- Table structure for sys_logininfor @@ -565,234 +596,7 @@ CREATE TABLE `sys_logininfor` ( `msg` varchar(255) DEFAULT '' COMMENT '提示消息', `login_time` datetime DEFAULT NULL COMMENT '访问时间', PRIMARY KEY (`info_id`) -) ENGINE=InnoDB AUTO_INCREMENT=323 DEFAULT CHARSET=utf8 COMMENT='系统访问记录'; - --- ---------------------------- --- Records of sys_logininfor --- ---------------------------- -INSERT INTO `sys_logininfor` VALUES ('100', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '1', '验证码错误', '2022-11-25 05:07:29'); -INSERT INTO `sys_logininfor` VALUES ('101', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 05:07:53'); -INSERT INTO `sys_logininfor` VALUES ('102', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '退出成功', '2022-11-25 05:09:43'); -INSERT INTO `sys_logininfor` VALUES ('103', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 05:21:10'); -INSERT INTO `sys_logininfor` VALUES ('104', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '退出成功', '2022-11-25 05:23:15'); -INSERT INTO `sys_logininfor` VALUES ('105', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '1', '验证码错误', '2022-11-25 06:16:31'); -INSERT INTO `sys_logininfor` VALUES ('106', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 06:16:40'); -INSERT INTO `sys_logininfor` VALUES ('107', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 06:39:08'); -INSERT INTO `sys_logininfor` VALUES ('108', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 06:44:23'); -INSERT INTO `sys_logininfor` VALUES ('109', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 06:51:09'); -INSERT INTO `sys_logininfor` VALUES ('110', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-25 10:12:07'); -INSERT INTO `sys_logininfor` VALUES ('111', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 04:53:02'); -INSERT INTO `sys_logininfor` VALUES ('112', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 05:00:47'); -INSERT INTO `sys_logininfor` VALUES ('113', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 05:06:27'); -INSERT INTO `sys_logininfor` VALUES ('114', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 05:16:46'); -INSERT INTO `sys_logininfor` VALUES ('115', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 06:17:17'); -INSERT INTO `sys_logininfor` VALUES ('116', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 06:27:33'); -INSERT INTO `sys_logininfor` VALUES ('117', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 06:34:26'); -INSERT INTO `sys_logininfor` VALUES ('118', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 09:53:04'); -INSERT INTO `sys_logininfor` VALUES ('119', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 10:02:49'); -INSERT INTO `sys_logininfor` VALUES ('120', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 10:04:39'); -INSERT INTO `sys_logininfor` VALUES ('121', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 10:11:37'); -INSERT INTO `sys_logininfor` VALUES ('122', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 12:40:46'); -INSERT INTO `sys_logininfor` VALUES ('123', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-29 13:22:58'); -INSERT INTO `sys_logininfor` VALUES ('124', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:01:21'); -INSERT INTO `sys_logininfor` VALUES ('125', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:09:58'); -INSERT INTO `sys_logininfor` VALUES ('126', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:11:41'); -INSERT INTO `sys_logininfor` VALUES ('127', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:24:33'); -INSERT INTO `sys_logininfor` VALUES ('128', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:31:40'); -INSERT INTO `sys_logininfor` VALUES ('129', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:33:32'); -INSERT INTO `sys_logininfor` VALUES ('130', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:36:10'); -INSERT INTO `sys_logininfor` VALUES ('131', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 02:45:14'); -INSERT INTO `sys_logininfor` VALUES ('132', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 03:11:08'); -INSERT INTO `sys_logininfor` VALUES ('133', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 03:14:02'); -INSERT INTO `sys_logininfor` VALUES ('134', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 03:15:53'); -INSERT INTO `sys_logininfor` VALUES ('135', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 03:18:22'); -INSERT INTO `sys_logininfor` VALUES ('136', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 04:51:34'); -INSERT INTO `sys_logininfor` VALUES ('137', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 04:54:36'); -INSERT INTO `sys_logininfor` VALUES ('138', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 04:56:21'); -INSERT INTO `sys_logininfor` VALUES ('139', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 06:05:30'); -INSERT INTO `sys_logininfor` VALUES ('140', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 06:19:22'); -INSERT INTO `sys_logininfor` VALUES ('141', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 06:28:48'); -INSERT INTO `sys_logininfor` VALUES ('142', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 06:32:54'); -INSERT INTO `sys_logininfor` VALUES ('143', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 06:47:23'); -INSERT INTO `sys_logininfor` VALUES ('144', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 07:06:37'); -INSERT INTO `sys_logininfor` VALUES ('145', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 07:12:55'); -INSERT INTO `sys_logininfor` VALUES ('146', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:35:33'); -INSERT INTO `sys_logininfor` VALUES ('147', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:37:34'); -INSERT INTO `sys_logininfor` VALUES ('148', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:40:20'); -INSERT INTO `sys_logininfor` VALUES ('149', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:46:36'); -INSERT INTO `sys_logininfor` VALUES ('150', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:49:03'); -INSERT INTO `sys_logininfor` VALUES ('151', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:50:17'); -INSERT INTO `sys_logininfor` VALUES ('152', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:51:39'); -INSERT INTO `sys_logininfor` VALUES ('153', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-11-30 09:53:03'); -INSERT INTO `sys_logininfor` VALUES ('154', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 03:23:46'); -INSERT INTO `sys_logininfor` VALUES ('155', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 03:26:48'); -INSERT INTO `sys_logininfor` VALUES ('156', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 03:31:48'); -INSERT INTO `sys_logininfor` VALUES ('157', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 03:36:19'); -INSERT INTO `sys_logininfor` VALUES ('158', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 03:58:22'); -INSERT INTO `sys_logininfor` VALUES ('159', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 04:04:17'); -INSERT INTO `sys_logininfor` VALUES ('160', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 04:10:04'); -INSERT INTO `sys_logininfor` VALUES ('161', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 05:19:26'); -INSERT INTO `sys_logininfor` VALUES ('162', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 05:59:14'); -INSERT INTO `sys_logininfor` VALUES ('163', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 06:11:17'); -INSERT INTO `sys_logininfor` VALUES ('164', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 06:19:43'); -INSERT INTO `sys_logininfor` VALUES ('165', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-01 06:54:55'); -INSERT INTO `sys_logininfor` VALUES ('166', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:24:29'); -INSERT INTO `sys_logininfor` VALUES ('167', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:30:22'); -INSERT INTO `sys_logininfor` VALUES ('168', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:33:52'); -INSERT INTO `sys_logininfor` VALUES ('169', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:35:17'); -INSERT INTO `sys_logininfor` VALUES ('170', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:37:30'); -INSERT INTO `sys_logininfor` VALUES ('171', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:42:16'); -INSERT INTO `sys_logininfor` VALUES ('172', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:45:08'); -INSERT INTO `sys_logininfor` VALUES ('173', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:48:42'); -INSERT INTO `sys_logininfor` VALUES ('174', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:53:27'); -INSERT INTO `sys_logininfor` VALUES ('175', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:56:07'); -INSERT INTO `sys_logininfor` VALUES ('176', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 11:58:48'); -INSERT INTO `sys_logininfor` VALUES ('177', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 12:03:20'); -INSERT INTO `sys_logininfor` VALUES ('178', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 12:09:24'); -INSERT INTO `sys_logininfor` VALUES ('179', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 12:14:59'); -INSERT INTO `sys_logininfor` VALUES ('180', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 12:16:20'); -INSERT INTO `sys_logininfor` VALUES ('181', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-04 12:17:33'); -INSERT INTO `sys_logininfor` VALUES ('182', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-05 08:53:20'); -INSERT INTO `sys_logininfor` VALUES ('183', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-05 09:17:13'); -INSERT INTO `sys_logininfor` VALUES ('184', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-05 10:07:45'); -INSERT INTO `sys_logininfor` VALUES ('185', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-05 10:11:09'); -INSERT INTO `sys_logininfor` VALUES ('186', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-05 10:12:48'); -INSERT INTO `sys_logininfor` VALUES ('187', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:43:51'); -INSERT INTO `sys_logininfor` VALUES ('188', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:45:54'); -INSERT INTO `sys_logininfor` VALUES ('189', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:49:33'); -INSERT INTO `sys_logininfor` VALUES ('190', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:50:55'); -INSERT INTO `sys_logininfor` VALUES ('191', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:52:21'); -INSERT INTO `sys_logininfor` VALUES ('192', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:53:36'); -INSERT INTO `sys_logininfor` VALUES ('193', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-06 12:56:03'); -INSERT INTO `sys_logininfor` VALUES ('194', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-08 06:56:20'); -INSERT INTO `sys_logininfor` VALUES ('195', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-08 06:58:10'); -INSERT INTO `sys_logininfor` VALUES ('196', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 02:59:48'); -INSERT INTO `sys_logininfor` VALUES ('197', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 03:40:39'); -INSERT INTO `sys_logininfor` VALUES ('198', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 03:46:00'); -INSERT INTO `sys_logininfor` VALUES ('199', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 03:47:24'); -INSERT INTO `sys_logininfor` VALUES ('200', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 03:49:38'); -INSERT INTO `sys_logininfor` VALUES ('201', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:19:20'); -INSERT INTO `sys_logininfor` VALUES ('202', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:25:09'); -INSERT INTO `sys_logininfor` VALUES ('203', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:28:03'); -INSERT INTO `sys_logininfor` VALUES ('204', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:33:10'); -INSERT INTO `sys_logininfor` VALUES ('205', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:37:05'); -INSERT INTO `sys_logininfor` VALUES ('206', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:46:47'); -INSERT INTO `sys_logininfor` VALUES ('207', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 08:58:01'); -INSERT INTO `sys_logininfor` VALUES ('208', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:00:10'); -INSERT INTO `sys_logininfor` VALUES ('209', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:02:04'); -INSERT INTO `sys_logininfor` VALUES ('210', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:04:06'); -INSERT INTO `sys_logininfor` VALUES ('211', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:06:50'); -INSERT INTO `sys_logininfor` VALUES ('212', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:10:20'); -INSERT INTO `sys_logininfor` VALUES ('213', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:14:51'); -INSERT INTO `sys_logininfor` VALUES ('214', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:17:37'); -INSERT INTO `sys_logininfor` VALUES ('215', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:21:24'); -INSERT INTO `sys_logininfor` VALUES ('216', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:24:15'); -INSERT INTO `sys_logininfor` VALUES ('217', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 09:52:10'); -INSERT INTO `sys_logininfor` VALUES ('218', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 10:01:08'); -INSERT INTO `sys_logininfor` VALUES ('219', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 10:04:19'); -INSERT INTO `sys_logininfor` VALUES ('220', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-12 10:06:12'); -INSERT INTO `sys_logininfor` VALUES ('221', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 01:58:49'); -INSERT INTO `sys_logininfor` VALUES ('222', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:17:34'); -INSERT INTO `sys_logininfor` VALUES ('223', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:35:23'); -INSERT INTO `sys_logininfor` VALUES ('224', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:40:58'); -INSERT INTO `sys_logininfor` VALUES ('225', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:43:12'); -INSERT INTO `sys_logininfor` VALUES ('226', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:46:46'); -INSERT INTO `sys_logininfor` VALUES ('227', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:53:09'); -INSERT INTO `sys_logininfor` VALUES ('228', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 03:55:33'); -INSERT INTO `sys_logininfor` VALUES ('229', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 04:01:44'); -INSERT INTO `sys_logininfor` VALUES ('230', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 04:56:07'); -INSERT INTO `sys_logininfor` VALUES ('231', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:09:20'); -INSERT INTO `sys_logininfor` VALUES ('232', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:11:51'); -INSERT INTO `sys_logininfor` VALUES ('233', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:13:11'); -INSERT INTO `sys_logininfor` VALUES ('234', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:18:22'); -INSERT INTO `sys_logininfor` VALUES ('235', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:20:54'); -INSERT INTO `sys_logininfor` VALUES ('236', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:23:54'); -INSERT INTO `sys_logininfor` VALUES ('237', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 05:29:19'); -INSERT INTO `sys_logininfor` VALUES ('238', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:00:57'); -INSERT INTO `sys_logininfor` VALUES ('239', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:04:07'); -INSERT INTO `sys_logininfor` VALUES ('240', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:06:25'); -INSERT INTO `sys_logininfor` VALUES ('241', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:08:09'); -INSERT INTO `sys_logininfor` VALUES ('242', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:13:22'); -INSERT INTO `sys_logininfor` VALUES ('243', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:14:52'); -INSERT INTO `sys_logininfor` VALUES ('244', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:20:01'); -INSERT INTO `sys_logininfor` VALUES ('245', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:21:42'); -INSERT INTO `sys_logininfor` VALUES ('246', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:24:11'); -INSERT INTO `sys_logininfor` VALUES ('247', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:39:42'); -INSERT INTO `sys_logininfor` VALUES ('248', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:48:33'); -INSERT INTO `sys_logininfor` VALUES ('249', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 06:52:56'); -INSERT INTO `sys_logininfor` VALUES ('250', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 07:49:11'); -INSERT INTO `sys_logininfor` VALUES ('251', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 08:26:58'); -INSERT INTO `sys_logininfor` VALUES ('252', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 08:40:24'); -INSERT INTO `sys_logininfor` VALUES ('253', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 08:58:14'); -INSERT INTO `sys_logininfor` VALUES ('254', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-13 10:34:33'); -INSERT INTO `sys_logininfor` VALUES ('255', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-14 03:21:06'); -INSERT INTO `sys_logininfor` VALUES ('256', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 01:58:35'); -INSERT INTO `sys_logininfor` VALUES ('257', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 02:16:00'); -INSERT INTO `sys_logininfor` VALUES ('258', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 05:42:22'); -INSERT INTO `sys_logininfor` VALUES ('259', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:16:03'); -INSERT INTO `sys_logininfor` VALUES ('260', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:19:09'); -INSERT INTO `sys_logininfor` VALUES ('261', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:23:42'); -INSERT INTO `sys_logininfor` VALUES ('262', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:26:32'); -INSERT INTO `sys_logininfor` VALUES ('263', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:33:36'); -INSERT INTO `sys_logininfor` VALUES ('264', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:48:16'); -INSERT INTO `sys_logininfor` VALUES ('265', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:51:39'); -INSERT INTO `sys_logininfor` VALUES ('266', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:53:38'); -INSERT INTO `sys_logininfor` VALUES ('267', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 08:58:36'); -INSERT INTO `sys_logininfor` VALUES ('268', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:07:09'); -INSERT INTO `sys_logininfor` VALUES ('269', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:09:53'); -INSERT INTO `sys_logininfor` VALUES ('270', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:28:21'); -INSERT INTO `sys_logininfor` VALUES ('271', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:30:25'); -INSERT INTO `sys_logininfor` VALUES ('272', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:34:11'); -INSERT INTO `sys_logininfor` VALUES ('273', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:36:12'); -INSERT INTO `sys_logininfor` VALUES ('274', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:46:02'); -INSERT INTO `sys_logininfor` VALUES ('275', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:48:14'); -INSERT INTO `sys_logininfor` VALUES ('276', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:52:46'); -INSERT INTO `sys_logininfor` VALUES ('277', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:55:32'); -INSERT INTO `sys_logininfor` VALUES ('278', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:56:58'); -INSERT INTO `sys_logininfor` VALUES ('279', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 09:59:22'); -INSERT INTO `sys_logininfor` VALUES ('280', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:01:07'); -INSERT INTO `sys_logininfor` VALUES ('281', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:03:49'); -INSERT INTO `sys_logininfor` VALUES ('282', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:07:10'); -INSERT INTO `sys_logininfor` VALUES ('283', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:09:49'); -INSERT INTO `sys_logininfor` VALUES ('284', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:11:01'); -INSERT INTO `sys_logininfor` VALUES ('285', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:12:35'); -INSERT INTO `sys_logininfor` VALUES ('286', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:17:08'); -INSERT INTO `sys_logininfor` VALUES ('287', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:19:21'); -INSERT INTO `sys_logininfor` VALUES ('288', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 10:21:35'); -INSERT INTO `sys_logininfor` VALUES ('289', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 11:05:23'); -INSERT INTO `sys_logininfor` VALUES ('290', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-15 11:09:24'); -INSERT INTO `sys_logininfor` VALUES ('291', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 02:13:20'); -INSERT INTO `sys_logininfor` VALUES ('292', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 12:47:13'); -INSERT INTO `sys_logininfor` VALUES ('293', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 12:52:26'); -INSERT INTO `sys_logininfor` VALUES ('294', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 12:54:25'); -INSERT INTO `sys_logininfor` VALUES ('295', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 13:01:36'); -INSERT INTO `sys_logininfor` VALUES ('296', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 13:05:10'); -INSERT INTO `sys_logininfor` VALUES ('297', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 13:08:56'); -INSERT INTO `sys_logininfor` VALUES ('298', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 13:10:32'); -INSERT INTO `sys_logininfor` VALUES ('299', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-19 13:11:35'); -INSERT INTO `sys_logininfor` VALUES ('300', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 01:59:13'); -INSERT INTO `sys_logininfor` VALUES ('301', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:01:20'); -INSERT INTO `sys_logininfor` VALUES ('302', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:29:56'); -INSERT INTO `sys_logininfor` VALUES ('303', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:36:21'); -INSERT INTO `sys_logininfor` VALUES ('304', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:40:10'); -INSERT INTO `sys_logininfor` VALUES ('305', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:41:37'); -INSERT INTO `sys_logininfor` VALUES ('306', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 02:44:07'); -INSERT INTO `sys_logininfor` VALUES ('307', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 03:19:55'); -INSERT INTO `sys_logininfor` VALUES ('308', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 03:32:26'); -INSERT INTO `sys_logininfor` VALUES ('309', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:21:25'); -INSERT INTO `sys_logininfor` VALUES ('310', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:24:01'); -INSERT INTO `sys_logininfor` VALUES ('311', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:26:26'); -INSERT INTO `sys_logininfor` VALUES ('312', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:27:33'); -INSERT INTO `sys_logininfor` VALUES ('313', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:30:28'); -INSERT INTO `sys_logininfor` VALUES ('314', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:35:25'); -INSERT INTO `sys_logininfor` VALUES ('315', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:38:28'); -INSERT INTO `sys_logininfor` VALUES ('316', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:46:18'); -INSERT INTO `sys_logininfor` VALUES ('317', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:47:46'); -INSERT INTO `sys_logininfor` VALUES ('318', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 06:55:47'); -INSERT INTO `sys_logininfor` VALUES ('319', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 07:00:05'); -INSERT INTO `sys_logininfor` VALUES ('320', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 07:01:52'); -INSERT INTO `sys_logininfor` VALUES ('321', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 07:20:05'); -INSERT INTO `sys_logininfor` VALUES ('322', 'admin', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', '0', '登录成功', '2022-12-20 07:24:09'); +) ENGINE=InnoDB AUTO_INCREMENT=409 DEFAULT CHARSET=utf8 COMMENT='系统访问记录'; -- ---------------------------- -- Table structure for sys_menu @@ -816,16 +620,16 @@ CREATE TABLE `sys_menu` ( `update_time` datetime DEFAULT NULL COMMENT '更新时间', `remark` varchar(500) DEFAULT '' COMMENT '备注', PRIMARY KEY (`menu_id`) -) ENGINE=InnoDB AUTO_INCREMENT=2008 DEFAULT CHARSET=utf8 COMMENT='菜单权限表'; +) ENGINE=InnoDB AUTO_INCREMENT=2013 DEFAULT CHARSET=utf8 COMMENT='菜单权限表'; -- ---------------------------- -- Records of sys_menu -- ---------------------------- -INSERT INTO `sys_menu` VALUES ('1', '系统管理', '0', '1', '#', 'menuItem', 'M', '1', '1', '', 'fa fa-gear', 'admin', '2022-11-29 10:10:28', 'admin', '2022-12-12 09:52:29', '系统管理目录'); +INSERT INTO `sys_menu` VALUES ('1', '系统管理', '0', '1', '#', 'menuItem', 'M', '1', '1', '', 'fa fa-gear', 'admin', '2022-11-29 10:10:28', 'admin', '2023-03-17 10:13:17', '系统管理目录'); INSERT INTO `sys_menu` VALUES ('2', '系统监控', '0', '2', '#', 'menuItem', 'M', '1', '1', '', 'fa fa-video-camera', 'admin', '2022-11-29 10:10:29', 'admin', '2022-12-12 09:24:32', '系统监控目录'); INSERT INTO `sys_menu` VALUES ('3', '系统工具', '0', '3', '#', 'menuItem', 'M', '1', '1', '', 'fa fa-bars', 'admin', '2022-11-29 10:10:29', 'admin', '2022-12-12 09:24:39', '系统工具目录'); INSERT INTO `sys_menu` VALUES ('4', '若依官网', '0', '4', 'http://ruoyi.vip', 'menuBlank', 'C', '1', '1', '', 'fa fa-location-arrow', 'admin', '2022-11-29 10:10:29', 'admin', '2022-12-12 09:24:48', '若依官网地址'); -INSERT INTO `sys_menu` VALUES ('5', '数据配置管理', '0', '5', '#', '', 'M', '0', '1', '', 'fa fa-gear', 'admin', '2022-11-29 12:15:43', '', null, '数据配置管理'); +INSERT INTO `sys_menu` VALUES ('5', '数据源配置', '0', '5', '#', 'menuItem', 'M', '0', '1', '', 'fa fa-bars', 'admin', '2022-11-29 12:15:43', 'admin', '2023-03-05 13:35:43', '数据配置管理'); INSERT INTO `sys_menu` VALUES ('100', '用户管理', '1', '1', '/system/user', '', 'C', '0', '1', 'system:user:view', 'fa fa-user-o', 'admin', '2022-11-29 10:10:29', '', null, '用户管理菜单'); INSERT INTO `sys_menu` VALUES ('101', '角色管理', '1', '2', '/system/role', '', 'C', '0', '1', 'system:role:view', 'fa fa-user-secret', 'admin', '2022-11-29 10:10:29', '', null, '角色管理菜单'); INSERT INTO `sys_menu` VALUES ('102', '菜单管理', '1', '3', '/system/menu', '', 'C', '0', '1', 'system:menu:view', 'fa fa-th-list', 'admin', '2022-11-29 10:10:29', '', null, '菜单管理菜单'); @@ -843,7 +647,7 @@ INSERT INTO `sys_menu` VALUES ('113', '缓存监控', '2', '5', '/monitor/cache' INSERT INTO `sys_menu` VALUES ('114', '表单构建', '3', '1', '/tool/build', '', 'C', '0', '1', 'tool:build:view', 'fa fa-wpforms', 'admin', '2022-11-29 10:10:30', '', null, '表单构建菜单'); INSERT INTO `sys_menu` VALUES ('115', '代码生成', '3', '2', '/tool/gen', '', 'C', '0', '1', 'tool:gen:view', 'fa fa-code', 'admin', '2022-11-29 10:10:30', '', null, '代码生成菜单'); INSERT INTO `sys_menu` VALUES ('116', '系统接口', '3', '3', '/tool/swagger', '', 'C', '0', '1', 'tool:swagger:view', 'fa fa-gg', 'admin', '2022-11-29 10:10:30', '', null, '系统接口菜单'); -INSERT INTO `sys_menu` VALUES ('117', '数据配置', '5', '1', '/system/dbconfig', 'menuItem', 'C', '0', '1', 'system:dbconfig:view', 'fa fa-gg', 'admin', '2022-11-29 12:15:53', 'admin', '2022-11-30 07:17:43', '数据配置'); +INSERT INTO `sys_menu` VALUES ('117', '数据源配置', '5', '1', '/system/dbconfig', 'menuItem', 'C', '0', '1', 'system:dbconfig:view', 'fa fa-gg', 'admin', '2022-11-29 12:15:53', 'admin', '2023-03-05 13:15:05', '数据配置'); INSERT INTO `sys_menu` VALUES ('500', '操作日志', '108', '1', '/monitor/operlog', '', 'C', '0', '1', 'monitor:operlog:view', 'fa fa-address-book', 'admin', '2022-11-29 10:10:30', '', null, '操作日志菜单'); INSERT INTO `sys_menu` VALUES ('501', '登录日志', '108', '2', '/monitor/logininfor', '', 'C', '0', '1', 'monitor:logininfor:view', 'fa fa-file-image-o', 'admin', '2022-11-29 10:10:30', '', null, '登录日志菜单'); INSERT INTO `sys_menu` VALUES ('1000', '用户查询', '100', '1', '#', '', 'F', '0', '1', 'system:user:list', '#', 'admin', '2022-11-29 10:10:30', '', null, ''); @@ -913,14 +717,18 @@ INSERT INTO `sys_menu` VALUES ('1063', '配置新增', '117', '2', '#', 'menuIte INSERT INTO `sys_menu` VALUES ('1064', '修改', '117', '3', '#', '', 'F', '0', '1', 'system:dbconfig:edit', '#', 'admin', '2022-11-29 13:04:30', '', null, ''); INSERT INTO `sys_menu` VALUES ('1065', '删除', '117', '4', '#', '', 'F', '0', '1', 'system:dbconfig:remove', '#', 'admin', '2022-11-29 13:04:30', '', null, ''); INSERT INTO `sys_menu` VALUES ('1066', '导出', '117', '5', '#', '', 'F', '0', '1', 'system:dbconfig:export', '#', 'admin', '2022-11-29 13:04:30', '', null, ''); -INSERT INTO `sys_menu` VALUES ('2000', '任务配置', '5', '2', '/system/jobconfig', 'menuItem', 'C', '0', '1', 'system:jobconfig:view', 'fa fa-archive', 'admin', '2022-11-30 07:16:51', 'admin', '2022-11-30 07:19:45', ''); +INSERT INTO `sys_menu` VALUES ('2000', '任务配置', '2008', '2', '/system/jobconfig', 'menuItem', 'C', '0', '1', 'system:jobconfig:view', 'fa fa-archive', 'admin', '2022-11-30 07:16:51', 'admin', '2023-03-05 13:14:17', ''); INSERT INTO `sys_menu` VALUES ('2001', '查询', '2000', '1', 'system:dbconfig:list', 'menuItem', 'F', '0', '1', 'system:jobconfig:list', '#', 'admin', '2022-11-30 07:18:54', 'admin', '2022-11-30 07:23:02', ''); INSERT INTO `sys_menu` VALUES ('2002', '新增', '2000', '2', '#', 'menuItem', 'F', '0', '1', 'system:dbconfig:add', '#', 'admin', '2022-11-30 07:22:19', '', null, ''); INSERT INTO `sys_menu` VALUES ('2003', '修改', '2000', '3', '#', 'menuItem', 'F', '0', '1', 'system:dbconfig:edit', '#', 'admin', '2022-11-30 07:22:51', '', null, ''); INSERT INTO `sys_menu` VALUES ('2004', '删除', '2000', '4', '#', 'menuItem', 'F', '0', '1', 'system:dbconfig:remove', '#', 'admin', '2022-11-30 07:23:53', '', null, ''); -INSERT INTO `sys_menu` VALUES ('2005', '运行实例', '5', '3', '/system/jobInstance', 'menuItem', 'C', '0', '1', '/system/jobInstance', 'fa fa-asterisk', 'admin', '2022-12-12 03:41:51', 'admin', '2022-12-12 03:50:16', ''); +INSERT INTO `sys_menu` VALUES ('2005', '运行实例', '2008', '3', '/system/jobInstance', 'menuItem', 'C', '0', '1', '/system/jobInstance', 'fa fa-asterisk', 'admin', '2022-12-12 03:41:51', 'admin', '2023-03-05 13:14:29', ''); INSERT INTO `sys_menu` VALUES ('2006', '查看详情', '2005', '1', '#', 'menuItem', 'F', '0', '1', 'system:jobInstance:detail', '#', 'admin', '2022-12-12 03:42:42', 'admin', '2022-12-19 12:50:41', ''); INSERT INTO `sys_menu` VALUES ('2007', '查看差异', '2005', '2', '#', 'menuItem', 'F', '0', '1', 'system:jobInstance:diffDetail', '#', 'admin', '2022-12-19 12:50:09', 'admin', '2022-12-19 12:51:15', ''); +INSERT INTO `sys_menu` VALUES ('2008', '数据对比', '0', '6', '#', 'menuItem', 'M', '0', '1', '', 'fa fa-bars', 'admin', '2023-03-05 13:12:55', 'admin', '2023-03-05 13:13:41', ''); +INSERT INTO `sys_menu` VALUES ('2009', '数据探测', '0', '7', '#', 'menuItem', 'M', '0', '1', null, 'fa fa-bars', 'admin', '2023-03-05 13:15:40', '', null, ''); +INSERT INTO `sys_menu` VALUES ('2010', '任务配置', '2009', '0', '/system/probeJobConfig', 'menuItem', 'C', '0', '1', 'system:probeJobConfig:view', '#', 'admin', '2023-03-13 11:53:09', 'admin', '2023-03-13 11:53:52', ''); +INSERT INTO `sys_menu` VALUES ('2012', '探测结果', '2009', '1', '/system/probeJobInstance', 'menuItem', 'C', '0', '1', 'system:probeJobInstance:view', '#', 'admin', '2023-03-14 12:20:21', 'admin', '2023-03-14 12:20:56', ''); -- ---------------------------- -- Table structure for sys_notice @@ -968,7 +776,7 @@ CREATE TABLE `sys_oper_log` ( `error_msg` varchar(2000) DEFAULT '' COMMENT '错误消息', `oper_time` datetime DEFAULT NULL COMMENT '操作时间', PRIMARY KEY (`oper_id`) -) ENGINE=InnoDB AUTO_INCREMENT=197 DEFAULT CHARSET=utf8 COMMENT='操作日志记录'; +) ENGINE=InnoDB AUTO_INCREMENT=251 DEFAULT CHARSET=utf8 COMMENT='操作日志记录'; -- ---------------------------- -- Table structure for sys_post @@ -1176,7 +984,7 @@ CREATE TABLE `sys_user` ( -- ---------------------------- -- Records of sys_user -- ---------------------------- -INSERT INTO `sys_user` VALUES ('1', '103', 'admin', 'admin', '00', 'ry@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2022-12-20 15:24:08', '2022-11-25 05:03:52', 'admin', '2022-11-25 05:03:52', '', '2022-12-20 07:24:09', '管理员'); +INSERT INTO `sys_user` VALUES ('1', '103', 'admin', 'admin', '00', 'xiaoqiu2017wy@163.com', '15888888888', '1', '', '29c67a30398638269fe600f73a054934', '111111', '0', '0', '127.0.0.1', '2023-03-17 18:10:20', '2022-11-25 05:03:52', 'admin', '2022-11-25 05:03:52', '', '2023-03-17 10:10:23', '管理员'); INSERT INTO `sys_user` VALUES ('2', '105', 'ry', '若依', '00', 'ry@qq.com', '15666666666', '1', '', '8e6d98b90472783cc73c17047ddccf36', '222222', '0', '0', '127.0.0.1', '2022-11-25 05:03:52', '2022-11-25 05:03:52', 'admin', '2022-11-25 05:03:52', '', null, '测试员'); -- ---------------------------- @@ -1201,7 +1009,7 @@ CREATE TABLE `sys_user_online` ( -- ---------------------------- -- Records of sys_user_online -- ---------------------------- -INSERT INTO `sys_user_online` VALUES ('a7346ff6-e689-4450-9b41-676bc0eedc98', 'admin', '研发部门', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', 'on_line', '2022-12-20 15:24:06', '2022-12-20 15:24:08', '1800000'); +INSERT INTO `sys_user_online` VALUES ('0052b779-31d7-4748-961e-af078289225d', 'admin', '研发部门', '127.0.0.1', '内网IP', 'Chrome 10', 'Windows 10', 'on_line', '2023-03-17 18:10:18', '2023-03-17 18:12:25', '1800000'); -- ---------------------------- -- Table structure for sys_user_post From d7d8901641f9491a98116d2082507a7903cdf327 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Sat, 18 Mar 2023 20:51:26 +0800 Subject: [PATCH 11/26] doc:data-profiling doc --- README-CN.md | 26 ++++++++++++++++++++++---- README.md | 29 ++++++++++++++++++++++++++--- img_2.png | Bin 0 -> 10429 bytes img_3.png | Bin 0 -> 16186 bytes img_4.png | Bin 0 -> 14189 bytes 5 files changed, 48 insertions(+), 7 deletions(-) create mode 100644 img_2.png create mode 100644 img_3.png create mode 100644 img_4.png diff --git a/README-CN.md b/README-CN.md index 793ed1f..ec7bd83 100644 --- a/README-CN.md +++ b/README-CN.md @@ -16,13 +16,17 @@ dataCompare 是一个数据库比对工具:支持hive表数据比对,mysql ![image](https://user-images.githubusercontent.com/28300167/207563954-6e3dba02-84de-4881-9a23-371b88ed5b1e.png) #### 功能介绍 -(1)低代码配置,即可实现数据表的对比,不需要繁琐的sql开发 -(2)目前已经支持如下功能: 量级对比、一致性对比、差异case 发现,已经支持MySQL、Hive、Doris - -(3)后续计划支持:陌生表指针探测,包括:枚举值探测、范围值探测、主键id hash 探测 +数据对比: +(1)界面级交互数据对比任务配置,低代码少量配置快速生成对比任务 +(2)量级对比、一致性对比、自动化差异case发现 +(3)目前已经支持MySQL、Apache Hive、Apache Doris 等JDBC 数据库 +(4)已经支持对比结果自动发送邮件告警报告 +数据探针: +(1)低代码、少量配置即可完成数据探测 +(2)主键、枚举值、空值探测 #### 软件架构 ![输入图片说明](image77.png) @@ -54,6 +58,8 @@ dataCompare 是一个数据库比对工具:支持hive表数据比对,mysql 系统主页 ![image](https://user-images.githubusercontent.com/28300167/207257662-273fc531-c21e-437a-9d20-f15a533b58bd.png) +(1)数据对比功能展示 + 数据库配置 mysql配置 @@ -75,6 +81,18 @@ job配置 ![3fd83de9c582347f7f88cc82f438db4](https://user-images.githubusercontent.com/28300167/208607767-94cffce0-30f3-45ec-a280-978964e153bb.png) +(2)数据探针 + +job配置 + +![img_2.png](img_2.png) + +探针结果 + +![img_3.png](img_3.png) + +![img_4.png](img_4.png) + #### 系统运行 系统运行环境要求: diff --git a/README.md b/README.md index 5e1c0e6..0c8858a 100644 --- a/README.md +++ b/README.md @@ -18,12 +18,22 @@ dataCompare is a database comparison platform: support Hive table data compariso ![image](https://user-images.githubusercontent.com/28300167/207563534-e4df0c95-846b-4cf3-be68-37b91bd05f0b.png) #### Features -(1)Low-code configuration can realize the comparison of data tables without cumbersome sql development -(2)The following functions are currently supported: magnitude comparison, consistency comparison, difference case discovery, MySQL、Hive and Doris haved already supported +data-compare -(3)Subsequent plan support: unfamiliar table pointer detection, including: enumeration value detection, range value detection, primary key id hash detection +(1)Interface-level interactive data comparison task configuration, low code and small amount of configuration to quickly generate comparison tasks +(2)Magnitude comparison, consistency comparison, automatic difference case discovery + +(3)JDBC databases such as MySQL, Apache Hive, and Apache Doris are currently supported + +(4)Already supports the comparison results to automatically send email alarm reports + +data-profiling + +(1)Data detection can be completed with low code and a small amount of configuration + +(2)Primary key, enumeration value, null value detection #### Software Architecture @@ -57,6 +67,8 @@ Big Data:Hive、Spark Home ![image](https://user-images.githubusercontent.com/28300167/207257662-273fc531-c21e-437a-9d20-f15a533b58bd.png) +data-compare: + DbConfig mysql config @@ -78,6 +90,17 @@ Comparison results are displayed ![3fd83de9c582347f7f88cc82f438db4](https://user-images.githubusercontent.com/28300167/208607767-94cffce0-30f3-45ec-a280-978964e153bb.png) +data-profiling: + +job config + +![img_2.png](img_2.png) + +profiling result + +![img_3.png](img_3.png) + +![img_4.png](img_4.png) #### The system running environment diff --git a/img_2.png b/img_2.png new file mode 100644 index 0000000000000000000000000000000000000000..205b52a8691c7eccd9f2156e6c30e73a1a9622a9 GIT binary patch literal 10429 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 literal 0 HcmV?d00001 diff --git a/img_3.png b/img_3.png new file mode 100644 index 0000000000000000000000000000000000000000..9a51791e863802f86d670a73e6f82f13cfcdc201 GIT binary patch literal 16186 zcmeI3by(D0*YC%=6#+p(K|m0L5Gm;#1(9wLBn6ZZ>CRDMKtMw2mPSyJkcN?#PU(>D z9)f+X>2s?!h%gjibYt_lQl zTn7RZvaj-clPjur=ve1%KIeF#&LVgCB!bV>^pSBs80zgz8tBJoAp-ce1cIbXKMUNiUnzeDa@epd^!`xrn8yxDjj7z_r1A{FQFGlSyv#P%#WQ>sFjf zSIeq;nZUq!+oIT)I#t_;uIItqYF`nD#ony1#qiWZ>?&~qTe?qxOc_8mGA8SV?{ApHk2VC1{xKU`;8CAN>D(>pHc2C=_aW9ln z5xX8aE#8${a|~GLAgKe2yMoCv>+a{S8K0P=ch!BV9eN+FNb3KrfwRFrOzG~7JsD*^ zhl&3r#rf%WayTKq8c{-ElTWfVw4U2(GPQFjBiK`u^Jct|(`vOZZGyw#3^TbrE-!hV zq6I4-$9#0CnX*S2Y>yuKhvfC*$|W3D)iqD=mYNQf%=cHX;O0~GNA0)dSuAbRPt8*t z8lp*V`|E&er3c%6Owe+aK@iREVte`O8D=IOY@&vK8|Yr~;&m^CYd4p~!hVTjyr9EU z%rFk!-7;YSvuCnRKV^FTu&ty^qVCR3INhR$U6aT_>#o596U79sNz4ZPy>3R+zf#lN`_xEWOo{N)3z4%ggJ@=$I}(${om=p5lGw zMn>%CLWMZ~yxlQY4IPJVdA{*CZ(7aE9razdJ7Cy=(o%kMxDq$|?AvI!{gG7a+Hr$* zUAuSr!7vPZBi9pMc{W2avC3lfQZTfXm3r|-FbNI6^ZG+a!rN`X_8jSCXKk?Pg_;hl zqLJdc(aJ%^QSZX_ngE#2N7D@>Ihnx21X?}%Fn)4IJ8kH!I5wN**R4nqw)Hl zyEEv|8fW7~J!WIAstBab#$GI0Rz3dOc=F7nl&;k0k7ASxcPgQ{y@a-f#{712V(g{l z<*7tLhbL_-=C%5li$w;Ct#E6!p3|+-TUN<#dn6qdn;B3zuAwn;q{wh4%S^%Uh}y5c zdy5m5N~g-S*P<#5$0wGTfUM(;I ztpB#)#2E zOhE@Ucn2>~D@&{H7X3Q}CRx^Rcv_>AtAo!Gd#2ClH6}V6Hx_Jcj_qLGr#54QA16O7 zgyAG*tt~}o~z5;;&2}=W`d$w{&9B!_rh^yXK#}P58l-D zEoO7<3zl5$t`!|d_oX_$68t03f|gug0abF#3vAxyb=P=BN&Wx8o#|3bV!>SE#TmEY zoOaKb9zTyw*r>GI6@v7(|C9yDvxr+i4;JKY+TqrMm@@x7!bc!lhb!^_A3y$IY?qDhcWku=@wo$9uCmcr~ z7kgh7p;=oPdKxL^@vysZ1E_O-xp&`LDyezujmD26k=4C&VZT`cj3$dq!eIa5BblCH z6)v^1@mGCz9SCb&-^m*KM4>{XH-4j+uSHiIL3Pfn_Pi%#kFTRE7`=KoU0{pC8(NzJ zKj)vtob-|8gtEDdieap@X7x)|p+InTwrekQtlLGs6`|PM>s^yEDioF|paK z-S16Awk3zQ>0*!c78ku2-#_lmbuCV59|a4$r7p-!&XS<*>9pon+L`9iYDyqMB+Zm; z``Dh$=y}%rKRU?MBHd~qhBZ*-qO+dJ?8GMduUW+M*i`XVF`NrkJT0;D$HI_Wzy*Ce z5?rB3mEoHel7%EOu0d2UYCt89IV;`!iqAE2<!gw0HS>;fm_WW( zIUlylXBTeRF#spQERP-BL#f`|c%+<3ZmTkT(LHX&EO|g(jAp3B%&tO)=^vX?SK5%b zF?bR!w6U^?Bg$xmXskCN*esB@X>JT3+&oG`YVWj_^J zEb>VN9#@^fu~fstOs_u*)I8Ml8uPxMj=JmbQ;%7Y*^-a)>~^~0JvdW3r~i`gC0)2e zF&#}tSd8EI_9blu7Yo)Bh<)8l?wk^%A8UEUX%~bgpz~ zQczV*{vR6e@*htjWsE`#JV%?LENsPIXQkOAqO*}_ilq^#%azP*2`di@(R?kL}30*UFe4WwFvF!;XMeu~*Ne(8CzHKe$#|$-A>nWF)36f1RB38t^^gUGlF^ z$h`B6Sk35_`k(!s=y3?8n5Pd@<||I0KYpC!N0Xmao{ix}tNpj>-i9uCa-93^KtcAT zcf4Mo`gID9bSjq7y}J9G&7XO8gI0bM2naHC_2kvF{*-S(#0&(o;pp2$dnl#fZ|5Fz zkh)(j_1j^9%rlOX+`ICx4dv~MW7TGJZLo06_-TrifBgBgA~Jup&0jhRv77Hqdd$a$ z*j!A^E%g{}*49{a*%|%FnHoecToYlv^1g+Q1m@F1ANs!1$fL{%&4r=NAwFMBa@xs{ z?^H3=c3P@L7A+CrS$fTapaza)X<)z}1!p_avsFY3Qx1m~AoxV2&|FUmptGw|9e=Uh zWyZ&`d4vy`>ioijCL2P;|FEL#Q6`e;xfWvW6#~nDz*2sFgwH1~%C6hXMD>9}g-3~- za|pV>T|}ycrr#UV>Z0@m(~8#1WyiOnr+u7RXCo;C9%;X#Q8jROG-7K znJN|q{?E2?WXfXF3Sr7bMa?fBPFrW<9~JhO*`!A*oRl}p3KbKNNh&UW+(E93gg&SJ z%TD^tEtVODBplD5e3$f2MN*JC?8Z)2NuIKpGKxqAC9HyVB16 z&hjXvFyzOyBJ~V+r>8LL5J;fIW-6D2E`S83Fibfi@ywewp#VIEQR`vhD*KL9V(sd0 z2PoqS%oD|fM#M}bwUz=?@)_ts2cboM(-i<_WIkoGUBvCc+DLc{6P1obAjp`1@_E;z z$ch>lDa(jG!L48X7X0j8`u!+%>@HnH|NAeBx9ndk-IW)+Qif#QO;7pGi8{+3VSFTZ zU3_v#{WF`O2M4!ve~iOgcP|tpEUs}%qW9W%?jA*?nWb6pqhkn|6cG z$@k{vZfP8Wa5s;O;@qV@g>>o3mC15TAP@@!%LT!tmocVnklWf(+GSuu3^9a|&I_{< zIeWyR$WFgfwmLIW7Jkv zpEmox()&*5ei^{F289WVy@&yPN~y(C%k$f3#)%H=U6cOSs#yxVDHQ9DRofU}tY(e+ z2CwQ@kl>S9xq$3C_Wnq|O^=8#30;-Vu0LsD_c0&uB9Nv}h`lt}cn!bu_UvJY&16^Z zuDZ7%&nHXC$z&+RYvnEWMY;5iD=k&?j)`g7?^=MLq)AGKT37>VT@;v z5iuD%ub~^C--9Mkn*Z`T*RY+yZz*16%?Dc0Zw!yESF#5)#mg=2eWs&S%_H3oVrO}} zbRN#iQ%Sr56k^1s-v`h=p>mr>yACV2#f9aFYAy--%DOM)n<|;;z7hZ{)&L1O*nw)= zAH4C{NBPFai@2c{pu%=NZN)T#$Ojd?Plflk`}d)HOro}@B_>{Lj61r0F%mo5sq|~B zSnVlsJ5JUa1w-=yc-eT>8L?js*vL1FrPWiz1$@**5`)<)h5`VZ;kgF_>4QE&KlrCYA zp8Uv%!@bY3b&ps=dG(c&pena%Ox>-6Tr4JlUCjNQ|Fb@hV*7Y-9=R!))TPdNjo;!k z({*TD4iTx*4Z0*$w46QzP|$u4OAZl?t<1Bjk&ccZOb=|W0<$fv{9s}A3IYv_5&Mq5 zleF$Gb1YuCNu``_jj`*%a8$n=u7^h%C8vDqn%nsP7OrA%u_z-!6gQDb=ee)5H?&${ z(&1y?50C~R8)ENWr`n41aVYbb>cPUOebUO=R{iy+YOirz`l}F_0)T165*u_O=l!4g z-1<5AD3=tUj8bErC4^Dz&V)1OHFFeO0yA!>T&Lf(zGS-D^HS3KetlzkbCUT zM1rW+1E4>~11En&I3#pcC`$8;=iUNHd1yr4`7w+Ajw@J?lIqam_IRPlN_q4~4l%Vj z+i4fGj`BGieF{?KTVpWYI0A>Ea3qwtU2rH!trZjET^WhAr|--FsPh!PogVTe-^!O7 z1oYGAWTo!PMjkABk?aKOqrVz4DtL!&?>8pC9B;hjvDL=MH|j2nnO)uRgH1VnUF4zn zOJkiP8y~5h8k}o53DiX7x4jjTWV-Ptt)IQpV4q7!%)WG|YCktYWUgZkk!Z;w#}tEh z^(m&%DK_0%%5BW<&J8MM!Z=UXKw)^e1p+(^SM5<4t|PnnL;2Jv-SS**Op6n0*^inm z>6GblJK25$iQc<*&!hR|nD!VenP>eAiGZo5G$4^w zw#r|O2aAUZByL|lv|rftd{+v^f#7oW>7*GeC*0l=-S!8e#1EOc2Ftk&QJLVvbZ$+`FVa>d5g5FzrO3 z6L>7UumsdYijNTHTQ3_?h3=N!Xta*~fbjS>6Q7$(4e71@sY-7RKop&kkua99ui`E3 zu`}wFeSe(S1pC6x)6VLP+HN+ZoWq;NE%qwSVr-68)$Z)nv6J9Mg2Q~LNh!6r@P&M( zFJ_1+KG;NZJqdJk9%+&d$$I$H(fmtZ3{nXHxmo{DoZkP~$EEXTHwR4;FZn2Ia$UP{ z3@OP!w#8K!toqb4X%`$-mG`ATfY7^%mKf!CH~&c6Q~i-Qfgc*CE2l*8q^LX~lG)Dq zkr{;=w$;m}++#JrmzGZ%wy5|cX=bR835dQIsMYsM<}oMJ*Ti$*6D@gv9ty5Ns!#7P zhBq53WkG)=tTE)~Y{pbPPabgH2(N#u2K$jK^Dy`6v~oY`%{NxN5pd@n_6L!{4=>8B zH}i2@rrHHBm4hE#r8ia6jh~)>d_qE!Ta|c;FCBBg+$#wA2-D zxmm;J49iG732oQFhLzK>-1PZ)tp-&sgeoYjq}0+f2nRXK!;h*nL;Vk7ESf!ZLP_O5 zw6UYfS{lC@!S8%RmWi&T%PN5oLz>4v^fcMMOlyG=1~upWwJpt&T^_O>H_8jOiG!Im zCT$#&qB|HuGtRmg`(8ro+7($EL2Au-eInKmAARi1+0(*80&4tqU6x|jjdUs}8V2_p zkZ)SlY&J~#-QSN`MK2Ec1z)tRSb4WH!8<5PNn~Yo!0$Muc{rNxxo8GaMH11rj+m%( z-K3#@|Y`YL1@bF+1+R6Ig2+cdB+II-XGI!6iMS z582WhR`0{$V)d36is}G;5;HY5qR^wHdjBzDXANhXbzi_dS=>iLbiqn7m#+S!{dnKF z0@d?9m*v8|-*y0*`8vFbJbJRn&RMWSbY@OZdqv&Bxs9l5j!~yQf$|k!l>Nt+wy+ik zJ&KM%pV90y>^}E3-j{0PpAK8kqYsKl-|G2xX^Pd&`LEq@ zkO#^OxA}G%?5y(DklDEt^lTwDGv>Z6oGjEkbZMW~@(nZ1&dE+^1R@w5{WHRGk@ z<;wVp=1AMg3OAKHPL7(VRC!otZ7nXiw<8-BFe^y`RUo<=8D5{fid-KsGdkSEvK=Nd zNV&KVX!p1=QHsPbk@6MFo*&q?=8-fsC(EV#YX|DoB8^Mz_W|mwGq0_AnQQI)oqbuw zEeci`3sz8SY4prR^e)xFHQjFM7jk@+^f83<2p@O_>n;!YAw>3TR55{^cel5G?=>Kr zp^w|dzb0`wVThK^`^XiMK@)w_742<KL1A>Uheq>r@Lr14eW3`lZN?c0Wa$v`-?Ad3E6jtX_=@nd{VR!+XQ;#FU}I z@w^e=fya+yWhhVPKUv&SPjRcKr%0){NlR$MW}V-^o+7KKfq%C?vXGHj!sbbSizO>G6~PQ9j8{B6^S)x|BDl)Z1Z{5%}9lkI__x zC$HDhB&5#Cxr_2Au&g@<<>W-ilhHjt1xxSGsHG(-m@3LB%8=%y@SoJ}4x9=uU~`wc zT8SN zq7y0F!M$Oz8hSs@-btYXe$_MZsU^d_9rq$C#*bagghJf$rfd=uvBe-ojfpP$xR&rc zO3BY7HwW?-QHG|<#5u!HSG5uvSV%bP6qpa{x(kUww!v5 z{vg?22lt){Gs~N!>@}R}VQ*9@^0R zT&Td2F^q7lmzV+jwv;*3IwMWiIcT4m_ zsjx7dT`!;8Lb|}pwGt|KEFf23aG?daAg3HhIm@a!kof#9)SO{xYqi{LhbDRjfW$1hNNdkxuwOO3+?_wc-puSyeg7R@|UDrEtMP`>$3tFIw-V z-Bk1!Ov=}utcXqM>M>935pHZ8&fq#WD7jRT@IE?@++Sr=I@HjWPB%B=PH#tjC*PnF zIf-}gUJd-?Y;AL}hWuBK1)skzWdG9%0U=?745!b&Ev2kBIe{5(x|@>i|9GfWA?tX5 z9aU;6n`Am(=jPk3LeO&AEr_#W0TW-Iofwd0rIJEu?l$%UZnlv@abhwUZv^$)RO-L2 zK|!E>I#a1BlMH(#YSBYgEhmDZqF%w{`x@yq#0|G+Pwv8jjf$bpMNX7S&e zm|BV11B`K3v~mn;KFKAvv0~Tbo4i4o`$i9BhV}hBGajl354axmcqbRyPUbg_rEl$( zQtlbYC~+qUsB)_pr*i$R&0*xa#6dpNv5n))KRZMgT<%QG33r+kB%8-`_*~14DIfih zIa2@8%Ftp0frx+UAcZRYdG-Oc`tKjVdl%Wh!;ka%kF?~Cp3R>ivdsn$BIEJmh6j-c z07Oy;eg~0LH@LDpLGcbxGysu}e*!=}h@87vCdQO3iU*Op4L?96Pw5X3`JE>I??EIp zw|?Pw5ZRzXsr4s_4CV$5^CyVZ`vD@6KR{%)PXy4|?;!F|AS#Xrkq^aNfWlt;6#ffD z_TWL}5g*I5e*uv_8%seyX_7deoJd0*RnQT9AcIf3C&zP6rQHt@2hPv_1y;l#m> z&ug^J78RyUduRQw3lI5+XY*QM<-bTs2GhnDKb!zgqoZ%HoX@PFyJgk5ZHC@o@3fwS`ss%=Z-zZJ=7^BdA`o%hio~0vK1M{%!#vV~_ZJhEs)% z$z)fnytey>*Xp!sp`MuZ^TkgAYnrI_#n=1o^AT`9-Kx}XV8jMYUd8j2L%W7C-hJu( z;xQ$?_jIz@jd6fhbgn=5q*NFz4#cmX@(sdP7hnPf1WOO5bk@J8RCgceJ+w(P=Z{6YGv z>Rv1j|GG3!(~Dj*dOeDg%6NjX{*Pn|O@1x} z$FVA5P@_iN0PyRvN(uv#=Do(9oYP=ny*R#r>EkTwlOzHw zh>h}yBW=?2u+Z3}S`8M(I%8{=uAO(jvt#gF-@cPfn-x@+t6oZ5=?(7zXkgx$`;69SHQ5 zI>vu!^bIKX0+4qpB3IL8`pavKL+I}2`a~M2k^{iUTM3E5xlQ2fq}a&isf^PFRSN-O z*QRsk5FYx5;1A2T-WhS?Jtc8_|JRdQB4*kpzXu{>XqI83}Yx^NScBAw4v7Sz0Mxt1zz}66%AZ%Y9cXmR6;q z-;mucLj8Y&PjThnz-Qu5A^P09ZgamX)daZ#9SqnuG5z&osqWzsjT#Y3dBh%l}aZbcK=A(EUNIa`($jnlkols`g1NMGx~2Mg{9Arl-gNU9-v+< zU0Crv*mhQTjf)EC(?@3*c~!0*xPXehp5a9-DEzAg)rMdi9;1``RiH|9Bnqt8FAZs} zcy~_W{>JyBV4<}#5PU6(jyPdyl*2sYLSRKB2nRsuB!l8`b2@bBQE}!u%Kck$s8Z{% z`LPjnLXJ<}Czm?`QU?VTJrgzMZae8@ca+(5;KSa_+@4rfaU<}~-DS-U2E=)Ji@kya z)N!sMaCgcEfizM8Wto&^ucxcED8iziM>@8uwlBEkyA$KYC-)qDA`NrM1Hl812xt}8l^kjs1vOfT^(GdF!Oq#Ch^Bv6$ z{b~PygUkAlb%_62t=GFYnoR8e%1wkuCPr$D}vpbq4`Pd!IRiDpCvGu^RH2 zfLU2W8^qDr4}Q;Ke~Kw0+Y;(kWGP*jXKc*}_n%VJ zAu!9G(bEWWB1v%^;HP}vz%ZL7fzUbkWafi;4Xcr-b!7r!TB>|)#Zv*{x!j>4v_F)))K^wfC@ah z@PxBdyU*1)3G2zpCG*xz91Hyw6IDg_9n-anuXSsZ-B_+ewrAUyT@LD(^mTFTfM^`z^n~u+x!IA=VVB$RT^>YCDU6-Ue^QpxMuv98Z;*n2 zl6X=|grAfzHKr6SjzrMB8enerk;sOH>iw+hpImG^3@gmnm@%;2(y;K3^J(H%E#FXD zY})e@sA9B*&bfu~spWNx=X9Lv& z!WY!La}J@|(fdw&fFFACxjhV$Z!PD%TkmmpvDuH0uR*B6V{|}+6AULt6$~fuxl>!c z3`vyUI#v0{!arbt`M9 z2b>0-Z`%u@lEEwBdZXaV2RVYrpqg{C|KSePMd2UnfYVWrog(TCPWKlij zv~(G1EpMau`DmZnuzSa!>!_)}%DtLWEzZ6Yz6-!~?AO}a^)+QN1Xn&x8TJ7)o6?TxC^bN*E7 zW=Cn?m-I{(h8^^ksM%zgh$~ZNOa_|~3&-tJ`B)opNPbF-setw1CNu{lS5%prX~Q?9 zUJ+jIT^+T0M1qo@Tkrw0BDSKAd6|Hf>#B{;jge#bO*=`4+0Rt_`C8*&7tQ}?)c>DO zq}lfet@z#T%^=prTYx_@#_>L{yiFaBunZvP;Euop(e1EJHyTzGY5UlN;p3>I7HZfs zR^HE@;0+Ppk2SB^6vkcevHOm$otUvPRrsZtAHHz}cMn7kmLy)s02UFIxb?4#t5xkkMgUsaQcBCTIZ8@M?l z8mWEHzd18e?RyD9YHLVD7+LG}s9(-?z`6z886nW_9>2C9kWcc)V_lCKHhSS#6g0C_ zA~>xl`l{p6#GpC2kXPF?214Kl#-fn`*hIs3yc?=ha;F4b$Wbey(RY2dBa_SA5XseJ z?my9iY#n+ss(H?tf!>9Zsd_246cu<@xIkskM6d+DsjY3PDLP1Ln9IR8iF7MZg zk=q}J2_J*RROhpl8%Mczu(86_-C)Iv;}N6%gBj0yLwXuYJZ%w{{dXPxmu~RvZqU)9 z#}z7M&cVR=Tr>YRK8nOK6}U+qQh0BLM1QVD{RO!$HPv43Bql$_#06>lNG=JB5J%HDA}gfqsRMD94@`bos5?(s z)cSPsgjO*{^P82-(yDk@v!X#`Cvz0r5?6*j!)Ssw@50;moM<$4PlOeF9Mw>yfO`1X zm3EF-f9tz;ib9VyfoG#BQCeKty+*d!Z)fjp5>w@)dC)m`o3}{911Xy|CzU1CT1ffR zEThtB(5no&w&`B0;t)cTJ&su>m+djNbC{!(qx7SGao3QM-MFU-gANmICl)BuST_t* zLpwx*l>T1XZ>Zgw^PByx~veTRhVKk{)gzEU+s&~g2b zj-}ZP-8XHpHz3dc5OnE|PR_xXutKq;@FLr$odXH{_2;b8@QYgW7eLC`T59;Vi|Kpe zZ4!2BeA9~<&yy1qv2*a*$w#m8)LaW(qQ>nbW+kbH6q&%ibyxX+*UuH)$?GW*mBmXK SS8yjDA}yhCH%IK@i~j}h=4rA3 literal 0 HcmV?d00001 diff --git a/img_4.png b/img_4.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d7bb21b68d5f213a6e830403cea3c109351e9b GIT binary patch literal 14189 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 literal 0 HcmV?d00001 From 4760555e941ab76a735c696fbb1ef71c9066152c Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Sat, 18 Mar 2023 20:55:01 +0800 Subject: [PATCH 12/26] doc:update doc --- README-CN.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README-CN.md b/README-CN.md index ec7bd83..1b50b9b 100644 --- a/README-CN.md +++ b/README-CN.md @@ -18,14 +18,19 @@ dataCompare 是一个数据库比对工具:支持hive表数据比对,mysql #### 功能介绍 数据对比: + (1)界面级交互数据对比任务配置,低代码少量配置快速生成对比任务 + (2)量级对比、一致性对比、自动化差异case发现 + (3)目前已经支持MySQL、Apache Hive、Apache Doris 等JDBC 数据库 + (4)已经支持对比结果自动发送邮件告警报告 数据探针: (1)低代码、少量配置即可完成数据探测 + (2)主键、枚举值、空值探测 #### 软件架构 From 099a1bf3f8674ebb0bb2487c302ab55aebf1c23d Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Mon, 20 Mar 2023 20:51:48 +0800 Subject: [PATCH 13/26] doc:update dataCompare doc --- README-CN.md | 6 +++++- README.md | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README-CN.md b/README-CN.md index 1b50b9b..b60fd47 100644 --- a/README-CN.md +++ b/README-CN.md @@ -11,7 +11,11 @@ [![CN doc](https://img.shields.io/badge/文档-中文版-blue.svg)](README-CN.md) #### 介绍 -dataCompare 是一个数据库比对工具:支持hive表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理,后续考虑支持ck等等 +dataCompare 是一个大数据数据比对和数据探测平台 + +(1)支持hive表数据比对,mysql、Doris 数据比对,实现自动化配置进行数据比对,避免频繁写sql 进行处理 + +(2)支持少量配置即可实现数据探测 ![image](https://user-images.githubusercontent.com/28300167/207563954-6e3dba02-84de-4881-9a23-371b88ed5b1e.png) diff --git a/README.md b/README.md index 0c8858a..01d5300 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,11 @@ #### Introduction -dataCompare is a database comparison platform: support Hive table data comparison, MySQL、Doris data comparison, realize automatic configuration for data comparison, avoid frequent SQL writing for processing, and consider supporting CK and so on +dataCompare is a database comparison and profiling platform + +(1)support Hive table data comparison, MySQL、Doris data comparison, realize automatic configuration for data comparison, avoid frequent SQL writing for processing + +(2)support easy configuration for data profiling ![image](https://user-images.githubusercontent.com/28300167/207563534-e4df0c95-846b-4cf3-be68-37b91bd05f0b.png) From 77a10b73236f9a48db3731a830bf88fb92b933d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 20 Mar 2023 21:03:26 +0800 Subject: [PATCH 14/26] doc: update doc --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 01d5300..a5ba78f 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,9 @@ dataCompare is a database comparison and profiling platform ![image](https://user-images.githubusercontent.com/28300167/207563534-e4df0c95-846b-4cf3-be68-37b91bd05f0b.png) +![image](https://user-images.githubusercontent.com/28300167/226346775-f1c1ed2d-8370-45db-878c-8ab81d9e402e.png) + + #### Features data-compare From 1d49f4525bd5bd7a2d8faf6571792c661559be38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 20 Mar 2023 21:03:57 +0800 Subject: [PATCH 15/26] doc:update doc --- README-CN.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README-CN.md b/README-CN.md index b60fd47..69cbea9 100644 --- a/README-CN.md +++ b/README-CN.md @@ -19,6 +19,8 @@ dataCompare 是一个大数据数据比对和数据探测平台 ![image](https://user-images.githubusercontent.com/28300167/207563954-6e3dba02-84de-4881-9a23-371b88ed5b1e.png) +![image](https://user-images.githubusercontent.com/28300167/226346775-f1c1ed2d-8370-45db-878c-8ab81d9e402e.png) + #### 功能介绍 数据对比: From 592ef1fc024530a1c3627fc46b85b682ea5f4620 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Tue, 21 Mar 2023 17:18:59 +0800 Subject: [PATCH 16/26] doc:update readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a5ba78f..16bc3e3 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,8 @@ Environment installation configuration #### Technological Communication ![image](https://user-images.githubusercontent.com/28300167/207255900-152d6834-9602-4ada-91ca-ad9906d89bf8.png) +#### Star History +[![Star History Chart](https://api.star-history.com/svg?repos=zhugezifang/dataCompare&type=Date)](https://star-history.com/#zhugezifang/dataCompare&Date) #### Thanks Thanks ruoyi Provides front-end services From 6342714191f9588abb9c6f8c09cfda452212fab5 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Sun, 26 Mar 2023 20:00:25 +0800 Subject: [PATCH 17/26] feat:length profiling --- .../com/vince/xq/project/common/RunUtil.java | 14 +++ .../domain/ProbeJobInstance.java | 11 ++ .../domain/ProbeJobInstanceResult.java | 11 ++ .../service/ProbeJobInstanceServiceImpl.java | 101 +++++++++++------- .../probeJobConfig/domain/Probejobconfig.java | 11 ++ .../mybatis/system/ProbeJobInstanceMapper.xml | 5 + .../mybatis/system/ProbeJobconfigMapper.xml | 6 +- .../templates/system/probeJobConfig/add.html | 8 ++ .../system/probeJobConfig/probeJobConfig.html | 4 + .../system/probeJobInstance/detail.html | 32 ++++++ .../probeJobInstance/probeJobInstance.html | 4 + 11 files changed, 169 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/vince/xq/project/common/RunUtil.java b/src/main/java/com/vince/xq/project/common/RunUtil.java index 4222220..ae8df2d 100644 --- a/src/main/java/com/vince/xq/project/common/RunUtil.java +++ b/src/main/java/com/vince/xq/project/common/RunUtil.java @@ -299,6 +299,10 @@ public static Instance runNum(Dbconfig dbconfig, String connectDriver, String co "group by column\n" + ")t order by cnt desc limit 20;"; + public static final String lengthTemplateSql = "select len,count(*) as cnt from (\n" + + "select *,length(column) as len from tableName filter\n" + + ")t group by len;"; + public static ProbeJobInstance runProbeJob(Dbconfig dbconfig, Probejobconfig probejobconfig) throws Exception { DbTypeEnum dbTypeEnum = DbTypeEnum.findEnumByType(dbconfig.getType()); String filter = probejobconfig.getFilter(); @@ -334,6 +338,16 @@ public static ProbeJobInstance runProbeJob(Dbconfig dbconfig, Probejobconfig pro } instance.setEnumResult(JSONObject.toJSONString(enumResult)); } + if (StringUtils.isNotBlank(probejobconfig.getTableLengthFields())) { + String[] lenFieldArr = probejobconfig.getTableLengthFields().split(","); + Map>> lengthResult = new HashMap<>(); + for (String lenField : lenFieldArr) { + String sql = lengthTemplateSql.replaceAll("column", lenField).replace("tableName", probejobconfig.getTableName()).replace("filter", Optional.ofNullable(filter).orElse("")); + List> lenList = runProbJobField(dbconfig, dbTypeEnum.getConnectDriver(), sql); + lengthResult.put(lenField, lenList); + } + instance.setLenResult(JSONObject.toJSONString(lengthResult)); + } return instance; } diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java index 46b6474..0c94086 100644 --- a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstance.java @@ -34,6 +34,9 @@ public class ProbeJobInstance implements Serializable @Excel(name = "nullResult") private String nullResult; + @Excel(name = "lenResult") + private String lenResult; + @Excel(name = "filter") private String filter; @@ -49,6 +52,14 @@ public void setFilter(String filter) { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; + public String getLenResult() { + return lenResult; + } + + public void setLenResult(String lenResult) { + this.lenResult = lenResult; + } + public Long getId() { return id; } diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java index 951cf2f..2ef1670 100644 --- a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/domain/ProbeJobInstanceResult.java @@ -25,12 +25,23 @@ public class ProbeJobInstanceResult implements Serializable @Excel(name = "enumResultMap") private Map> enumResultMap; + @Excel(name = "lenResultMap") + private Map> lenResultMap; + @Excel(name = "nullResultList") private List nullResultList; @Excel(name = "filter") private String filter; + public Map> getLenResultMap() { + return lenResultMap; + } + + public void setLenResultMap(Map> lenResultMap) { + this.lenResultMap = lenResultMap; + } + public Long getId() { return id; } diff --git a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java index 3c1f0e4..af48169 100644 --- a/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java +++ b/src/main/java/com/vince/xq/project/system/ProbeJobInstance/service/ProbeJobInstanceServiceImpl.java @@ -17,6 +17,7 @@ import com.vince.xq.project.system.probeJobConfig.mapper.ProbeJobconfigMapper; import com.vince.xq.project.system.user.domain.User; import com.vince.xq.project.system.user.mapper.UserMapper; +import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -67,50 +68,76 @@ private ProbeJobInstanceResult extract(ProbeJobInstance instance) { probeJobInstanceResult.setTableName(instance.getTableName()); probeJobInstanceResult.setFilter(instance.getFilter()); - JSONObject primaryResultObj = JSONObject.parseObject(instance.getPrimaryResult()); - for (String key : primaryResultObj.keySet()) { - ProbeJobInstanceResult.PrimaryResult primaryResult = new ProbeJobInstanceResult.PrimaryResult(); - primaryResult.setPrimaryField(key); - JSONObject jsonObject = JSONObject.parseObject(primaryResultObj.getString(key)); - primaryResult.setCnt(jsonObject.getLong("cnt")); - primaryResult.setDistinctCnt(jsonObject.getLong("distinct_cnt")); - probeJobInstanceResult.setPrimaryResult(primaryResult); + if (StringUtils.isNotEmpty(instance.getPrimaryResult())){ + JSONObject primaryResultObj = JSONObject.parseObject(instance.getPrimaryResult()); + for (String key : primaryResultObj.keySet()) { + ProbeJobInstanceResult.PrimaryResult primaryResult = new ProbeJobInstanceResult.PrimaryResult(); + primaryResult.setPrimaryField(key); + JSONObject jsonObject = JSONObject.parseObject(primaryResultObj.getString(key)); + primaryResult.setCnt(jsonObject.getLong("cnt")); + primaryResult.setDistinctCnt(jsonObject.getLong("distinct_cnt")); + probeJobInstanceResult.setPrimaryResult(primaryResult); + } } - JSONObject nullResultObj = JSONObject.parseObject(instance.getNullResult()); - List nullResultList = new ArrayList<>(); - for (String key : nullResultObj.keySet()) { - ProbeJobInstanceResult.NullResult nullResult = new ProbeJobInstanceResult.NullResult(); - nullResult.setNullField(key); - JSONArray jsonArray = JSONObject.parseArray(nullResultObj.getString(key)); - long totalCnt = 0; - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); - if (jsonObject.getString("dict").equals("0")) { - nullResult.setNullCnt(jsonObject.getLong("cnt")); + if (StringUtils.isNotEmpty(instance.getNullResult())){ + JSONObject nullResultObj = JSONObject.parseObject(instance.getNullResult()); + List nullResultList = new ArrayList<>(); + for (String key : nullResultObj.keySet()) { + ProbeJobInstanceResult.NullResult nullResult = new ProbeJobInstanceResult.NullResult(); + nullResult.setNullField(key); + JSONArray jsonArray = JSONObject.parseArray(nullResultObj.getString(key)); + long totalCnt = 0; + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); + if (jsonObject.getString("dict").equals("0")) { + nullResult.setNullCnt(jsonObject.getLong("cnt")); + } + totalCnt += jsonObject.getLong("cnt"); } - totalCnt += jsonObject.getLong("cnt"); + nullResult.setTotalCnt(totalCnt); + nullResultList.add(nullResult); } - nullResult.setTotalCnt(totalCnt); - nullResultList.add(nullResult); + probeJobInstanceResult.setNullResultList(nullResultList); } - probeJobInstanceResult.setNullResultList(nullResultList); - - JSONObject enumObj = JSONObject.parseObject(instance.getEnumResult()); - Map> enumResultMap = new HashMap<>(); - for (String key : enumObj.keySet()) { - JSONArray jsonArray = JSONObject.parseArray(enumObj.getString(key)); - List list = new ArrayList<>(); - for (int i = 0; i < jsonArray.size(); i++) { - JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); - ProbeJobInstanceResult.EnumResult enumResult = new ProbeJobInstanceResult.EnumResult(); - enumResult.setEnumValue(jsonObject.getString("dict")); - enumResult.setCnt(jsonObject.getLong("cnt")); - list.add(enumResult); + + + if (StringUtils.isNotEmpty(instance.getEnumResult())){ + JSONObject enumObj = JSONObject.parseObject(instance.getEnumResult()); + Map> enumResultMap = new HashMap<>(); + for (String key : enumObj.keySet()) { + JSONArray jsonArray = JSONObject.parseArray(enumObj.getString(key)); + List list = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); + ProbeJobInstanceResult.EnumResult enumResult = new ProbeJobInstanceResult.EnumResult(); + enumResult.setEnumValue(jsonObject.getString("dict")); + enumResult.setCnt(jsonObject.getLong("cnt")); + list.add(enumResult); + } + enumResultMap.put(key, list); } - enumResultMap.put(key, list); + probeJobInstanceResult.setEnumResultMap(enumResultMap); } - probeJobInstanceResult.setEnumResultMap(enumResultMap); + + if (StringUtils.isNotEmpty(instance.getLenResult())) { + JSONObject lenObj = JSONObject.parseObject(instance.getLenResult()); + Map> lenResultMap = new HashMap<>(); + for (String key : lenObj.keySet()) { + JSONArray jsonArray = JSONObject.parseArray(lenObj.getString(key)); + List list = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + JSONObject jsonObject = JSONObject.parseObject(jsonArray.get(i).toString()); + ProbeJobInstanceResult.EnumResult enumResult = new ProbeJobInstanceResult.EnumResult(); + enumResult.setEnumValue(jsonObject.getString("len")); + enumResult.setCnt(jsonObject.getLong("cnt")); + list.add(enumResult); + } + lenResultMap.put(key, list); + } + probeJobInstanceResult.setLenResultMap(lenResultMap); + } + return probeJobInstanceResult; } diff --git a/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java b/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java index 9b4fc23..60a4c32 100644 --- a/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java +++ b/src/main/java/com/vince/xq/project/system/probeJobConfig/domain/Probejobconfig.java @@ -31,6 +31,9 @@ public class Probejobconfig implements Serializable @Excel(name = "tableNullFields") private String tableNullFields; + @Excel(name = "tableLengthFields") + private String tableLengthFields; + /** createBy */ @Excel(name = "createBy") private String createBy; @@ -45,6 +48,14 @@ public class Probejobconfig implements Serializable @Excel(name = "dbConfigId") private Long dbConfigId; + public String getTableLengthFields() { + return tableLengthFields; + } + + public void setTableLengthFields(String tableLengthFields) { + this.tableLengthFields = tableLengthFields; + } + public Long getId() { return id; } diff --git a/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml b/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml index d987429..1d6a1e3 100644 --- a/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml +++ b/src/main/resources/mybatis/system/ProbeJobInstanceMapper.xml @@ -10,6 +10,7 @@ + @@ -22,6 +23,7 @@ a.primary_result, a.enum_result, a.null_result, + a.len_result, a.create_time, b.`table_name`, b.filter @@ -35,6 +37,7 @@ a.primary_result, a.enum_result, a.null_result, + a.len_result, a.create_time, b.`table_name` from probe_job_instance a join probe_job_config b on a.job_config_id=b.id @@ -68,12 +71,14 @@ primary_result, enum_result, null_result, + len_result, create_time )values( #{jobconfigId}, #{primaryResult}, #{enumResult}, #{nullResult}, + #{lenResult}, sysdate() ) diff --git a/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml b/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml index 3766fc1..30d1764 100644 --- a/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml +++ b/src/main/resources/mybatis/system/ProbeJobconfigMapper.xml @@ -10,6 +10,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -17,7 +18,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - select id, `table_name`,table_primary, table_enum_fields, table_null_fields,db_config_id,filter, + select id, `table_name`,table_primary, table_enum_fields, table_null_fields,table_length_fields,db_config_id,filter, create_by, create_time from probe_job_config @@ -53,6 +54,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" table_primary, table_enum_fields, table_null_fields, + table_length_fields, db_config_id, filter, @@ -63,6 +65,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" #{tablePrimary}, #{tableEnumFields}, #{tableNullFields}, + #{tableNullFields}, + #{dbConfigId}, #{filter}, #{createBy}, diff --git a/src/main/resources/templates/system/probeJobConfig/add.html b/src/main/resources/templates/system/probeJobConfig/add.html index 32da64c..679c834 100644 --- a/src/main/resources/templates/system/probeJobConfig/add.html +++ b/src/main/resources/templates/system/probeJobConfig/add.html @@ -49,6 +49,14 @@
+
+ +
+ +
+
+
diff --git a/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html b/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html index b917d2d..6451aeb 100644 --- a/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html +++ b/src/main/resources/templates/system/probeJobConfig/probeJobConfig.html @@ -83,6 +83,10 @@ field: 'tableNullFields', title: '空值检测字段' }, + { + field: 'tableLengthFields', + title: '长度检测字段' + }, { field: 'filter', title: '过滤条件' diff --git a/src/main/resources/templates/system/probeJobInstance/detail.html b/src/main/resources/templates/system/probeJobInstance/detail.html index cff8c84..197b5fd 100644 --- a/src/main/resources/templates/system/probeJobInstance/detail.html +++ b/src/main/resources/templates/system/probeJobInstance/detail.html @@ -127,6 +127,38 @@
+
+ +
+ +
+
+ +
+ +
+
+ + + + + + + + + + + + + + + +
lenth_value
num
+ +
+ +
+
diff --git a/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html b/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html index 6e88348..5841267 100644 --- a/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html +++ b/src/main/resources/templates/system/probeJobInstance/probeJobInstance.html @@ -68,6 +68,10 @@ field: 'nullResult', title: '空值检测结果' }, + { + field: 'lenResult', + title: '字段长度检测结果' + }, { field: 'createTime', title: '创建时间', From 145971a6cfc36e2421d071bcdc0e0effb7efca33 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Sun, 26 Mar 2023 20:07:18 +0800 Subject: [PATCH 18/26] feat:length sql --- sql/dataCompare.sql | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/sql/dataCompare.sql b/sql/dataCompare.sql index bc53752..0623475 100644 --- a/sql/dataCompare.sql +++ b/sql/dataCompare.sql @@ -142,8 +142,9 @@ CREATE TABLE `probe_job_config` ( `id` int(11) NOT NULL AUTO_INCREMENT, `table_name` varchar(255) NOT NULL, `table_primary` varchar(255) DEFAULT NULL, - `table_enum_fields` varchar(255) NOT NULL COMMENT 'table_enum_fields', - `table_null_fields` varchar(255) NOT NULL COMMENT 'table_null_fields', + `table_enum_fields` varchar(255) DEFAULT NULL COMMENT 'table_enum_fields', + `table_null_fields` varchar(255) DEFAULT NULL COMMENT 'table_null_fields', + `table_length_fields` varchar(255) DEFAULT NULL COMMENT 'table_length_fields', `filter` varchar(255) DEFAULT NULL COMMENT 'filter', `db_config_id` int(11) DEFAULT NULL, `create_time` datetime DEFAULT NULL, @@ -161,6 +162,7 @@ CREATE TABLE `probe_job_instance` ( `primary_result` text COMMENT 'primary_result', `enum_result` text COMMENT 'enum_result', `null_result` text COMMENT 'null_result', + `len_result` text COMMENT 'len_result', `create_time` datetime DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=35 DEFAULT CHARSET=utf8 COMMENT='probe_job_instance'; From a94e91244875cf6c4a35bfbe54833605b624438d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Tue, 28 Mar 2023 22:30:33 +0800 Subject: [PATCH 19/26] feat:english bolt feat:english bolt --- .github/workflows/english-bolt.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 .github/workflows/english-bolt.yml diff --git a/.github/workflows/english-bolt.yml b/.github/workflows/english-bolt.yml new file mode 100644 index 0000000..ab963c6 --- /dev/null +++ b/.github/workflows/english-bolt.yml @@ -0,0 +1,15 @@ +name: 'issues-translator' +on: + issue_comment: + types: [created] + issues: + types: [opened] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: usthe/issues-translate-action@v2.7 + with: + IS_MODIFY_TITLE: true + # BOT_GITHUB_TOKEN: ${{ secrets.BOT_GITHUB_TOKEN }} From 212f3f84fcba1bc26ebe35cfee5f05a619d9a399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 3 Apr 2023 19:50:58 +0800 Subject: [PATCH 20/26] doc:update doc doc:update doc --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 16bc3e3..da2e175 100644 --- a/README.md +++ b/README.md @@ -109,6 +109,8 @@ profiling result ![img_4.png](img_4.png) +![image](https://user-images.githubusercontent.com/28300167/229501053-4e33b6fb-851a-4fb2-9b19-16308359f57e.png) + #### The system running environment java jdk8 From 9c164858026b85d1ad2d642fabb17cd586d54f38 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Mon, 3 Apr 2023 19:54:28 +0800 Subject: [PATCH 21/26] doc:update doc --- README-CN.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README-CN.md b/README-CN.md index 69cbea9..c7089a6 100644 --- a/README-CN.md +++ b/README-CN.md @@ -104,6 +104,8 @@ job配置 ![img_4.png](img_4.png) +![image](https://user-images.githubusercontent.com/28300167/229501053-4e33b6fb-851a-4fb2-9b19-16308359f57e.png) + #### 系统运行 系统运行环境要求: From 118f1c5e617bd9502cc50176141a8369a07c0789 Mon Sep 17 00:00:00 2001 From: duanxiaoqiu Date: Fri, 7 Apr 2023 21:51:42 +0800 Subject: [PATCH 22/26] doc:update doc --- README-CN.md | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README-CN.md b/README-CN.md index c7089a6..e2bf2a6 100644 --- a/README-CN.md +++ b/README-CN.md @@ -117,7 +117,7 @@ mysql 5.7.36 (1)将sql目录中的sql文件进行运行在数据库,创建库和表 -(2)下载发布好的jar(https://github.com/zhugezifang/dataCompare/releases) 或者自己构建jar +(2)在根目录下面进行mvn clean package -Dmaven.test.skip=true -Ptest,使用target 目录下的dataCompare.jar (3)修改数据库配置信息 application.yml,将数据库连接信息改为步骤(1)的数据库连接信息 ![47d1145d147214348d6d0f2fc599ea7](https://user-images.githubusercontent.com/28300167/219598181-5731e845-a49e-43af-a96c-db6d6148b11a.png) diff --git a/README.md b/README.md index da2e175..0fe613e 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ Runing config (1)Run the SQL files in the SQL directory in the database, create database and tables -(2)download the release jar(https://github.com/zhugezifang/dataCompare/releases) or build jar using the source code of the project +(2)build jar using the source code of the project: mvn clean package -Dmaven.test.skip=true -Ptest (3)edit database config information of application.yml From 108ea390675d972d0efab6f49d60e71a24ad312d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 31 Jul 2023 15:21:42 +0800 Subject: [PATCH 23/26] test:test case test:test case --- src/test/java/XqTest.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/test/java/XqTest.java b/src/test/java/XqTest.java index 0a45db7..60577b7 100644 --- a/src/test/java/XqTest.java +++ b/src/test/java/XqTest.java @@ -7,7 +7,10 @@ import java.sql.*; + public class XqTest { + + /** @Test public void testSql() throws Exception { Dbconfig dbconfig = new Dbconfig(); @@ -62,4 +65,5 @@ public void testHive() throws Exception { throw new Exception("连接数据库失败"); } } + /** } From f78b8ef23c0460c000425214931299b87dd9ab36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 31 Jul 2023 15:22:17 +0800 Subject: [PATCH 24/26] Update README-CN.md --- README-CN.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README-CN.md b/README-CN.md index e2bf2a6..3ae4c65 100644 --- a/README-CN.md +++ b/README-CN.md @@ -117,7 +117,7 @@ mysql 5.7.36 (1)将sql目录中的sql文件进行运行在数据库,创建库和表 -(2)在根目录下面进行mvn clean package -Dmaven.test.skip=true -Ptest,使用target 目录下的dataCompare.jar +(2)在根目录下面进行mvn clean package,使用target 目录下的dataCompare.jar (3)修改数据库配置信息 application.yml,将数据库连接信息改为步骤(1)的数据库连接信息 ![47d1145d147214348d6d0f2fc599ea7](https://user-images.githubusercontent.com/28300167/219598181-5731e845-a49e-43af-a96c-db6d6148b11a.png) From ca709e10a8e5e6333231d5ac68cfdbc3f897e7cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Mon, 31 Jul 2023 15:22:49 +0800 Subject: [PATCH 25/26] doc:update package info doc:update package info --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0fe613e..81894d1 100644 --- a/README.md +++ b/README.md @@ -121,7 +121,7 @@ Runing config (1)Run the SQL files in the SQL directory in the database, create database and tables -(2)build jar using the source code of the project: mvn clean package -Dmaven.test.skip=true -Ptest +(2)build jar using the source code of the project: mvn clean package (3)edit database config information of application.yml From d118e89272f53071ae45ca99ce8e2dddaf836925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AF=B8=E8=91=9B=E5=AD=90=E6=88=BF?= Date: Tue, 16 Apr 2024 19:20:18 +0800 Subject: [PATCH 26/26] doc:update readme --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 81894d1..1c44ce0 100644 --- a/README.md +++ b/README.md @@ -135,10 +135,6 @@ Environment installation configuration (2)After installation, when creating a new data source connection, select Hive at the address jdbc:hive2://ip:10000 - -#### Technological Communication -![image](https://user-images.githubusercontent.com/28300167/207255900-152d6834-9602-4ada-91ca-ad9906d89bf8.png) - #### Star History [![Star History Chart](https://api.star-history.com/svg?repos=zhugezifang/dataCompare&type=Date)](https://star-history.com/#zhugezifang/dataCompare&Date)