getActiveSessions()
+ {
+ throw new UnsupportedOperationException("getActiveSessions method not supported");
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java
new file mode 100644
index 0000000..32c74e4
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/shiro/web/session/SpringSessionValidationScheduler.java
@@ -0,0 +1,131 @@
+package com.playlet.framework.shiro.web.session;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import org.apache.shiro.session.mgt.DefaultSessionManager;
+import org.apache.shiro.session.mgt.SessionValidationScheduler;
+import org.apache.shiro.session.mgt.ValidatingSessionManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Component;
+import com.playlet.common.utils.Threads;
+
+/**
+ * 自定义任务调度器完成
+ *
+ * @author ruoyi
+ */
+@Component
+public class SpringSessionValidationScheduler implements SessionValidationScheduler
+{
+ private static final Logger log = LoggerFactory.getLogger(SpringSessionValidationScheduler.class);
+
+ public static final long DEFAULT_SESSION_VALIDATION_INTERVAL = DefaultSessionManager.DEFAULT_SESSION_VALIDATION_INTERVAL;
+
+ /**
+ * 定时器,用于处理超时的挂起请求,也用于连接断开时的重连。
+ */
+ @Autowired
+ @Qualifier("scheduledExecutorService")
+ private ScheduledExecutorService executorService;
+
+ private volatile boolean enabled = false;
+
+ /**
+ * 会话验证管理器
+ */
+ @Autowired
+ @Qualifier("sessionManager")
+ @Lazy
+ private ValidatingSessionManager sessionManager;
+
+ // 相隔多久检查一次session的有效性,单位毫秒,默认就是10分钟
+ @Value("${shiro.session.validationInterval}")
+ private long sessionValidationInterval;
+
+ @Override
+ public boolean isEnabled()
+ {
+ return this.enabled;
+ }
+
+ /**
+ * Specifies how frequently (in milliseconds) this Scheduler will call the
+ * {@link org.apache.shiro.session.mgt.ValidatingSessionManager#validateSessions()
+ * ValidatingSessionManager#validateSessions()} method.
+ *
+ *
+ * Unless this method is called, the default value is {@link #DEFAULT_SESSION_VALIDATION_INTERVAL}.
+ *
+ * @param sessionValidationInterval
+ */
+ public void setSessionValidationInterval(long sessionValidationInterval)
+ {
+ this.sessionValidationInterval = sessionValidationInterval;
+ }
+
+ /**
+ * Starts session validation by creating a spring PeriodicTrigger.
+ */
+ @Override
+ public void enableSessionValidation()
+ {
+
+ enabled = true;
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("Scheduling session validation job using Spring Scheduler with "
+ + "session validation interval of [" + sessionValidationInterval + "]ms...");
+ }
+
+ try
+ {
+ executorService.scheduleAtFixedRate(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if (enabled)
+ {
+ sessionManager.validateSessions();
+ }
+ }
+ }, 1000, sessionValidationInterval * 60 * 1000, TimeUnit.MILLISECONDS);
+
+ this.enabled = true;
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("Session validation job successfully scheduled with Spring Scheduler.");
+ }
+
+ }
+ catch (Exception e)
+ {
+ if (log.isErrorEnabled())
+ {
+ log.error("Error starting the Spring Scheduler session validation job. Session validation may not occur.", e);
+ }
+ }
+ }
+
+ @Override
+ public void disableSessionValidation()
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("Stopping Spring Scheduler session validation job...");
+ }
+
+ if (this.enabled)
+ {
+ Threads.shutdownAndAwaitTermination(executorService);
+ }
+ this.enabled = false;
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java
new file mode 100644
index 0000000..0893564
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/Server.java
@@ -0,0 +1,241 @@
+package com.playlet.framework.web.domain;
+
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import com.playlet.common.utils.Arith;
+import com.playlet.common.utils.IpUtils;
+import com.playlet.framework.web.domain.server.Cpu;
+import com.playlet.framework.web.domain.server.Jvm;
+import com.playlet.framework.web.domain.server.Mem;
+import com.playlet.framework.web.domain.server.Sys;
+import com.playlet.framework.web.domain.server.SysFile;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.CentralProcessor.TickType;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.util.Util;
+
+/**
+ * 服务器相关信息
+ *
+ * @author ruoyi
+ */
+public class Server
+{
+
+ private static final int OSHI_WAIT_SECOND = 1000;
+
+ /**
+ * CPU相关信息
+ */
+ private Cpu cpu = new Cpu();
+
+ /**
+ * 內存相关信息
+ */
+ private Mem mem = new Mem();
+
+ /**
+ * JVM相关信息
+ */
+ private Jvm jvm = new Jvm();
+
+ /**
+ * 服务器相关信息
+ */
+ private Sys sys = new Sys();
+
+ /**
+ * 磁盘相关信息
+ */
+ private List sysFiles = new LinkedList();
+
+ public Cpu getCpu()
+ {
+ return cpu;
+ }
+
+ public void setCpu(Cpu cpu)
+ {
+ this.cpu = cpu;
+ }
+
+ public Mem getMem()
+ {
+ return mem;
+ }
+
+ public void setMem(Mem mem)
+ {
+ this.mem = mem;
+ }
+
+ public Jvm getJvm()
+ {
+ return jvm;
+ }
+
+ public void setJvm(Jvm jvm)
+ {
+ this.jvm = jvm;
+ }
+
+ public Sys getSys()
+ {
+ return sys;
+ }
+
+ public void setSys(Sys sys)
+ {
+ this.sys = sys;
+ }
+
+ public List getSysFiles()
+ {
+ return sysFiles;
+ }
+
+ public void setSysFiles(List sysFiles)
+ {
+ this.sysFiles = sysFiles;
+ }
+
+ public void copyTo() throws Exception
+ {
+ SystemInfo si = new SystemInfo();
+ HardwareAbstractionLayer hal = si.getHardware();
+
+ setCpuInfo(hal.getProcessor());
+
+ setMemInfo(hal.getMemory());
+
+ setSysInfo();
+
+ setJvmInfo();
+
+ setSysFiles(si.getOperatingSystem());
+ }
+
+ /**
+ * 设置CPU信息
+ */
+ private void setCpuInfo(CentralProcessor processor)
+ {
+ // CPU信息
+ long[] prevTicks = processor.getSystemCpuLoadTicks();
+ Util.sleep(OSHI_WAIT_SECOND);
+ long[] ticks = processor.getSystemCpuLoadTicks();
+ long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
+ long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
+ long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
+ long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
+ long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
+ long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
+ long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
+ long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
+ long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
+ cpu.setCpuNum(processor.getLogicalProcessorCount());
+ cpu.setTotal(totalCpu);
+ cpu.setSys(cSys);
+ cpu.setUsed(user);
+ cpu.setWait(iowait);
+ cpu.setFree(idle);
+ }
+
+ /**
+ * 设置内存信息
+ */
+ private void setMemInfo(GlobalMemory memory)
+ {
+ mem.setTotal(memory.getTotal());
+ mem.setUsed(memory.getTotal() - memory.getAvailable());
+ mem.setFree(memory.getAvailable());
+ }
+
+ /**
+ * 设置服务器信息
+ */
+ private void setSysInfo()
+ {
+ Properties props = System.getProperties();
+ sys.setComputerName(IpUtils.getHostName());
+ sys.setComputerIp(IpUtils.getHostIp());
+ sys.setOsName(props.getProperty("os.name"));
+ sys.setOsArch(props.getProperty("os.arch"));
+ sys.setUserDir(props.getProperty("user.dir"));
+ }
+
+ /**
+ * 设置Java虚拟机
+ */
+ private void setJvmInfo() throws UnknownHostException
+ {
+ Properties props = System.getProperties();
+ jvm.setTotal(Runtime.getRuntime().totalMemory());
+ jvm.setMax(Runtime.getRuntime().maxMemory());
+ jvm.setFree(Runtime.getRuntime().freeMemory());
+ jvm.setVersion(props.getProperty("java.version"));
+ jvm.setHome(props.getProperty("java.home"));
+ }
+
+ /**
+ * 设置磁盘信息
+ */
+ private void setSysFiles(OperatingSystem os)
+ {
+ FileSystem fileSystem = os.getFileSystem();
+ List fsArray = fileSystem.getFileStores();
+ for (OSFileStore fs : fsArray)
+ {
+ long free = fs.getUsableSpace();
+ long total = fs.getTotalSpace();
+ long used = total - free;
+ SysFile sysFile = new SysFile();
+ sysFile.setDirName(fs.getMount());
+ sysFile.setSysTypeName(fs.getType());
+ sysFile.setTypeName(fs.getName());
+ sysFile.setTotal(convertFileSize(total));
+ sysFile.setFree(convertFileSize(free));
+ sysFile.setUsed(convertFileSize(used));
+ sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
+ sysFiles.add(sysFile);
+ }
+ }
+
+ /**
+ * 字节转换
+ *
+ * @param size 字节大小
+ * @return 转换后值
+ */
+ public String convertFileSize(long size)
+ {
+ long kb = 1024;
+ long mb = kb * 1024;
+ long gb = mb * 1024;
+ if (size >= gb)
+ {
+ return String.format("%.1f GB", (float) size / gb);
+ }
+ else if (size >= mb)
+ {
+ float f = (float) size / mb;
+ return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
+ }
+ else if (size >= kb)
+ {
+ float f = (float) size / kb;
+ return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
+ }
+ else
+ {
+ return String.format("%d B", size);
+ }
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java
new file mode 100644
index 0000000..a93c8b4
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Cpu.java
@@ -0,0 +1,101 @@
+package com.playlet.framework.web.domain.server;
+
+import com.playlet.common.utils.Arith;
+
+/**
+ * CPU相关信息
+ *
+ * @author ruoyi
+ */
+public class Cpu
+{
+ /**
+ * 核心数
+ */
+ private int cpuNum;
+
+ /**
+ * CPU总的使用率
+ */
+ private double total;
+
+ /**
+ * CPU系统使用率
+ */
+ private double sys;
+
+ /**
+ * CPU用户使用率
+ */
+ private double used;
+
+ /**
+ * CPU当前等待率
+ */
+ private double wait;
+
+ /**
+ * CPU当前空闲率
+ */
+ private double free;
+
+ public int getCpuNum()
+ {
+ return cpuNum;
+ }
+
+ public void setCpuNum(int cpuNum)
+ {
+ this.cpuNum = cpuNum;
+ }
+
+ public double getTotal()
+ {
+ return Arith.round(Arith.mul(total, 100), 2);
+ }
+
+ public void setTotal(double total)
+ {
+ this.total = total;
+ }
+
+ public double getSys()
+ {
+ return Arith.round(Arith.mul(sys / total, 100), 2);
+ }
+
+ public void setSys(double sys)
+ {
+ this.sys = sys;
+ }
+
+ public double getUsed()
+ {
+ return Arith.round(Arith.mul(used / total, 100), 2);
+ }
+
+ public void setUsed(double used)
+ {
+ this.used = used;
+ }
+
+ public double getWait()
+ {
+ return Arith.round(Arith.mul(wait / total, 100), 2);
+ }
+
+ public void setWait(double wait)
+ {
+ this.wait = wait;
+ }
+
+ public double getFree()
+ {
+ return Arith.round(Arith.mul(free / total, 100), 2);
+ }
+
+ public void setFree(double free)
+ {
+ this.free = free;
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java
new file mode 100644
index 0000000..5e107a4
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Jvm.java
@@ -0,0 +1,130 @@
+package com.playlet.framework.web.domain.server;
+
+import java.lang.management.ManagementFactory;
+import com.playlet.common.utils.Arith;
+import com.playlet.common.utils.DateUtils;
+
+/**
+ * JVM相关信息
+ *
+ * @author ruoyi
+ */
+public class Jvm
+{
+ /**
+ * 当前JVM占用的内存总数(M)
+ */
+ private double total;
+
+ /**
+ * JVM最大可用内存总数(M)
+ */
+ private double max;
+
+ /**
+ * JVM空闲内存(M)
+ */
+ private double free;
+
+ /**
+ * JDK版本
+ */
+ private String version;
+
+ /**
+ * JDK路径
+ */
+ private String home;
+
+ public double getTotal()
+ {
+ return Arith.div(total, (1024 * 1024), 2);
+ }
+
+ public void setTotal(double total)
+ {
+ this.total = total;
+ }
+
+ public double getMax()
+ {
+ return Arith.div(max, (1024 * 1024), 2);
+ }
+
+ public void setMax(double max)
+ {
+ this.max = max;
+ }
+
+ public double getFree()
+ {
+ return Arith.div(free, (1024 * 1024), 2);
+ }
+
+ public void setFree(double free)
+ {
+ this.free = free;
+ }
+
+ public double getUsed()
+ {
+ return Arith.div(total - free, (1024 * 1024), 2);
+ }
+
+ public double getUsage()
+ {
+ return Arith.mul(Arith.div(total - free, total, 4), 100);
+ }
+
+ /**
+ * 获取JDK名称
+ */
+ public String getName()
+ {
+ return ManagementFactory.getRuntimeMXBean().getVmName();
+ }
+
+ public String getVersion()
+ {
+ return version;
+ }
+
+ public void setVersion(String version)
+ {
+ this.version = version;
+ }
+
+ public String getHome()
+ {
+ return home;
+ }
+
+ public void setHome(String home)
+ {
+ this.home = home;
+ }
+
+ /**
+ * JDK启动时间
+ */
+ public String getStartTime()
+ {
+ return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
+ }
+
+ /**
+ * JDK运行时间
+ */
+ public String getRunTime()
+ {
+ return DateUtils.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());
+ }
+
+ /**
+ * 运行参数
+ */
+ public String getInputArgs()
+ {
+ return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java
new file mode 100644
index 0000000..cd20f94
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Mem.java
@@ -0,0 +1,61 @@
+package com.playlet.framework.web.domain.server;
+
+import com.playlet.common.utils.Arith;
+
+/**
+ * 內存相关信息
+ *
+ * @author ruoyi
+ */
+public class Mem
+{
+ /**
+ * 内存总量
+ */
+ private double total;
+
+ /**
+ * 已用内存
+ */
+ private double used;
+
+ /**
+ * 剩余内存
+ */
+ private double free;
+
+ public double getTotal()
+ {
+ return Arith.div(total, (1024 * 1024 * 1024), 2);
+ }
+
+ public void setTotal(long total)
+ {
+ this.total = total;
+ }
+
+ public double getUsed()
+ {
+ return Arith.div(used, (1024 * 1024 * 1024), 2);
+ }
+
+ public void setUsed(long used)
+ {
+ this.used = used;
+ }
+
+ public double getFree()
+ {
+ return Arith.div(free, (1024 * 1024 * 1024), 2);
+ }
+
+ public void setFree(long free)
+ {
+ this.free = free;
+ }
+
+ public double getUsage()
+ {
+ return Arith.mul(Arith.div(used, total, 4), 100);
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java
new file mode 100644
index 0000000..cc0ef90
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/Sys.java
@@ -0,0 +1,84 @@
+package com.playlet.framework.web.domain.server;
+
+/**
+ * 系统相关信息
+ *
+ * @author ruoyi
+ */
+public class Sys
+{
+ /**
+ * 服务器名称
+ */
+ private String computerName;
+
+ /**
+ * 服务器Ip
+ */
+ private String computerIp;
+
+ /**
+ * 项目路径
+ */
+ private String userDir;
+
+ /**
+ * 操作系统
+ */
+ private String osName;
+
+ /**
+ * 系统架构
+ */
+ private String osArch;
+
+ public String getComputerName()
+ {
+ return computerName;
+ }
+
+ public void setComputerName(String computerName)
+ {
+ this.computerName = computerName;
+ }
+
+ public String getComputerIp()
+ {
+ return computerIp;
+ }
+
+ public void setComputerIp(String computerIp)
+ {
+ this.computerIp = computerIp;
+ }
+
+ public String getUserDir()
+ {
+ return userDir;
+ }
+
+ public void setUserDir(String userDir)
+ {
+ this.userDir = userDir;
+ }
+
+ public String getOsName()
+ {
+ return osName;
+ }
+
+ public void setOsName(String osName)
+ {
+ this.osName = osName;
+ }
+
+ public String getOsArch()
+ {
+ return osArch;
+ }
+
+ public void setOsArch(String osArch)
+ {
+ this.osArch = osArch;
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java
new file mode 100644
index 0000000..ecf007b
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/domain/server/SysFile.java
@@ -0,0 +1,114 @@
+package com.playlet.framework.web.domain.server;
+
+/**
+ * 系统文件相关信息
+ *
+ * @author ruoyi
+ */
+public class SysFile
+{
+ /**
+ * 盘符路径
+ */
+ private String dirName;
+
+ /**
+ * 盘符类型
+ */
+ private String sysTypeName;
+
+ /**
+ * 文件类型
+ */
+ private String typeName;
+
+ /**
+ * 总大小
+ */
+ private String total;
+
+ /**
+ * 剩余大小
+ */
+ private String free;
+
+ /**
+ * 已经使用量
+ */
+ private String used;
+
+ /**
+ * 资源的使用率
+ */
+ private double usage;
+
+ public String getDirName()
+ {
+ return dirName;
+ }
+
+ public void setDirName(String dirName)
+ {
+ this.dirName = dirName;
+ }
+
+ public String getSysTypeName()
+ {
+ return sysTypeName;
+ }
+
+ public void setSysTypeName(String sysTypeName)
+ {
+ this.sysTypeName = sysTypeName;
+ }
+
+ public String getTypeName()
+ {
+ return typeName;
+ }
+
+ public void setTypeName(String typeName)
+ {
+ this.typeName = typeName;
+ }
+
+ public String getTotal()
+ {
+ return total;
+ }
+
+ public void setTotal(String total)
+ {
+ this.total = total;
+ }
+
+ public String getFree()
+ {
+ return free;
+ }
+
+ public void setFree(String free)
+ {
+ this.free = free;
+ }
+
+ public String getUsed()
+ {
+ return used;
+ }
+
+ public void setUsed(String used)
+ {
+ this.used = used;
+ }
+
+ public double getUsage()
+ {
+ return usage;
+ }
+
+ public void setUsage(double usage)
+ {
+ this.usage = usage;
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java b/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..32b5d78
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/exception/GlobalExceptionHandler.java
@@ -0,0 +1,141 @@
+package com.playlet.framework.web.exception;
+
+import javax.servlet.http.HttpServletRequest;
+import org.apache.shiro.authz.AuthorizationException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import org.springframework.web.servlet.ModelAndView;
+import com.playlet.common.core.domain.AjaxResult;
+import com.playlet.common.exception.DemoModeException;
+import com.playlet.common.exception.ServiceException;
+import com.playlet.common.utils.ServletUtils;
+import com.playlet.common.utils.security.PermissionUtils;
+
+/**
+ * 全局异常处理器
+ *
+ * @author ruoyi
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler
+{
+ private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+ /**
+ * 权限校验异常(ajax请求返回json,redirect请求跳转页面)
+ */
+ @ExceptionHandler(AuthorizationException.class)
+ public Object handleAuthorizationException(AuthorizationException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
+ if (ServletUtils.isAjaxRequest(request))
+ {
+ return AjaxResult.error(PermissionUtils.getMsg(e.getMessage()));
+ }
+ else
+ {
+ return new ModelAndView("error/unauth");
+ }
+ }
+
+ /**
+ * 请求方式不支持
+ */
+ @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+ public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+ HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 拦截未知的运行时异常
+ */
+ @ExceptionHandler(RuntimeException.class)
+ public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',发生未知异常.", requestURI, e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 系统异常
+ */
+ @ExceptionHandler(Exception.class)
+ public AjaxResult handleException(Exception e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求地址'{}',发生系统异常.", requestURI, e);
+ return AjaxResult.error(e.getMessage());
+ }
+
+ /**
+ * 业务异常
+ */
+ @ExceptionHandler(ServiceException.class)
+ public Object handleServiceException(ServiceException e, HttpServletRequest request)
+ {
+ log.error(e.getMessage(), e);
+ if (ServletUtils.isAjaxRequest(request))
+ {
+ return AjaxResult.error(e.getMessage());
+ }
+ else
+ {
+ return new ModelAndView("error/service", "errorMessage", e.getMessage());
+ }
+ }
+
+ /**
+ * 请求路径中缺少必需的路径变量
+ */
+ @ExceptionHandler(MissingPathVariableException.class)
+ public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
+ return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
+ }
+
+ /**
+ * 请求参数类型不匹配
+ */
+ @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+ public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e,
+ HttpServletRequest request)
+ {
+ String requestURI = request.getRequestURI();
+ log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
+ return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
+ }
+
+ /**
+ * 自定义验证异常
+ */
+ @ExceptionHandler(BindException.class)
+ public AjaxResult handleBindException(BindException e)
+ {
+ log.error(e.getMessage(), e);
+ String message = e.getAllErrors().get(0).getDefaultMessage();
+ return AjaxResult.error(message);
+ }
+
+ /**
+ * 演示模式异常
+ */
+ @ExceptionHandler(DemoModeException.class)
+ public AjaxResult handleDemoModeException(DemoModeException e)
+ {
+ return AjaxResult.error("演示模式,不允许操作");
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java
new file mode 100644
index 0000000..983e392
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/CacheService.java
@@ -0,0 +1,83 @@
+package com.playlet.framework.web.service;
+
+import java.util.Set;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.stereotype.Service;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.utils.CacheUtils;
+
+/**
+ * 缓存操作处理
+ *
+ * @author ruoyi
+ */
+@Service
+public class CacheService
+{
+ /**
+ * 获取所有缓存名称
+ *
+ * @return 缓存列表
+ */
+ public String[] getCacheNames()
+ {
+ String[] cacheNames = CacheUtils.getCacheNames();
+ return ArrayUtils.removeElement(cacheNames, Constants.SYS_AUTH_CACHE);
+ }
+
+ /**
+ * 根据缓存名称获取所有键名
+ *
+ * @param cacheName 缓存名称
+ * @return 键名列表
+ */
+ public Set getCacheKeys(String cacheName)
+ {
+ return CacheUtils.getCache(cacheName).keys();
+ }
+
+ /**
+ * 根据缓存名称和键名获取内容值
+ *
+ * @param cacheName 缓存名称
+ * @param cacheKey 键名
+ * @return 键值
+ */
+ public Object getCacheValue(String cacheName, String cacheKey)
+ {
+ return CacheUtils.get(cacheName, cacheKey);
+ }
+
+ /**
+ * 根据名称删除缓存信息
+ *
+ * @param cacheName 缓存名称
+ */
+ public void clearCacheName(String cacheName)
+ {
+ CacheUtils.removeAll(cacheName);
+ }
+
+ /**
+ * 根据名称和键名删除缓存信息
+ *
+ * @param cacheName 缓存名称
+ * @param cacheKey 键名
+ */
+ public void clearCacheKey(String cacheName, String cacheKey)
+ {
+ CacheUtils.remove(cacheName, cacheKey);
+ }
+
+ /**
+ * 清理所有缓存
+ */
+ public void clearAll()
+ {
+ String[] cacheNames = getCacheNames();
+ for (String cacheName : cacheNames)
+ {
+ CacheUtils.removeAll(cacheName);
+ }
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java
new file mode 100644
index 0000000..340ff64
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/ConfigService.java
@@ -0,0 +1,28 @@
+package com.playlet.framework.web.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.system.service.ISysConfigService;
+
+/**
+ * RuoYi首创 html调用 thymeleaf 实现参数管理
+ *
+ * @author ruoyi
+ */
+@Service("config")
+public class ConfigService
+{
+ @Autowired
+ private ISysConfigService configService;
+
+ /**
+ * 根据键名查询参数配置信息
+ *
+ * @param configKey 参数键名
+ * @return 参数键值
+ */
+ public String getKey(String configKey)
+ {
+ return configService.selectConfigByKey(configKey);
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java
new file mode 100644
index 0000000..8e36188
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/DictService.java
@@ -0,0 +1,46 @@
+package com.playlet.framework.web.service;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.core.domain.entity.SysDictData;
+import com.playlet.system.service.ISysDictDataService;
+import com.playlet.system.service.ISysDictTypeService;
+
+/**
+ * RuoYi首创 html调用 thymeleaf 实现字典读取
+ *
+ * @author ruoyi
+ */
+@Service("dict")
+public class DictService
+{
+ @Autowired
+ private ISysDictTypeService dictTypeService;
+
+ @Autowired
+ private ISysDictDataService dictDataService;
+
+ /**
+ * 根据字典类型查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @return 参数键值
+ */
+ public List getType(String dictType)
+ {
+ return dictTypeService.selectDictDataByType(dictType);
+ }
+
+ /**
+ * 根据字典类型和字典键值查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典键值
+ * @return 字典标签
+ */
+ public String getLabel(String dictType, String dictValue)
+ {
+ return dictDataService.selectDictLabel(dictType, dictValue);
+ }
+}
diff --git a/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java b/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java
new file mode 100644
index 0000000..2689d14
--- /dev/null
+++ b/playlet-framework/src/main/java/com/playlet/framework/web/service/PermissionService.java
@@ -0,0 +1,262 @@
+package com.playlet.framework.web.service;
+
+import java.beans.BeanInfo;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import org.apache.shiro.SecurityUtils;
+import org.apache.shiro.subject.Subject;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import com.playlet.common.utils.StringUtils;
+
+/**
+ * RuoYi首创 js调用 thymeleaf 实现按钮权限可见性
+ *
+ * @author ruoyi
+ */
+@Service("permission")
+public class PermissionService
+{
+ private static final Logger log = LoggerFactory.getLogger(PermissionService.class);
+
+ /** 没有权限,hidden用于前端隐藏按钮 */
+ public static final String NOACCESS = "hidden";
+
+ private static final String ROLE_DELIMETER = ",";
+
+ private static final String PERMISSION_DELIMETER = ",";
+
+ /**
+ * 验证用户是否具备某权限,无权限返回hidden用于前端隐藏(如需返回Boolean使用isPermitted)
+ *
+ * @param permission 权限字符串
+ * @return 用户是否具备某权限
+ */
+ public String hasPermi(String permission)
+ {
+ return isPermitted(permission) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否不具备某权限,与 hasPermi逻辑相反。无权限返回hidden用于前端隐藏(如需返回Boolean使用isLacksPermitted)
+ *
+ * @param permission 权限字符串
+ * @return 用户是否不具备某权限
+ */
+ public String lacksPermi(String permission)
+ {
+ return isLacksPermitted(permission) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个权限,无权限返回hidden用于隐藏(如需返回Boolean使用hasAnyPermissions)
+ *
+ * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
+ * @return 用户是否具有以下任意一个权限
+ */
+ public String hasAnyPermi(String permissions)
+ {
+ return hasAnyPermissions(permissions, PERMISSION_DELIMETER) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否具备某角色,无权限返回hidden用于隐藏(如需返回Boolean使用isRole)
+ *
+ * @param role 角色字符串
+ * @return 用户是否具备某角色
+ */
+ public String hasRole(String role)
+ {
+ return isRole(role) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否不具备某角色,与hasRole逻辑相反。无权限返回hidden用于隐藏(如需返回Boolean使用isLacksRole)
+ *
+ * @param role 角色字符串
+ * @return 用户是否不具备某角色
+ */
+ public String lacksRole(String role)
+ {
+ return isLacksRole(role) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个角色,无权限返回hidden用于隐藏(如需返回Boolean使用isAnyRoles)
+ *
+ * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
+ * @return 用户是否具有以下任意一个角色
+ */
+ public String hasAnyRoles(String roles)
+ {
+ return isAnyRoles(roles, ROLE_DELIMETER) ? StringUtils.EMPTY : NOACCESS;
+ }
+
+ /**
+ * 验证用户是否认证通过或已记住的用户。
+ *
+ * @return 用户是否认证通过或已记住的用户
+ */
+ public boolean isUser()
+ {
+ Subject subject = SecurityUtils.getSubject();
+ return subject != null && subject.getPrincipal() != null;
+ }
+
+ /**
+ * 判断用户是否拥有某个权限
+ *
+ * @param permission 权限字符串
+ * @return 用户是否具备某权限
+ */
+ public boolean isPermitted(String permission)
+ {
+ return SecurityUtils.getSubject().isPermitted(permission);
+ }
+
+ /**
+ * 判断用户是否不具备某权限,与 isPermitted逻辑相反。
+ *
+ * @param permission 权限名称
+ * @return 用户是否不具备某权限
+ */
+ public boolean isLacksPermitted(String permission)
+ {
+ return isPermitted(permission) != true;
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个权限。
+ *
+ * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
+ * @return 用户是否具有以下任意一个权限
+ */
+ public boolean hasAnyPermissions(String permissions)
+ {
+ return hasAnyPermissions(permissions, PERMISSION_DELIMETER);
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个权限。
+ *
+ * @param permissions 以 delimeter 为分隔符的权限列表
+ * @param delimeter 权限列表分隔符
+ * @return 用户是否具有以下任意一个权限
+ */
+ public boolean hasAnyPermissions(String permissions, String delimeter)
+ {
+ Subject subject = SecurityUtils.getSubject();
+
+ if (subject != null)
+ {
+ if (delimeter == null || delimeter.length() == 0)
+ {
+ delimeter = PERMISSION_DELIMETER;
+ }
+
+ for (String permission : permissions.split(delimeter))
+ {
+ if (permission != null && subject.isPermitted(permission.trim()) == true)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 判断用户是否拥有某个角色
+ *
+ * @param role 角色字符串
+ * @return 用户是否具备某角色
+ */
+ public boolean isRole(String role)
+ {
+ return SecurityUtils.getSubject().hasRole(role);
+ }
+
+ /**
+ * 验证用户是否不具备某角色,与 isRole逻辑相反。
+ *
+ * @param role 角色名称
+ * @return 用户是否不具备某角色
+ */
+ public boolean isLacksRole(String role)
+ {
+ return isRole(role) != true;
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个角色。
+ *
+ * @param roles 以 ROLE_NAMES_DELIMETER 为分隔符的角色列表
+ * @return 用户是否具有以下任意一个角色
+ */
+ public boolean isAnyRoles(String roles)
+ {
+ return isAnyRoles(roles, ROLE_DELIMETER);
+ }
+
+ /**
+ * 验证用户是否具有以下任意一个角色。
+ *
+ * @param roles 以 delimeter 为分隔符的角色列表
+ * @param delimeter 角色列表分隔符
+ * @return 用户是否具有以下任意一个角色
+ */
+ public boolean isAnyRoles(String roles, String delimeter)
+ {
+ Subject subject = SecurityUtils.getSubject();
+ if (subject != null)
+ {
+ if (delimeter == null || delimeter.length() == 0)
+ {
+ delimeter = ROLE_DELIMETER;
+ }
+
+ for (String role : roles.split(delimeter))
+ {
+ if (subject.hasRole(role.trim()) == true)
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * 返回用户属性值
+ *
+ * @param property 属性名称
+ * @return 用户属性值
+ */
+ public Object getPrincipalProperty(String property)
+ {
+ Subject subject = SecurityUtils.getSubject();
+ if (subject != null)
+ {
+ Object principal = subject.getPrincipal();
+ try
+ {
+ BeanInfo bi = Introspector.getBeanInfo(principal.getClass());
+ for (PropertyDescriptor pd : bi.getPropertyDescriptors())
+ {
+ if (pd.getName().equals(property) == true)
+ {
+ return pd.getReadMethod().invoke(principal, (Object[]) null);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ log.error("Error reading property [{}] from principal of type [{}]", property, principal.getClass().getName());
+ }
+ }
+ return null;
+ }
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java b/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java
new file mode 100644
index 0000000..d27dfb5
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/config/GenConfig.java
@@ -0,0 +1,73 @@
+package com.playlet.generator.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取代码生成相关配置
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "gen")
+@PropertySource(value = { "classpath:generator.yml" })
+public class GenConfig
+{
+ /** 作者 */
+ public static String author;
+
+ /** 生成包路径 */
+ public static String packageName;
+
+ /** 自动去除表前缀,默认是false */
+ public static boolean autoRemovePre;
+
+ /** 表前缀(类名不会包含表前缀) */
+ public static String tablePrefix;
+
+ public static String getAuthor()
+ {
+ return author;
+ }
+
+ @Value("${author}")
+ public void setAuthor(String author)
+ {
+ GenConfig.author = author;
+ }
+
+ public static String getPackageName()
+ {
+ return packageName;
+ }
+
+ @Value("${packageName}")
+ public void setPackageName(String packageName)
+ {
+ GenConfig.packageName = packageName;
+ }
+
+ public static boolean getAutoRemovePre()
+ {
+ return autoRemovePre;
+ }
+
+ @Value("${autoRemovePre}")
+ public void setAutoRemovePre(boolean autoRemovePre)
+ {
+ GenConfig.autoRemovePre = autoRemovePre;
+ }
+
+ public static String getTablePrefix()
+ {
+ return tablePrefix;
+ }
+
+ @Value("${tablePrefix}")
+ public void setTablePrefix(String tablePrefix)
+ {
+ GenConfig.tablePrefix = tablePrefix;
+ }
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java b/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java
new file mode 100644
index 0000000..4819f79
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/controller/GenController.java
@@ -0,0 +1,304 @@
+package com.playlet.generator.controller;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.apache.shiro.authz.annotation.RequiresRoles;
+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.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import com.alibaba.druid.DbType;
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
+import com.alibaba.fastjson.JSON;
+import com.playlet.common.annotation.Log;
+import com.playlet.common.core.controller.BaseController;
+import com.playlet.common.core.domain.AjaxResult;
+import com.playlet.common.core.domain.CxSelect;
+import com.playlet.common.core.page.TableDataInfo;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.enums.BusinessType;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.security.PermissionUtils;
+import com.playlet.common.utils.sql.SqlUtil;
+import com.playlet.generator.domain.GenTable;
+import com.playlet.generator.domain.GenTableColumn;
+import com.playlet.generator.service.IGenTableColumnService;
+import com.playlet.generator.service.IGenTableService;
+
+/**
+ * 代码生成 操作处理
+ *
+ * @author ruoyi
+ */
+@Controller
+@RequestMapping("/tool/gen")
+public class GenController extends BaseController
+{
+ private String prefix = "tool/gen";
+
+ @Autowired
+ private IGenTableService genTableService;
+
+ @Autowired
+ private IGenTableColumnService genTableColumnService;
+
+ @RequiresPermissions("tool:gen:view")
+ @GetMapping()
+ public String gen()
+ {
+ return prefix + "/gen";
+ }
+
+ /**
+ * 查询代码生成列表
+ */
+ @RequiresPermissions("tool:gen:list")
+ @PostMapping("/list")
+ @ResponseBody
+ public TableDataInfo genList(GenTable genTable)
+ {
+ startPage();
+ List list = genTableService.selectGenTableList(genTable);
+ return getDataTable(list);
+ }
+
+ /**
+ * 查询数据库列表
+ */
+ @RequiresPermissions("tool:gen:list")
+ @PostMapping("/db/list")
+ @ResponseBody
+ public TableDataInfo dataList(GenTable genTable)
+ {
+ startPage();
+ List list = genTableService.selectDbTableList(genTable);
+ return getDataTable(list);
+ }
+
+ /**
+ * 查询数据表字段列表
+ */
+ @RequiresPermissions("tool:gen:list")
+ @PostMapping("/column/list")
+ @ResponseBody
+ public TableDataInfo columnList(GenTableColumn genTableColumn)
+ {
+ TableDataInfo dataInfo = new TableDataInfo();
+ List list = genTableColumnService.selectGenTableColumnListByTableId(genTableColumn);
+ dataInfo.setRows(list);
+ dataInfo.setTotal(list.size());
+ return dataInfo;
+ }
+
+ /**
+ * 导入表结构
+ */
+ @RequiresPermissions("tool:gen:list")
+ @GetMapping("/importTable")
+ public String importTable()
+ {
+ return prefix + "/importTable";
+ }
+
+ /**
+ * 创建表结构
+ */
+ @GetMapping("/createTable")
+ public String createTable()
+ {
+ return prefix + "/createTable";
+ }
+
+ /**
+ * 导入表结构(保存)
+ */
+ @RequiresPermissions("tool:gen:list")
+ @Log(title = "代码生成", businessType = BusinessType.IMPORT)
+ @PostMapping("/importTable")
+ @ResponseBody
+ public AjaxResult importTableSave(String tables)
+ {
+ String[] tableNames = Convert.toStrArray(tables);
+ // 查询表信息
+ List tableList = genTableService.selectDbTableListByNames(tableNames);
+ String operName = Convert.toStr(PermissionUtils.getPrincipalProperty("loginName"));
+ genTableService.importGenTable(tableList, operName);
+ return AjaxResult.success();
+ }
+
+ /**
+ * 修改代码生成业务
+ */
+ @RequiresPermissions("tool:gen:edit")
+ @GetMapping("/edit/{tableId}")
+ public String edit(@PathVariable("tableId") Long tableId, ModelMap mmap)
+ {
+ GenTable table = genTableService.selectGenTableById(tableId);
+ List genTables = genTableService.selectGenTableAll();
+ List cxSelect = new ArrayList();
+ for (GenTable genTable : genTables)
+ {
+ if (!StringUtils.equals(table.getTableName(), genTable.getTableName()))
+ {
+ CxSelect cxTable = new CxSelect(genTable.getTableName(), genTable.getTableName() + ':' + genTable.getTableComment());
+ List cxColumns = new ArrayList();
+ for (GenTableColumn tableColumn : genTable.getColumns())
+ {
+ cxColumns.add(new CxSelect(tableColumn.getColumnName(), tableColumn.getColumnName() + ':' + tableColumn.getColumnComment()));
+ }
+ cxTable.setS(cxColumns);
+ cxSelect.add(cxTable);
+ }
+ }
+ mmap.put("table", table);
+ mmap.put("data", JSON.toJSON(cxSelect));
+ return prefix + "/edit";
+ }
+
+ /**
+ * 修改保存代码生成业务
+ */
+ @RequiresPermissions("tool:gen:edit")
+ @Log(title = "代码生成", businessType = BusinessType.UPDATE)
+ @PostMapping("/edit")
+ @ResponseBody
+ public AjaxResult editSave(@Validated GenTable genTable)
+ {
+ genTableService.validateEdit(genTable);
+ genTableService.updateGenTable(genTable);
+ return AjaxResult.success();
+ }
+
+ @RequiresPermissions("tool:gen:remove")
+ @Log(title = "代码生成", businessType = BusinessType.DELETE)
+ @PostMapping("/remove")
+ @ResponseBody
+ public AjaxResult remove(String ids)
+ {
+ genTableService.deleteGenTableByIds(ids);
+ return AjaxResult.success();
+ }
+
+ @RequiresRoles("admin")
+ @Log(title = "创建表", businessType = BusinessType.OTHER)
+ @PostMapping("/createTable")
+ @ResponseBody
+ public AjaxResult create(String sql)
+ {
+ try
+ {
+ SqlUtil.filterKeyword(sql);
+ List sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
+ List tableNames = new ArrayList<>();
+ for (SQLStatement sqlStatement : sqlStatements)
+ {
+ if (sqlStatement instanceof MySqlCreateTableStatement)
+ {
+ MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
+ if (genTableService.createTable(createTableStatement.toString()))
+ {
+ String tableName = createTableStatement.getTableName().replaceAll("`", "");
+ tableNames.add(tableName);
+ }
+ }
+ }
+ List tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
+ String operName = Convert.toStr(PermissionUtils.getPrincipalProperty("loginName"));
+ genTableService.importGenTable(tableList, operName);
+ return AjaxResult.success();
+ }
+ catch (Exception e)
+ {
+ logger.error(e.getMessage(), e);
+ return AjaxResult.error("创建表结构异常");
+ }
+ }
+
+ /**
+ * 预览代码
+ */
+ @RequiresPermissions("tool:gen:preview")
+ @GetMapping("/preview/{tableId}")
+ @ResponseBody
+ public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
+ {
+ Map dataMap = genTableService.previewCode(tableId);
+ return AjaxResult.success(dataMap);
+ }
+
+ /**
+ * 生成代码(下载方式)
+ */
+ @RequiresPermissions("tool:gen:code")
+ @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+ @GetMapping("/download/{tableName}")
+ public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
+ {
+ byte[] data = genTableService.downloadCode(tableName);
+ genCode(response, data);
+ }
+
+ /**
+ * 生成代码(自定义路径)
+ */
+ @RequiresPermissions("tool:gen:code")
+ @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+ @GetMapping("/genCode/{tableName}")
+ @ResponseBody
+ public AjaxResult genCode(@PathVariable("tableName") String tableName)
+ {
+ genTableService.generatorCode(tableName);
+ return AjaxResult.success();
+ }
+
+ /**
+ * 同步数据库
+ */
+ @RequiresPermissions("tool:gen:edit")
+ @Log(title = "代码生成", businessType = BusinessType.UPDATE)
+ @GetMapping("/synchDb/{tableName}")
+ @ResponseBody
+ public AjaxResult synchDb(@PathVariable("tableName") String tableName)
+ {
+ genTableService.synchDb(tableName);
+ return AjaxResult.success();
+ }
+
+ /**
+ * 批量生成代码
+ */
+ @RequiresPermissions("tool:gen:code")
+ @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+ @GetMapping("/batchGenCode")
+ @ResponseBody
+ public void batchGenCode(HttpServletResponse response, String tables) throws IOException
+ {
+ String[] tableNames = Convert.toStrArray(tables);
+ byte[] data = genTableService.downloadCode(tableNames);
+ genCode(response, data);
+ }
+
+ /**
+ * 生成zip文件
+ */
+ private void genCode(HttpServletResponse response, byte[] data) throws IOException
+ {
+ response.reset();
+ response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
+ response.addHeader("Content-Length", "" + data.length);
+ response.setContentType("application/octet-stream; charset=UTF-8");
+ IOUtils.write(data, response.getOutputStream());
+ }
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java
new file mode 100644
index 0000000..328ad23
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTable.java
@@ -0,0 +1,372 @@
+package com.playlet.generator.domain;
+
+import java.util.List;
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import org.apache.commons.lang3.ArrayUtils;
+import com.playlet.common.constant.GenConstants;
+import com.playlet.common.core.domain.BaseEntity;
+import com.playlet.common.utils.StringUtils;
+
+/**
+ * 业务表 gen_table
+ *
+ * @author ruoyi
+ */
+public class GenTable extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 编号 */
+ private Long tableId;
+
+ /** 表名称 */
+ @NotBlank(message = "表名称不能为空")
+ private String tableName;
+
+ /** 表描述 */
+ @NotBlank(message = "表描述不能为空")
+ private String tableComment;
+
+ /** 关联父表的表名 */
+ private String subTableName;
+
+ /** 本表关联父表的外键名 */
+ private String subTableFkName;
+
+ /** 实体类名称(首字母大写) */
+ @NotBlank(message = "实体类名称不能为空")
+ private String className;
+
+ /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */
+ private String tplCategory;
+
+ /** 生成包路径 */
+ @NotBlank(message = "生成包路径不能为空")
+ private String packageName;
+
+ /** 生成模块名 */
+ @NotBlank(message = "生成模块名不能为空")
+ private String moduleName;
+
+ /** 生成业务名 */
+ @NotBlank(message = "生成业务名不能为空")
+ private String businessName;
+
+ /** 生成功能名 */
+ @NotBlank(message = "生成功能名不能为空")
+ private String functionName;
+
+ /** 生成作者 */
+ @NotBlank(message = "作者不能为空")
+ private String functionAuthor;
+
+ /** 生成代码方式(0zip压缩包 1自定义路径) */
+ private String genType;
+
+ /** 生成路径(不填默认项目路径) */
+ private String genPath;
+
+ /** 主键信息 */
+ private GenTableColumn pkColumn;
+
+ /** 子表信息 */
+ private GenTable subTable;
+
+ /** 表列信息 */
+ @Valid
+ private List columns;
+
+ /** 其它生成选项 */
+ private String options;
+
+ /** 树编码字段 */
+ private String treeCode;
+
+ /** 树父编码字段 */
+ private String treeParentCode;
+
+ /** 树名称字段 */
+ private String treeName;
+
+ /** 上级菜单ID字段 */
+ private String parentMenuId;
+
+ /** 上级菜单名称字段 */
+ private String parentMenuName;
+
+ public Long getTableId()
+ {
+ return tableId;
+ }
+
+ public void setTableId(Long tableId)
+ {
+ this.tableId = tableId;
+ }
+
+ public String getTableName()
+ {
+ return tableName;
+ }
+
+ public void setTableName(String tableName)
+ {
+ this.tableName = tableName;
+ }
+
+ public String getTableComment()
+ {
+ return tableComment;
+ }
+
+ public void setTableComment(String tableComment)
+ {
+ this.tableComment = tableComment;
+ }
+
+ public String getSubTableName()
+ {
+ return subTableName;
+ }
+
+ public void setSubTableName(String subTableName)
+ {
+ this.subTableName = subTableName;
+ }
+
+ public String getSubTableFkName()
+ {
+ return subTableFkName;
+ }
+
+ public void setSubTableFkName(String subTableFkName)
+ {
+ this.subTableFkName = subTableFkName;
+ }
+
+ public String getClassName()
+ {
+ return className;
+ }
+
+ public void setClassName(String className)
+ {
+ this.className = className;
+ }
+
+ public String getTplCategory()
+ {
+ return tplCategory;
+ }
+
+ public void setTplCategory(String tplCategory)
+ {
+ this.tplCategory = tplCategory;
+ }
+
+ public String getPackageName()
+ {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName)
+ {
+ this.packageName = packageName;
+ }
+
+ public String getModuleName()
+ {
+ return moduleName;
+ }
+
+ public void setModuleName(String moduleName)
+ {
+ this.moduleName = moduleName;
+ }
+
+ public String getBusinessName()
+ {
+ return businessName;
+ }
+
+ public void setBusinessName(String businessName)
+ {
+ this.businessName = businessName;
+ }
+
+ public String getFunctionName()
+ {
+ return functionName;
+ }
+
+ public void setFunctionName(String functionName)
+ {
+ this.functionName = functionName;
+ }
+
+ public String getFunctionAuthor()
+ {
+ return functionAuthor;
+ }
+
+ public void setFunctionAuthor(String functionAuthor)
+ {
+ this.functionAuthor = functionAuthor;
+ }
+
+ public String getGenType()
+ {
+ return genType;
+ }
+
+ public void setGenType(String genType)
+ {
+ this.genType = genType;
+ }
+
+ public String getGenPath()
+ {
+ return genPath;
+ }
+
+ public void setGenPath(String genPath)
+ {
+ this.genPath = genPath;
+ }
+
+ public GenTableColumn getPkColumn()
+ {
+ return pkColumn;
+ }
+
+ public void setPkColumn(GenTableColumn pkColumn)
+ {
+ this.pkColumn = pkColumn;
+ }
+
+ public GenTable getSubTable()
+ {
+ return subTable;
+ }
+
+ public void setSubTable(GenTable subTable)
+ {
+ this.subTable = subTable;
+ }
+
+ public List getColumns()
+ {
+ return columns;
+ }
+
+ public void setColumns(List columns)
+ {
+ this.columns = columns;
+ }
+
+ public String getOptions()
+ {
+ return options;
+ }
+
+ public void setOptions(String options)
+ {
+ this.options = options;
+ }
+
+ public String getTreeCode()
+ {
+ return treeCode;
+ }
+
+ public void setTreeCode(String treeCode)
+ {
+ this.treeCode = treeCode;
+ }
+
+ public String getTreeParentCode()
+ {
+ return treeParentCode;
+ }
+
+ public void setTreeParentCode(String treeParentCode)
+ {
+ this.treeParentCode = treeParentCode;
+ }
+
+ public String getTreeName()
+ {
+ return treeName;
+ }
+
+ public void setTreeName(String treeName)
+ {
+ this.treeName = treeName;
+ }
+
+ public String getParentMenuId()
+ {
+ return parentMenuId;
+ }
+
+ public void setParentMenuId(String parentMenuId)
+ {
+ this.parentMenuId = parentMenuId;
+ }
+
+ public String getParentMenuName()
+ {
+ return parentMenuName;
+ }
+
+ public void setParentMenuName(String parentMenuName)
+ {
+ this.parentMenuName = parentMenuName;
+ }
+
+ public boolean isSub()
+ {
+ return isSub(this.tplCategory);
+ }
+
+ public static boolean isSub(String tplCategory)
+ {
+ return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
+ }
+
+ public boolean isTree()
+ {
+ return isTree(this.tplCategory);
+ }
+
+ public static boolean isTree(String tplCategory)
+ {
+ return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
+ }
+
+ public boolean isCrud()
+ {
+ return isCrud(this.tplCategory);
+ }
+
+ public static boolean isCrud(String tplCategory)
+ {
+ return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
+ }
+
+ public boolean isSuperColumn(String javaField)
+ {
+ return isSuperColumn(this.tplCategory, javaField);
+ }
+
+ public static boolean isSuperColumn(String tplCategory, String javaField)
+ {
+ if (isTree(tplCategory))
+ {
+ return StringUtils.equalsAnyIgnoreCase(javaField,
+ ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
+ }
+ return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+ }
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java
new file mode 100644
index 0000000..ef0a1a2
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/domain/GenTableColumn.java
@@ -0,0 +1,373 @@
+package com.playlet.generator.domain;
+
+import javax.validation.constraints.NotBlank;
+import com.playlet.common.core.domain.BaseEntity;
+import com.playlet.common.utils.StringUtils;
+
+/**
+ * 代码生成业务字段表 gen_table_column
+ *
+ * @author ruoyi
+ */
+public class GenTableColumn extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 编号 */
+ private Long columnId;
+
+ /** 归属表编号 */
+ private Long tableId;
+
+ /** 列名称 */
+ private String columnName;
+
+ /** 列描述 */
+ private String columnComment;
+
+ /** 列类型 */
+ private String columnType;
+
+ /** JAVA类型 */
+ private String javaType;
+
+ /** JAVA字段名 */
+ @NotBlank(message = "Java属性不能为空")
+ private String javaField;
+
+ /** 是否主键(1是) */
+ private String isPk;
+
+ /** 是否自增(1是) */
+ private String isIncrement;
+
+ /** 是否必填(1是) */
+ private String isRequired;
+
+ /** 是否为插入字段(1是) */
+ private String isInsert;
+
+ /** 是否编辑字段(1是) */
+ private String isEdit;
+
+ /** 是否列表字段(1是) */
+ private String isList;
+
+ /** 是否查询字段(1是) */
+ private String isQuery;
+
+ /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */
+ private String queryType;
+
+ /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、upload上传控件、summernote富文本控件) */
+ private String htmlType;
+
+ /** 字典类型 */
+ private String dictType = "";
+
+ /** 排序 */
+ private Integer sort;
+
+ public void setColumnId(Long columnId)
+ {
+ this.columnId = columnId;
+ }
+
+ public Long getColumnId()
+ {
+ return columnId;
+ }
+
+ public void setTableId(Long tableId)
+ {
+ this.tableId = tableId;
+ }
+
+ public Long getTableId()
+ {
+ return tableId;
+ }
+
+ public void setColumnName(String columnName)
+ {
+ this.columnName = columnName;
+ }
+
+ public String getColumnName()
+ {
+ return columnName;
+ }
+
+ public void setColumnComment(String columnComment)
+ {
+ this.columnComment = columnComment;
+ }
+
+ public String getColumnComment()
+ {
+ return columnComment;
+ }
+
+ public void setColumnType(String columnType)
+ {
+ this.columnType = columnType;
+ }
+
+ public String getColumnType()
+ {
+ return columnType;
+ }
+
+ public void setJavaType(String javaType)
+ {
+ this.javaType = javaType;
+ }
+
+ public String getJavaType()
+ {
+ return javaType;
+ }
+
+ public void setJavaField(String javaField)
+ {
+ this.javaField = javaField;
+ }
+
+ public String getJavaField()
+ {
+ return javaField;
+ }
+
+ public String getCapJavaField()
+ {
+ return StringUtils.capitalize(javaField);
+ }
+
+ public void setIsPk(String isPk)
+ {
+ this.isPk = isPk;
+ }
+
+ public String getIsPk()
+ {
+ return isPk;
+ }
+
+ public boolean isPk()
+ {
+ return isPk(this.isPk);
+ }
+
+ public boolean isPk(String isPk)
+ {
+ return isPk != null && StringUtils.equals("1", isPk);
+ }
+
+ public String getIsIncrement()
+ {
+ return isIncrement;
+ }
+
+ public void setIsIncrement(String isIncrement)
+ {
+ this.isIncrement = isIncrement;
+ }
+
+ public boolean isIncrement()
+ {
+ return isIncrement(this.isIncrement);
+ }
+
+ public boolean isIncrement(String isIncrement)
+ {
+ return isIncrement != null && StringUtils.equals("1", isIncrement);
+ }
+
+ public void setIsRequired(String isRequired)
+ {
+ this.isRequired = isRequired;
+ }
+
+ public String getIsRequired()
+ {
+ return isRequired;
+ }
+
+ public boolean isRequired()
+ {
+ return isRequired(this.isRequired);
+ }
+
+ public boolean isRequired(String isRequired)
+ {
+ return isRequired != null && StringUtils.equals("1", isRequired);
+ }
+
+ public void setIsInsert(String isInsert)
+ {
+ this.isInsert = isInsert;
+ }
+
+ public String getIsInsert()
+ {
+ return isInsert;
+ }
+
+ public boolean isInsert()
+ {
+ return isInsert(this.isInsert);
+ }
+
+ public boolean isInsert(String isInsert)
+ {
+ return isInsert != null && StringUtils.equals("1", isInsert);
+ }
+
+ public void setIsEdit(String isEdit)
+ {
+ this.isEdit = isEdit;
+ }
+
+ public String getIsEdit()
+ {
+ return isEdit;
+ }
+
+ public boolean isEdit()
+ {
+ return isInsert(this.isEdit);
+ }
+
+ public boolean isEdit(String isEdit)
+ {
+ return isEdit != null && StringUtils.equals("1", isEdit);
+ }
+
+ public void setIsList(String isList)
+ {
+ this.isList = isList;
+ }
+
+ public String getIsList()
+ {
+ return isList;
+ }
+
+ public boolean isList()
+ {
+ return isList(this.isList);
+ }
+
+ public boolean isList(String isList)
+ {
+ return isList != null && StringUtils.equals("1", isList);
+ }
+
+ public void setIsQuery(String isQuery)
+ {
+ this.isQuery = isQuery;
+ }
+
+ public String getIsQuery()
+ {
+ return isQuery;
+ }
+
+ public boolean isQuery()
+ {
+ return isQuery(this.isQuery);
+ }
+
+ public boolean isQuery(String isQuery)
+ {
+ return isQuery != null && StringUtils.equals("1", isQuery);
+ }
+
+ public void setQueryType(String queryType)
+ {
+ this.queryType = queryType;
+ }
+
+ public String getQueryType()
+ {
+ return queryType;
+ }
+
+ public String getHtmlType()
+ {
+ return htmlType;
+ }
+
+ public void setHtmlType(String htmlType)
+ {
+ this.htmlType = htmlType;
+ }
+
+ public void setDictType(String dictType)
+ {
+ this.dictType = dictType;
+ }
+
+ public String getDictType()
+ {
+ return dictType;
+ }
+
+ public void setSort(Integer sort)
+ {
+ this.sort = sort;
+ }
+
+ public Integer getSort()
+ {
+ return sort;
+ }
+
+ public boolean isSuperColumn()
+ {
+ return isSuperColumn(this.javaField);
+ }
+
+ public static boolean isSuperColumn(String javaField)
+ {
+ return StringUtils.equalsAnyIgnoreCase(javaField,
+ // BaseEntity
+ "createBy", "createTime", "updateBy", "updateTime", "remark",
+ // TreeEntity
+ "parentName", "parentId", "orderNum", "ancestors");
+ }
+
+ public boolean isUsableColumn()
+ {
+ return isUsableColumn(javaField);
+ }
+
+ public static boolean isUsableColumn(String javaField)
+ {
+ // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
+ return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+ }
+
+ public String readConverterExp()
+ {
+ String remarks = StringUtils.substringBetween(this.columnComment, "(", ")");
+ StringBuffer sb = new StringBuffer();
+ if (StringUtils.isNotEmpty(remarks))
+ {
+ for (String value : remarks.split(" "))
+ {
+ if (StringUtils.isNotEmpty(value))
+ {
+ Object startStr = value.subSequence(0, 1);
+ String endStr = value.substring(1);
+ sb.append("").append(startStr).append("=").append(endStr).append(",");
+ }
+ }
+ return sb.deleteCharAt(sb.length() - 1).toString();
+ }
+ else
+ {
+ return this.columnComment;
+ }
+ }
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java
new file mode 100644
index 0000000..31d8ad5
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableColumnMapper.java
@@ -0,0 +1,60 @@
+package com.playlet.generator.mapper;
+
+import java.util.List;
+import com.playlet.generator.domain.GenTableColumn;
+
+/**
+ * 业务字段 数据层
+ *
+ * @author ruoyi
+ */
+public interface GenTableColumnMapper
+{
+ /**
+ * 根据表名称查询列信息
+ *
+ * @param tableName 表名称
+ * @return 列信息
+ */
+ public List selectDbTableColumnsByName(String tableName);
+
+ /**
+ * 查询业务字段列表
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 业务字段集合
+ */
+ public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn);
+
+ /**
+ * 新增业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+ /**
+ * 修改业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+ /**
+ * 删除业务字段
+ *
+ * @param genTableColumns 列数据
+ * @return 结果
+ */
+ public int deleteGenTableColumns(List genTableColumns);
+
+ /**
+ * 批量删除业务字段
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteGenTableColumnByIds(Long[] ids);
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java
new file mode 100644
index 0000000..d32ed22
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/mapper/GenTableMapper.java
@@ -0,0 +1,91 @@
+package com.playlet.generator.mapper;
+
+import java.util.List;
+import com.playlet.generator.domain.GenTable;
+
+/**
+ * 业务 数据层
+ *
+ * @author ruoyi
+ */
+public interface GenTableMapper
+{
+ /**
+ * 查询业务列表
+ *
+ * @param genTable 业务信息
+ * @return 业务集合
+ */
+ public List selectGenTableList(GenTable genTable);
+
+ /**
+ * 查询据库列表
+ *
+ * @param genTable 业务信息
+ * @return 数据库表集合
+ */
+ public List selectDbTableList(GenTable genTable);
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ public List selectDbTableListByNames(String[] tableNames);
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ public List selectGenTableAll();
+
+ /**
+ * 查询表ID业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ public GenTable selectGenTableById(Long id);
+
+ /**
+ * 查询表名称业务信息
+ *
+ * @param tableName 表名称
+ * @return 业务信息
+ */
+ public GenTable selectGenTableByName(String tableName);
+
+ /**
+ * 新增业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ public int insertGenTable(GenTable genTable);
+
+ /**
+ * 修改业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ public int updateGenTable(GenTable genTable);
+
+ /**
+ * 批量删除业务
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteGenTableByIds(Long[] ids);
+
+ /**
+ * 创建表
+ *
+ * @param sql
+ * @return 结果
+ */
+ public int createTable(String sql);
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java
new file mode 100644
index 0000000..74159fa
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableColumnService.java
@@ -0,0 +1,44 @@
+package com.playlet.generator.service;
+
+import java.util.List;
+import com.playlet.generator.domain.GenTableColumn;
+
+/**
+ * 业务字段 服务层
+ *
+ * @author ruoyi
+ */
+public interface IGenTableColumnService
+{
+ /**
+ * 查询业务字段列表
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 业务字段集合
+ */
+ public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn);
+
+ /**
+ * 新增业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+ /**
+ * 修改业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+ /**
+ * 删除业务字段信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteGenTableColumnByIds(String ids);
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java
new file mode 100644
index 0000000..e33b029
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/service/IGenTableService.java
@@ -0,0 +1,129 @@
+package com.playlet.generator.service;
+
+import java.util.List;
+import java.util.Map;
+import com.playlet.generator.domain.GenTable;
+
+/**
+ * 业务 服务层
+ *
+ * @author ruoyi
+ */
+public interface IGenTableService
+{
+ /**
+ * 查询业务列表
+ *
+ * @param genTable 业务信息
+ * @return 业务集合
+ */
+ public List selectGenTableList(GenTable genTable);
+
+ /**
+ * 查询据库列表
+ *
+ * @param genTable 业务信息
+ * @return 数据库表集合
+ */
+ public List selectDbTableList(GenTable genTable);
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ public List selectDbTableListByNames(String[] tableNames);
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ public List selectGenTableAll();
+
+ /**
+ * 查询业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ public GenTable selectGenTableById(Long id);
+
+ /**
+ * 修改业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ public void updateGenTable(GenTable genTable);
+
+ /**
+ * 删除业务信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public void deleteGenTableByIds(String ids);
+
+ /**
+ * 创建表
+ *
+ * @param sql 创建表语句
+ * @return 结果
+ */
+ public boolean createTable(String sql);
+
+ /**
+ * 导入表结构
+ *
+ * @param tableList 导入表列表
+ * @param operName 操作人员
+ */
+ public void importGenTable(List tableList, String operName);
+
+ /**
+ * 预览代码
+ *
+ * @param tableId 表编号
+ * @return 预览数据列表
+ */
+ public Map previewCode(Long tableId);
+
+ /**
+ * 生成代码(下载方式)
+ *
+ * @param tableName 表名称
+ * @return 数据
+ */
+ public byte[] downloadCode(String tableName);
+
+ /**
+ * 生成代码(自定义路径)
+ *
+ * @param tableName 表名称
+ */
+ public void generatorCode(String tableName);
+
+ /**
+ * 同步数据库
+ *
+ * @param tableName 表名称
+ */
+ public void synchDb(String tableName);
+
+ /**
+ * 批量生成代码(下载方式)
+ *
+ * @param tableNames 表数组
+ * @return 数据
+ */
+ public byte[] downloadCode(String[] tableNames);
+
+ /**
+ * 修改保存参数校验
+ *
+ * @param genTable 业务信息
+ */
+ public void validateEdit(GenTable genTable);
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java
new file mode 100644
index 0000000..e926aa9
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableColumnServiceImpl.java
@@ -0,0 +1,69 @@
+package com.playlet.generator.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.core.text.Convert;
+import com.playlet.generator.domain.GenTableColumn;
+import com.playlet.generator.mapper.GenTableColumnMapper;
+import com.playlet.generator.service.IGenTableColumnService;
+
+/**
+ * 业务字段 服务层实现
+ *
+ * @author ruoyi
+ */
+@Service
+public class GenTableColumnServiceImpl implements IGenTableColumnService
+{
+ @Autowired
+ private GenTableColumnMapper genTableColumnMapper;
+
+ /**
+ * 查询业务字段列表
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 业务字段集合
+ */
+ @Override
+ public List selectGenTableColumnListByTableId(GenTableColumn genTableColumn)
+ {
+ return genTableColumnMapper.selectGenTableColumnListByTableId(genTableColumn);
+ }
+
+ /**
+ * 新增业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ @Override
+ public int insertGenTableColumn(GenTableColumn genTableColumn)
+ {
+ return genTableColumnMapper.insertGenTableColumn(genTableColumn);
+ }
+
+ /**
+ * 修改业务字段
+ *
+ * @param genTableColumn 业务字段信息
+ * @return 结果
+ */
+ @Override
+ public int updateGenTableColumn(GenTableColumn genTableColumn)
+ {
+ return genTableColumnMapper.updateGenTableColumn(genTableColumn);
+ }
+
+ /**
+ * 删除业务字段对象
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ @Override
+ public int deleteGenTableColumnByIds(String ids)
+ {
+ return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
+ }
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java
new file mode 100644
index 0000000..94e6eb1
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/service/impl/GenTableServiceImpl.java
@@ -0,0 +1,534 @@
+package com.playlet.generator.service.impl;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.constant.GenConstants;
+import com.playlet.common.core.text.CharsetKit;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.exception.ServiceException;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.generator.domain.GenTable;
+import com.playlet.generator.domain.GenTableColumn;
+import com.playlet.generator.mapper.GenTableColumnMapper;
+import com.playlet.generator.mapper.GenTableMapper;
+import com.playlet.generator.service.IGenTableService;
+import com.playlet.generator.util.GenUtils;
+import com.playlet.generator.util.VelocityInitializer;
+import com.playlet.generator.util.VelocityUtils;
+
+/**
+ * 业务 服务层实现
+ *
+ * @author ruoyi
+ */
+@Service
+public class GenTableServiceImpl implements IGenTableService
+{
+ private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
+
+ @Autowired
+ private GenTableMapper genTableMapper;
+
+ @Autowired
+ private GenTableColumnMapper genTableColumnMapper;
+
+ /**
+ * 查询业务信息
+ *
+ * @param id 业务ID
+ * @return 业务信息
+ */
+ @Override
+ public GenTable selectGenTableById(Long id)
+ {
+ GenTable genTable = genTableMapper.selectGenTableById(id);
+ setTableFromOptions(genTable);
+ return genTable;
+ }
+
+ /**
+ * 查询业务列表
+ *
+ * @param genTable 业务信息
+ * @return 业务集合
+ */
+ @Override
+ public List selectGenTableList(GenTable genTable)
+ {
+ return genTableMapper.selectGenTableList(genTable);
+ }
+
+ /**
+ * 查询据库列表
+ *
+ * @param genTable 业务信息
+ * @return 数据库表集合
+ */
+ @Override
+ public List selectDbTableList(GenTable genTable)
+ {
+ return genTableMapper.selectDbTableList(genTable);
+ }
+
+ /**
+ * 查询据库列表
+ *
+ * @param tableNames 表名称组
+ * @return 数据库表集合
+ */
+ @Override
+ public List selectDbTableListByNames(String[] tableNames)
+ {
+ return genTableMapper.selectDbTableListByNames(tableNames);
+ }
+
+ /**
+ * 查询所有表信息
+ *
+ * @return 表信息集合
+ */
+ @Override
+ public List selectGenTableAll()
+ {
+ return genTableMapper.selectGenTableAll();
+ }
+
+ /**
+ * 修改业务
+ *
+ * @param genTable 业务信息
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public void updateGenTable(GenTable genTable)
+ {
+ String options = JSON.toJSONString(genTable.getParams());
+ genTable.setOptions(options);
+ int row = genTableMapper.updateGenTable(genTable);
+ if (row > 0)
+ {
+ for (GenTableColumn genTableColumn : genTable.getColumns())
+ {
+ genTableColumnMapper.updateGenTableColumn(genTableColumn);
+ }
+ }
+ }
+
+ /**
+ * 删除业务对象
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public void deleteGenTableByIds(String ids)
+ {
+ genTableMapper.deleteGenTableByIds(Convert.toLongArray(ids));
+ genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
+ }
+
+ /**
+ * 创建表
+ *
+ * @param sql 创建表语句
+ * @return 结果
+ */
+ @Override
+ public boolean createTable(String sql)
+ {
+ return genTableMapper.createTable(sql) == 0;
+ }
+
+ /**
+ * 导入表结构
+ *
+ * @param tableList 导入表列表
+ * @param operName 操作人员
+ */
+ @Override
+ @Transactional
+ public void importGenTable(List tableList, String operName)
+ {
+ try
+ {
+ for (GenTable table : tableList)
+ {
+ String tableName = table.getTableName();
+ GenUtils.initTable(table, operName);
+ int row = genTableMapper.insertGenTable(table);
+ if (row > 0)
+ {
+ // 保存列信息
+ List genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+ for (GenTableColumn column : genTableColumns)
+ {
+ GenUtils.initColumnField(column, table);
+ genTableColumnMapper.insertGenTableColumn(column);
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ throw new ServiceException("导入失败:" + e.getMessage());
+ }
+ }
+
+ /**
+ * 预览代码
+ *
+ * @param tableId 表编号
+ * @return 预览数据列表
+ */
+ @Override
+ public Map previewCode(Long tableId)
+ {
+ Map dataMap = new LinkedHashMap<>();
+ // 查询表信息
+ GenTable table = genTableMapper.selectGenTableById(tableId);
+ // 设置主子表信息
+ setSubTable(table);
+ // 设置主键列信息
+ setPkColumn(table);
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates)
+ {
+ // 渲染模板
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ dataMap.put(template, sw.toString());
+ }
+ return dataMap;
+ }
+
+ /**
+ * 生成代码(下载方式)
+ *
+ * @param tableName 表名称
+ * @return 数据
+ */
+ @Override
+ public byte[] downloadCode(String tableName)
+ {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(outputStream);
+ generatorCode(tableName, zip);
+ IOUtils.closeQuietly(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 生成代码(自定义路径)
+ *
+ * @param tableName 表名称
+ */
+ @Override
+ public void generatorCode(String tableName)
+ {
+ // 查询表信息
+ GenTable table = genTableMapper.selectGenTableByName(tableName);
+ // 设置主子表信息
+ setSubTable(table);
+ // 设置主键列信息
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates)
+ {
+ if (!StringUtils.contains(template, "sql.vm"))
+ {
+ // 渲染模板
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ try
+ {
+ String path = getGenPath(table, template);
+ FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
+ }
+ catch (IOException e)
+ {
+ throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
+ }
+ }
+ }
+ }
+
+ /**
+ * 同步数据库
+ *
+ * @param tableName 表名称
+ */
+ @Override
+ @Transactional
+ public void synchDb(String tableName)
+ {
+ GenTable table = genTableMapper.selectGenTableByName(tableName);
+ List tableColumns = table.getColumns();
+ Map tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
+
+ List dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+ if (StringUtils.isEmpty(dbTableColumns))
+ {
+ throw new ServiceException("同步数据失败,原表结构不存在");
+ }
+ List dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
+
+ dbTableColumns.forEach(column -> {
+ GenUtils.initColumnField(column, table);
+ if (tableColumnMap.containsKey(column.getColumnName()))
+ {
+ GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
+ column.setColumnId(prevColumn.getColumnId());
+ if (column.isList())
+ {
+ // 如果是列表,继续保留查询方式/字典类型选项
+ column.setDictType(prevColumn.getDictType());
+ column.setQueryType(prevColumn.getQueryType());
+ }
+ if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
+ && (column.isInsert() || column.isEdit())
+ && ((column.isUsableColumn()) || (!column.isSuperColumn())))
+ {
+ // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
+ column.setIsRequired(prevColumn.getIsRequired());
+ column.setHtmlType(prevColumn.getHtmlType());
+ }
+ genTableColumnMapper.updateGenTableColumn(column);
+ }
+ else
+ {
+ genTableColumnMapper.insertGenTableColumn(column);
+ }
+ });
+
+ List delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
+ if (StringUtils.isNotEmpty(delColumns))
+ {
+ genTableColumnMapper.deleteGenTableColumns(delColumns);
+ }
+ }
+
+ /**
+ * 批量生成代码(下载方式)
+ *
+ * @param tableNames 表数组
+ * @return 数据
+ */
+ @Override
+ public byte[] downloadCode(String[] tableNames)
+ {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(outputStream);
+ for (String tableName : tableNames)
+ {
+ generatorCode(tableName, zip);
+ }
+ IOUtils.closeQuietly(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 查询表信息并生成代码
+ */
+ private void generatorCode(String tableName, ZipOutputStream zip)
+ {
+ // 查询表信息
+ GenTable table = genTableMapper.selectGenTableByName(tableName);
+ // 设置主子表信息
+ setSubTable(table);
+ // 设置主键列信息
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 获取模板列表
+ List templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates)
+ {
+ // 渲染模板
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ try
+ {
+ // 添加到zip
+ zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+ IOUtils.write(sw.toString(), zip, Constants.UTF8);
+ IOUtils.closeQuietly(sw);
+ zip.flush();
+ zip.closeEntry();
+ }
+ catch (IOException e)
+ {
+ log.error("渲染模板失败,表名:" + table.getTableName(), e);
+ }
+ }
+ }
+
+ /**
+ * 修改保存参数校验
+ *
+ * @param genTable 业务信息
+ */
+ @Override
+ public void validateEdit(GenTable genTable)
+ {
+ if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
+ {
+ String options = JSON.toJSONString(genTable.getParams());
+ JSONObject paramsObj = JSONObject.parseObject(options);
+ if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
+ {
+ throw new ServiceException("树编码字段不能为空");
+ }
+ else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
+ {
+ throw new ServiceException("树父编码字段不能为空");
+ }
+ else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
+ {
+ throw new ServiceException("树名称字段不能为空");
+ }
+ }
+ else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
+ {
+ if (StringUtils.isEmpty(genTable.getSubTableName()))
+ {
+ throw new ServiceException("关联子表的表名不能为空");
+ }
+ else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
+ {
+ throw new ServiceException("子表关联的外键名不能为空");
+ }
+ }
+ }
+
+ /**
+ * 设置主键列信息
+ *
+ * @param table 业务表信息
+ */
+ public void setPkColumn(GenTable table)
+ {
+ for (GenTableColumn column : table.getColumns())
+ {
+ if (column.isPk())
+ {
+ table.setPkColumn(column);
+ break;
+ }
+ }
+ if (StringUtils.isNull(table.getPkColumn()))
+ {
+ table.setPkColumn(table.getColumns().get(0));
+ }
+ if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
+ {
+ for (GenTableColumn column : table.getSubTable().getColumns())
+ {
+ if (column.isPk())
+ {
+ table.getSubTable().setPkColumn(column);
+ break;
+ }
+ }
+ if (StringUtils.isNull(table.getSubTable().getPkColumn()))
+ {
+ table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
+ }
+ }
+ }
+
+ /**
+ * 设置主子表信息
+ *
+ * @param table 业务表信息
+ */
+ public void setSubTable(GenTable table)
+ {
+ String subTableName = table.getSubTableName();
+ if (StringUtils.isNotEmpty(subTableName))
+ {
+ table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
+ }
+ }
+
+ /**
+ * 设置代码生成其他选项值
+ *
+ * @param genTable 设置后的生成对象
+ */
+ public void setTableFromOptions(GenTable genTable)
+ {
+ JSONObject paramsObj = JSONObject.parseObject(genTable.getOptions());
+ if (StringUtils.isNotNull(paramsObj))
+ {
+ String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
+ String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
+ String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+ String parentMenuId = paramsObj.getString(GenConstants.PARENT_MENU_ID);
+ String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
+
+ genTable.setTreeCode(treeCode);
+ genTable.setTreeParentCode(treeParentCode);
+ genTable.setTreeName(treeName);
+ genTable.setParentMenuId(parentMenuId);
+ genTable.setParentMenuName(parentMenuName);
+ }
+ }
+
+ /**
+ * 获取代码生成地址
+ *
+ * @param table 业务表信息
+ * @param template 模板文件路径
+ * @return 生成地址
+ */
+ public static String getGenPath(GenTable table, String template)
+ {
+ String genPath = table.getGenPath();
+ if (StringUtils.equals(genPath, "/"))
+ {
+ return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+ }
+ return genPath + File.separator + VelocityUtils.getFileName(template, table);
+ }
+}
\ No newline at end of file
diff --git a/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java b/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java
new file mode 100644
index 0000000..6c39b2b
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/util/GenUtils.java
@@ -0,0 +1,252 @@
+package com.playlet.generator.util;
+
+import java.util.Arrays;
+import org.apache.commons.lang3.RegExUtils;
+import com.playlet.common.constant.GenConstants;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.generator.config.GenConfig;
+import com.playlet.generator.domain.GenTable;
+import com.playlet.generator.domain.GenTableColumn;
+
+/**
+ * 代码生成器 工具类
+ *
+ * @author ruoyi
+ */
+public class GenUtils
+{
+ /**
+ * 初始化表信息
+ */
+ public static void initTable(GenTable genTable, String operName)
+ {
+ genTable.setClassName(convertClassName(genTable.getTableName()));
+ genTable.setPackageName(GenConfig.getPackageName());
+ genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
+ genTable.setBusinessName(getBusinessName(genTable.getTableName()));
+ genTable.setFunctionName(replaceText(genTable.getTableComment()));
+ genTable.setFunctionAuthor(GenConfig.getAuthor());
+ genTable.setCreateBy(operName);
+ }
+
+ /**
+ * 初始化列属性字段
+ */
+ public static void initColumnField(GenTableColumn column, GenTable table)
+ {
+ String dataType = getDbType(column.getColumnType());
+ String columnName = column.getColumnName();
+ column.setTableId(table.getTableId());
+ column.setCreateBy(table.getCreateBy());
+ // 设置java字段名
+ column.setJavaField(StringUtils.toCamelCase(columnName));
+ // 设置默认类型
+ column.setJavaType(GenConstants.TYPE_STRING);
+ column.setQueryType(GenConstants.QUERY_EQ);
+
+ if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
+ {
+ // 字符串长度超过500设置为文本域
+ Integer columnLength = getColumnLength(column.getColumnType());
+ String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
+ column.setHtmlType(htmlType);
+ }
+ else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
+ {
+ column.setJavaType(GenConstants.TYPE_DATE);
+ column.setHtmlType(GenConstants.HTML_DATETIME);
+ }
+ else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))
+ {
+ column.setHtmlType(GenConstants.HTML_INPUT);
+
+ // 如果是浮点型 统一用BigDecimal
+ String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
+ if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
+ {
+ column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
+ }
+ // 如果是整形
+ else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
+ {
+ column.setJavaType(GenConstants.TYPE_INTEGER);
+ }
+ // 长整形
+ else
+ {
+ column.setJavaType(GenConstants.TYPE_LONG);
+ }
+ }
+
+ // 插入字段(默认所有字段都需要插入)
+ column.setIsInsert(GenConstants.REQUIRE);
+
+ // 编辑字段
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
+ {
+ column.setIsEdit(GenConstants.REQUIRE);
+ }
+ // 列表字段
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
+ {
+ column.setIsList(GenConstants.REQUIRE);
+ }
+ // 查询字段
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
+ {
+ column.setIsQuery(GenConstants.REQUIRE);
+ }
+
+ // 查询字段类型
+ if (StringUtils.endsWithIgnoreCase(columnName, "name"))
+ {
+ column.setQueryType(GenConstants.QUERY_LIKE);
+ }
+ // 状态字段设置单选框
+ if (StringUtils.endsWithIgnoreCase(columnName, "status"))
+ {
+ column.setHtmlType(GenConstants.HTML_RADIO);
+ }
+ // 类型&性别字段设置下拉框
+ else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+ || StringUtils.endsWithIgnoreCase(columnName, "sex"))
+ {
+ column.setHtmlType(GenConstants.HTML_SELECT);
+ }
+ // 文件字段设置上传控件
+ else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
+ {
+ column.setHtmlType(GenConstants.HTML_UPLOAD);
+ }
+ // 内容字段设置富文本控件
+ else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
+ {
+ column.setHtmlType(GenConstants.HTML_SUMMERNOTE);
+ }
+ }
+
+ /**
+ * 校验数组是否包含指定值
+ *
+ * @param arr 数组
+ * @param targetValue 值
+ * @return 是否包含
+ */
+ public static boolean arraysContains(String[] arr, String targetValue)
+ {
+ return Arrays.asList(arr).contains(targetValue);
+ }
+
+ /**
+ * 获取模块名
+ *
+ * @param packageName 包名
+ * @return 模块名
+ */
+ public static String getModuleName(String packageName)
+ {
+ int lastIndex = packageName.lastIndexOf(".");
+ int nameLength = packageName.length();
+ return StringUtils.substring(packageName, lastIndex + 1, nameLength);
+ }
+
+ /**
+ * 获取业务名
+ *
+ * @param tableName 表名
+ * @return 业务名
+ */
+ public static String getBusinessName(String tableName)
+ {
+ int lastIndex = tableName.lastIndexOf("_");
+ int nameLength = tableName.length();
+ return StringUtils.substring(tableName, lastIndex + 1, nameLength);
+ }
+
+ /**
+ * 表名转换成Java类名
+ *
+ * @param tableName 表名称
+ * @return 类名
+ */
+ public static String convertClassName(String tableName)
+ {
+ boolean autoRemovePre = GenConfig.getAutoRemovePre();
+ String tablePrefix = GenConfig.getTablePrefix();
+ if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
+ {
+ String[] searchList = StringUtils.split(tablePrefix, ",");
+ tableName = replaceFirst(tableName, searchList);
+ }
+ return StringUtils.convertToCamelCase(tableName);
+ }
+
+ /**
+ * 批量替换前缀
+ *
+ * @param replacementm 替换值
+ * @param searchList 替换列表
+ * @return
+ */
+ public static String replaceFirst(String replacementm, String[] searchList)
+ {
+ String text = replacementm;
+ for (String searchString : searchList)
+ {
+ if (replacementm.startsWith(searchString))
+ {
+ text = replacementm.replaceFirst(searchString, "");
+ break;
+ }
+ }
+ return text;
+ }
+
+ /**
+ * 关键字替换
+ *
+ * @param text 需要被替换的名字
+ * @return 替换后的名字
+ */
+ public static String replaceText(String text)
+ {
+ return RegExUtils.replaceAll(text, "(?:表|若依)", "");
+ }
+
+ /**
+ * 获取数据库类型字段
+ *
+ * @param columnType 列类型
+ * @return 截取后的列类型
+ */
+ public static String getDbType(String columnType)
+ {
+ if (StringUtils.indexOf(columnType, "(") > 0)
+ {
+ return StringUtils.substringBefore(columnType, "(");
+ }
+ else
+ {
+ return columnType;
+ }
+ }
+
+ /**
+ * 获取字段长度
+ *
+ * @param columnType 列类型
+ * @return 截取后的列类型
+ */
+ public static Integer getColumnLength(String columnType)
+ {
+ if (StringUtils.indexOf(columnType, "(") > 0)
+ {
+ String length = StringUtils.substringBetween(columnType, "(", ")");
+ return Integer.valueOf(length);
+ }
+ else
+ {
+ return 0;
+ }
+ }
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java
new file mode 100644
index 0000000..e5d743b
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityInitializer.java
@@ -0,0 +1,34 @@
+package com.playlet.generator.util;
+
+import java.util.Properties;
+import org.apache.velocity.app.Velocity;
+import com.playlet.common.constant.Constants;
+
+/**
+ * VelocityEngine工厂
+ *
+ * @author ruoyi
+ */
+public class VelocityInitializer
+{
+ /**
+ * 初始化vm方法
+ */
+ public static void initVelocity()
+ {
+ Properties p = new Properties();
+ try
+ {
+ // 加载classpath目录下的vm文件
+ p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ // 定义字符集
+ p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+ // 初始化Velocity引擎,指定配置Properties
+ Velocity.init(p);
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java
new file mode 100644
index 0000000..8ea94ff
--- /dev/null
+++ b/playlet-generator/src/main/java/com/playlet/generator/util/VelocityUtils.java
@@ -0,0 +1,384 @@
+package com.playlet.generator.util;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import org.apache.velocity.VelocityContext;
+import com.alibaba.fastjson.JSONObject;
+import com.playlet.common.constant.GenConstants;
+import com.playlet.common.utils.DateUtils;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.generator.config.GenConfig;
+import com.playlet.generator.domain.GenTable;
+import com.playlet.generator.domain.GenTableColumn;
+
+public class VelocityUtils
+{
+ /** 项目空间路径 */
+ private static final String PROJECT_PATH = "main/java";
+
+ /** mybatis空间路径 */
+ private static final String MYBATIS_PATH = "main/resources/mapper";
+
+ /** html空间路径 */
+ private static final String TEMPLATES_PATH = "main/resources/templates";
+
+ /** 默认上级菜单,系统工具 */
+ private static final String DEFAULT_PARENT_MENU_ID = "3";
+
+ /**
+ * 设置模板变量信息
+ *
+ * @return 模板列表
+ */
+ public static VelocityContext prepareContext(GenTable genTable)
+ {
+ String moduleName = genTable.getModuleName();
+ String businessName = genTable.getBusinessName();
+ String packageName = genTable.getPackageName();
+ String tplCategory = genTable.getTplCategory();
+ String functionName = genTable.getFunctionName();
+
+ VelocityContext velocityContext = new VelocityContext();
+ velocityContext.put("tplCategory", genTable.getTplCategory());
+ velocityContext.put("tableName", genTable.getTableName());
+ velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
+ velocityContext.put("ClassName", genTable.getClassName());
+ velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
+ velocityContext.put("moduleName", genTable.getModuleName());
+ velocityContext.put("businessName", genTable.getBusinessName());
+ velocityContext.put("basePackage", getPackagePrefix(packageName));
+ velocityContext.put("packageName", packageName);
+ velocityContext.put("author", genTable.getFunctionAuthor());
+ velocityContext.put("datetime", DateUtils.getDate());
+ velocityContext.put("pkColumn", genTable.getPkColumn());
+ velocityContext.put("importList", getImportList(genTable));
+ velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
+ velocityContext.put("columns", genTable.getColumns());
+ velocityContext.put("table", genTable);
+ setMenuVelocityContext(velocityContext, genTable);
+ if (GenConstants.TPL_TREE.equals(tplCategory))
+ {
+ setTreeVelocityContext(velocityContext, genTable);
+ }
+ if (GenConstants.TPL_SUB.equals(tplCategory))
+ {
+ setSubVelocityContext(velocityContext, genTable);
+ }
+ return velocityContext;
+ }
+
+ public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
+ {
+ String options = genTable.getOptions();
+ JSONObject paramsObj = JSONObject.parseObject(options);
+ String parentMenuId = getParentMenuId(paramsObj);
+ context.put("parentMenuId", parentMenuId);
+ }
+
+ public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
+ {
+ String options = genTable.getOptions();
+ JSONObject paramsObj = JSONObject.parseObject(options);
+ String treeCode = getTreecode(paramsObj);
+ String treeParentCode = getTreeParentCode(paramsObj);
+ String treeName = getTreeName(paramsObj);
+
+ context.put("treeCode", treeCode);
+ context.put("treeParentCode", treeParentCode);
+ context.put("treeName", treeName);
+ context.put("expandColumn", getExpandColumn(genTable));
+ if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+ {
+ context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+ }
+ if (paramsObj.containsKey(GenConstants.TREE_NAME))
+ {
+ context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
+ }
+ }
+
+ public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
+ {
+ GenTable subTable = genTable.getSubTable();
+ String subTableName = genTable.getSubTableName();
+ String subTableFkName = genTable.getSubTableFkName();
+ String subClassName = genTable.getSubTable().getClassName();
+ String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
+
+ context.put("subTable", subTable);
+ context.put("subTableName", subTableName);
+ context.put("subTableFkName", subTableFkName);
+ context.put("subTableFkClassName", subTableFkClassName);
+ context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
+ context.put("subClassName", subClassName);
+ context.put("subclassName", StringUtils.uncapitalize(subClassName));
+ context.put("subImportList", getImportList(genTable.getSubTable()));
+ }
+
+ /**
+ * 获取模板信息
+ *
+ * @return 模板列表
+ */
+ public static List getTemplateList(String tplCategory)
+ {
+ List templates = new ArrayList();
+ templates.add("vm/java/domain.java.vm");
+ templates.add("vm/java/mapper.java.vm");
+ templates.add("vm/java/service.java.vm");
+ templates.add("vm/java/serviceImpl.java.vm");
+ templates.add("vm/java/controller.java.vm");
+ templates.add("vm/xml/mapper.xml.vm");
+ if (GenConstants.TPL_CRUD.equals(tplCategory))
+ {
+ templates.add("vm/html/list.html.vm");
+ }
+ else if (GenConstants.TPL_TREE.equals(tplCategory))
+ {
+ templates.add("vm/html/tree.html.vm");
+ templates.add("vm/html/list-tree.html.vm");
+ }
+ else if (GenConstants.TPL_SUB.equals(tplCategory))
+ {
+ templates.add("vm/html/list.html.vm");
+ templates.add("vm/java/sub-domain.java.vm");
+ }
+ templates.add("vm/html/add.html.vm");
+ templates.add("vm/html/edit.html.vm");
+ templates.add("vm/sql/sql.vm");
+ return templates;
+ }
+
+ /**
+ * 获取文件名
+ */
+ public static String getFileName(String template, GenTable genTable)
+ {
+ // 文件名称
+ String fileName = "";
+ // 包路径
+ String packageName = genTable.getPackageName();
+ // 模块名
+ String moduleName = genTable.getModuleName();
+ // 大写类名
+ String className = genTable.getClassName();
+ // 业务名称
+ String businessName = genTable.getBusinessName();
+
+ String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
+ String mybatisPath = MYBATIS_PATH + "/" + moduleName;
+ String htmlPath = TEMPLATES_PATH + "/" + moduleName + "/" + businessName;
+
+ if (template.contains("domain.java.vm"))
+ {
+ fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
+ }
+ if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
+ {
+ fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
+ }
+ else if (template.contains("mapper.java.vm"))
+ {
+ fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
+ }
+ else if (template.contains("service.java.vm"))
+ {
+ fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
+ }
+ else if (template.contains("serviceImpl.java.vm"))
+ {
+ fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+ }
+ else if (template.contains("controller.java.vm"))
+ {
+ fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
+ }
+ else if (template.contains("mapper.xml.vm"))
+ {
+ fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
+ }
+ else if (template.contains("list.html.vm"))
+ {
+ fileName = StringUtils.format("{}/{}.html", htmlPath, businessName);
+ }
+ else if (template.contains("list-tree.html.vm"))
+ {
+ fileName = StringUtils.format("{}/{}.html", htmlPath, businessName);
+ }
+ else if (template.contains("tree.html.vm"))
+ {
+ fileName = StringUtils.format("{}/tree.html", htmlPath);
+ }
+ else if (template.contains("add.html.vm"))
+ {
+ fileName = StringUtils.format("{}/add.html", htmlPath);
+ }
+ else if (template.contains("edit.html.vm"))
+ {
+ fileName = StringUtils.format("{}/edit.html", htmlPath);
+ }
+ else if (template.contains("sql.vm"))
+ {
+ fileName = businessName + "Menu.sql";
+ }
+ return fileName;
+ }
+
+ /**
+ * 获取项目文件路径
+ *
+ * @return 路径
+ */
+ public static String getProjectPath()
+ {
+ String packageName = GenConfig.getPackageName();
+ StringBuffer projectPath = new StringBuffer();
+ projectPath.append("main/java/");
+ projectPath.append(packageName.replace(".", "/"));
+ projectPath.append("/");
+ return projectPath.toString();
+ }
+
+ /**
+ * 获取包前缀
+ *
+ * @param packageName 包名称
+ * @return 包前缀名称
+ */
+ public static String getPackagePrefix(String packageName)
+ {
+ int lastIndex = packageName.lastIndexOf(".");
+ return StringUtils.substring(packageName, 0, lastIndex);
+ }
+
+ /**
+ * 根据列类型获取导入包
+ *
+ * @param genTable 业务表对象
+ * @return 返回需要导入的包列表
+ */
+ public static HashSet getImportList(GenTable genTable)
+ {
+ List columns = genTable.getColumns();
+ GenTable subGenTable = genTable.getSubTable();
+ HashSet importList = new HashSet();
+ if (StringUtils.isNotNull(subGenTable))
+ {
+ importList.add("java.util.List");
+ }
+ for (GenTableColumn column : columns)
+ {
+ if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))
+ {
+ importList.add("java.util.Date");
+ importList.add("com.fasterxml.jackson.annotation.JsonFormat");
+ }
+ else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))
+ {
+ importList.add("java.math.BigDecimal");
+ }
+ }
+ return importList;
+ }
+
+ /**
+ * 获取权限前缀
+ *
+ * @param moduleName 模块名称
+ * @param businessName 业务名称
+ * @return 返回权限前缀
+ */
+ public static String getPermissionPrefix(String moduleName, String businessName)
+ {
+ return StringUtils.format("{}:{}", moduleName, businessName);
+ }
+
+ /**
+ * 获取上级菜单ID字段
+ *
+ * @param paramsObj 生成其他选项
+ * @return 上级菜单ID字段
+ */
+ public static String getParentMenuId(JSONObject paramsObj)
+ {
+ if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+ && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
+ {
+ return paramsObj.getString(GenConstants.PARENT_MENU_ID);
+ }
+ return DEFAULT_PARENT_MENU_ID;
+ }
+
+ /**
+ * 获取树编码
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树编码
+ */
+ public static String getTreecode(JSONObject paramsObj)
+ {
+ if (paramsObj.containsKey(GenConstants.TREE_CODE))
+ {
+ return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取树父编码
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树父编码
+ */
+ public static String getTreeParentCode(JSONObject paramsObj)
+ {
+ if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+ {
+ return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取树名称
+ *
+ * @param paramsObj 生成其他选项
+ * @return 树名称
+ */
+ public static String getTreeName(JSONObject paramsObj)
+ {
+ if (paramsObj.containsKey(GenConstants.TREE_NAME))
+ {
+ return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 获取需要在哪一列上面显示展开按钮
+ *
+ * @param genTable 业务表对象
+ * @return 展开按钮列序号
+ */
+ public static int getExpandColumn(GenTable genTable)
+ {
+ String options = genTable.getOptions();
+ JSONObject paramsObj = JSONObject.parseObject(options);
+ String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+ int num = 0;
+ for (GenTableColumn column : genTable.getColumns())
+ {
+ if (column.isList())
+ {
+ num++;
+ String columnName = column.getColumnName();
+ if (columnName.equals(treeName))
+ {
+ break;
+ }
+ }
+ }
+ return num;
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java b/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java
new file mode 100644
index 0000000..260d56b
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/config/ScheduleConfig.java
@@ -0,0 +1,57 @@
+//package com.playlet.quartz.config;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+//import javax.sql.DataSource;
+//import java.util.Properties;
+//
+///**
+// * 定时任务配置(单机部署建议默认走内存,如需集群需要创建qrtz数据库表/打开类注释)
+// *
+// * @author ruoyi
+// */
+//@Configuration
+//public class ScheduleConfig
+//{
+// @Bean
+// public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
+// {
+// SchedulerFactoryBean factory = new SchedulerFactoryBean();
+// factory.setDataSource(dataSource);
+//
+// // quartz参数
+// Properties prop = new Properties();
+// prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
+// prop.put("org.quartz.scheduler.instanceId", "AUTO");
+// // 线程池配置
+// prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+// prop.put("org.quartz.threadPool.threadCount", "20");
+// prop.put("org.quartz.threadPool.threadPriority", "5");
+// // JobStore配置
+// prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
+// // 集群配置
+// prop.put("org.quartz.jobStore.isClustered", "true");
+// prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
+// prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
+// prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
+//
+// // sqlserver 启用
+// // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
+// prop.put("org.quartz.jobStore.misfireThreshold", "12000");
+// prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
+// factory.setQuartzProperties(prop);
+//
+// factory.setSchedulerName("RuoyiScheduler");
+// // 延时启动
+// factory.setStartupDelay(1);
+// factory.setApplicationContextSchedulerContextKey("applicationContextKey");
+// // 可选,QuartzScheduler
+// // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
+// factory.setOverwriteExistingJobs(true);
+// // 设置自动启动,默认为true
+// factory.setAutoStartup(true);
+//
+// return factory;
+// }
+//}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java
new file mode 100644
index 0000000..8036e5b
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobController.java
@@ -0,0 +1,247 @@
+package com.playlet.quartz.controller;
+
+import java.util.List;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.quartz.SchedulerException;
+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.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import com.playlet.common.annotation.Log;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.core.controller.BaseController;
+import com.playlet.common.core.domain.AjaxResult;
+import com.playlet.common.core.page.TableDataInfo;
+import com.playlet.common.enums.BusinessType;
+import com.playlet.common.exception.job.TaskException;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.poi.ExcelUtil;
+import com.playlet.quartz.domain.SysJob;
+import com.playlet.quartz.service.ISysJobService;
+import com.playlet.quartz.util.CronUtils;
+import com.playlet.quartz.util.ScheduleUtils;
+
+/**
+ * 调度任务信息操作处理
+ *
+ * @author ruoyi
+ */
+@Controller
+@RequestMapping("/monitor/job")
+public class SysJobController extends BaseController
+{
+ private String prefix = "monitor/job";
+
+ @Autowired
+ private ISysJobService jobService;
+
+ @RequiresPermissions("monitor:job:view")
+ @GetMapping()
+ public String job()
+ {
+ return prefix + "/job";
+ }
+
+ @RequiresPermissions("monitor:job:list")
+ @PostMapping("/list")
+ @ResponseBody
+ public TableDataInfo list(SysJob job)
+ {
+ startPage();
+ List list = jobService.selectJobList(job);
+ return getDataTable(list);
+ }
+
+ @Log(title = "定时任务", businessType = BusinessType.EXPORT)
+ @RequiresPermissions("monitor:job:export")
+ @PostMapping("/export")
+ @ResponseBody
+ public AjaxResult export(SysJob job)
+ {
+ List list = jobService.selectJobList(job);
+ ExcelUtil util = new ExcelUtil(SysJob.class);
+ return util.exportExcel(list, "定时任务");
+ }
+
+ @Log(title = "定时任务", businessType = BusinessType.DELETE)
+ @RequiresPermissions("monitor:job:remove")
+ @PostMapping("/remove")
+ @ResponseBody
+ public AjaxResult remove(String ids) throws SchedulerException
+ {
+ jobService.deleteJobByIds(ids);
+ return success();
+ }
+
+ @RequiresPermissions("monitor:job:detail")
+ @GetMapping("/detail/{jobId}")
+ public String detail(@PathVariable("jobId") Long jobId, ModelMap mmap)
+ {
+ mmap.put("name", "job");
+ mmap.put("job", jobService.selectJobById(jobId));
+ return prefix + "/detail";
+ }
+
+ /**
+ * 任务调度状态修改
+ */
+ @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+ @RequiresPermissions("monitor:job:changeStatus")
+ @PostMapping("/changeStatus")
+ @ResponseBody
+ public AjaxResult changeStatus(SysJob job) throws SchedulerException
+ {
+ SysJob newJob = jobService.selectJobById(job.getJobId());
+ newJob.setStatus(job.getStatus());
+ return toAjax(jobService.changeStatus(newJob));
+ }
+
+ /**
+ * 任务调度立即执行一次
+ */
+ @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+ @RequiresPermissions("monitor:job:changeStatus")
+ @PostMapping("/run")
+ @ResponseBody
+ public AjaxResult run(SysJob job) throws SchedulerException
+ {
+ boolean result = jobService.run(job);
+ return result ? success() : error("任务不存在或已过期!");
+ }
+
+ /**
+ * 新增调度
+ */
+ @GetMapping("/add")
+ public String add()
+ {
+ return prefix + "/add";
+ }
+
+ /**
+ * 新增保存调度
+ */
+ @Log(title = "定时任务", businessType = BusinessType.INSERT)
+ @RequiresPermissions("monitor:job:add")
+ @PostMapping("/add")
+ @ResponseBody
+ public AjaxResult addSave(@Validated SysJob job) throws SchedulerException, TaskException
+ {
+ if (!CronUtils.isValid(job.getCronExpression()))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+ }
+ else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+ }
+ else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+ {
+ return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+ }
+ job.setCreateBy(getLoginName());
+ return toAjax(jobService.insertJob(job));
+ }
+
+ /**
+ * 修改调度
+ */
+ @RequiresPermissions("monitor:job:edit")
+ @GetMapping("/edit/{jobId}")
+ public String edit(@PathVariable("jobId") Long jobId, ModelMap mmap)
+ {
+ mmap.put("job", jobService.selectJobById(jobId));
+ return prefix + "/edit";
+ }
+
+ /**
+ * 修改保存调度
+ */
+ @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+ @RequiresPermissions("monitor:job:edit")
+ @PostMapping("/edit")
+ @ResponseBody
+ public AjaxResult editSave(@Validated SysJob job) throws SchedulerException, TaskException
+ {
+ if (!CronUtils.isValid(job.getCronExpression()))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+ }
+ else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+ }
+ else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+ }
+ else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+ {
+ return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+ }
+ return toAjax(jobService.updateJob(job));
+ }
+
+ /**
+ * 校验cron表达式是否有效
+ */
+ @PostMapping("/checkCronExpressionIsValid")
+ @ResponseBody
+ public boolean checkCronExpressionIsValid(SysJob job)
+ {
+ return jobService.checkCronExpressionIsValid(job.getCronExpression());
+ }
+
+ /**
+ * Cron表达式在线生成
+ */
+ @GetMapping("/cron")
+ public String cron()
+ {
+ return prefix + "/cron";
+ }
+
+ /**
+ * 查询cron表达式近5次的执行时间
+ */
+ @GetMapping("/queryCronExpression")
+ @ResponseBody
+ public AjaxResult queryCronExpression(@RequestParam(value = "cronExpression", required = false) String cronExpression)
+ {
+ if (jobService.checkCronExpressionIsValid(cronExpression))
+ {
+ List dateList = CronUtils.getRecentTriggerTime(cronExpression);
+ return success(dateList);
+ }
+ else
+ {
+ return error("表达式无效");
+ }
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java
new file mode 100644
index 0000000..cce50ac
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/controller/SysJobLogController.java
@@ -0,0 +1,103 @@
+package com.playlet.quartz.controller;
+
+import java.util.List;
+import org.apache.shiro.authz.annotation.RequiresPermissions;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.ResponseBody;
+import com.playlet.common.annotation.Log;
+import com.playlet.common.core.controller.BaseController;
+import com.playlet.common.core.domain.AjaxResult;
+import com.playlet.common.core.page.TableDataInfo;
+import com.playlet.common.enums.BusinessType;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.poi.ExcelUtil;
+import com.playlet.quartz.domain.SysJob;
+import com.playlet.quartz.domain.SysJobLog;
+import com.playlet.quartz.service.ISysJobLogService;
+import com.playlet.quartz.service.ISysJobService;
+
+/**
+ * 调度日志操作处理
+ *
+ * @author ruoyi
+ */
+@Controller
+@RequestMapping("/monitor/jobLog")
+public class SysJobLogController extends BaseController
+{
+ private String prefix = "monitor/job";
+
+ @Autowired
+ private ISysJobService jobService;
+
+ @Autowired
+ private ISysJobLogService jobLogService;
+
+ @RequiresPermissions("monitor:job:view")
+ @GetMapping()
+ public String jobLog(@RequestParam(value = "jobId", required = false) Long jobId, ModelMap mmap)
+ {
+ if (StringUtils.isNotNull(jobId))
+ {
+ SysJob job = jobService.selectJobById(jobId);
+ mmap.put("job", job);
+ }
+ return prefix + "/jobLog";
+ }
+
+ @RequiresPermissions("monitor:job:list")
+ @PostMapping("/list")
+ @ResponseBody
+ public TableDataInfo list(SysJobLog jobLog)
+ {
+ startPage();
+ List list = jobLogService.selectJobLogList(jobLog);
+ return getDataTable(list);
+ }
+
+ @Log(title = "调度日志", businessType = BusinessType.EXPORT)
+ @RequiresPermissions("monitor:job:export")
+ @PostMapping("/export")
+ @ResponseBody
+ public AjaxResult export(SysJobLog jobLog)
+ {
+ List list = jobLogService.selectJobLogList(jobLog);
+ ExcelUtil util = new ExcelUtil(SysJobLog.class);
+ return util.exportExcel(list, "调度日志");
+ }
+
+ @Log(title = "调度日志", businessType = BusinessType.DELETE)
+ @RequiresPermissions("monitor:job:remove")
+ @PostMapping("/remove")
+ @ResponseBody
+ public AjaxResult remove(String ids)
+ {
+ return toAjax(jobLogService.deleteJobLogByIds(ids));
+ }
+
+ @RequiresPermissions("monitor:job:detail")
+ @GetMapping("/detail/{jobLogId}")
+ public String detail(@PathVariable("jobLogId") Long jobLogId, ModelMap mmap)
+ {
+ mmap.put("name", "jobLog");
+ mmap.put("jobLog", jobLogService.selectJobLogById(jobLogId));
+ return prefix + "/detail";
+ }
+
+ @Log(title = "调度日志", businessType = BusinessType.CLEAN)
+ @RequiresPermissions("monitor:job:remove")
+ @PostMapping("/clean")
+ @ResponseBody
+ public AjaxResult clean()
+ {
+ jobLogService.cleanJobLog();
+ return success();
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java
new file mode 100644
index 0000000..bb5b11e
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJob.java
@@ -0,0 +1,169 @@
+package com.playlet.quartz.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.validation.constraints.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.annotation.Excel.ColumnType;
+import com.playlet.common.constant.ScheduleConstants;
+import com.playlet.common.core.domain.BaseEntity;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.quartz.util.CronUtils;
+
+/**
+ * 定时任务调度表 sys_job
+ *
+ * @author ruoyi
+ */
+public class SysJob extends BaseEntity implements Serializable
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 任务ID */
+ @Excel(name = "任务序号", cellType = ColumnType.NUMERIC)
+ private Long jobId;
+
+ /** 任务名称 */
+ @Excel(name = "任务名称")
+ private String jobName;
+
+ /** 任务组名 */
+ @Excel(name = "任务组名")
+ private String jobGroup;
+
+ /** 调用目标字符串 */
+ @Excel(name = "调用目标字符串")
+ private String invokeTarget;
+
+ /** cron执行表达式 */
+ @Excel(name = "执行表达式 ")
+ private String cronExpression;
+
+ /** cron计划策略 */
+ @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
+ private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
+
+ /** 是否并发执行(0允许 1禁止) */
+ @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止")
+ private String concurrent;
+
+ /** 任务状态(0正常 1暂停) */
+ @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停")
+ private String status;
+
+ public Long getJobId()
+ {
+ return jobId;
+ }
+
+ public void setJobId(Long jobId)
+ {
+ this.jobId = jobId;
+ }
+
+ @NotBlank(message = "任务名称不能为空")
+ @Size(min = 0, max = 64, message = "任务名称不能超过64个字符")
+ public String getJobName()
+ {
+ return jobName;
+ }
+
+ public void setJobName(String jobName)
+ {
+ this.jobName = jobName;
+ }
+
+ public String getJobGroup()
+ {
+ return jobGroup;
+ }
+
+ public void setJobGroup(String jobGroup)
+ {
+ this.jobGroup = jobGroup;
+ }
+
+ @NotBlank(message = "调用目标字符串不能为空")
+ @Size(min = 0, max = 1000, message = "调用目标字符串长度不能超过500个字符")
+ public String getInvokeTarget()
+ {
+ return invokeTarget;
+ }
+
+ public void setInvokeTarget(String invokeTarget)
+ {
+ this.invokeTarget = invokeTarget;
+ }
+
+ @NotBlank(message = "Cron执行表达式不能为空")
+ @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符")
+ public String getCronExpression()
+ {
+ return cronExpression;
+ }
+
+ public void setCronExpression(String cronExpression)
+ {
+ this.cronExpression = cronExpression;
+ }
+
+ public Date getNextValidTime()
+ {
+ if (StringUtils.isNotEmpty(cronExpression))
+ {
+ return CronUtils.getNextExecution(cronExpression);
+ }
+ return null;
+ }
+
+ public String getMisfirePolicy()
+ {
+ return misfirePolicy;
+ }
+
+ public void setMisfirePolicy(String misfirePolicy)
+ {
+ this.misfirePolicy = misfirePolicy;
+ }
+
+ public String getConcurrent()
+ {
+ return concurrent;
+ }
+
+ public void setConcurrent(String concurrent)
+ {
+ this.concurrent = concurrent;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("jobId", getJobId())
+ .append("jobName", getJobName())
+ .append("jobGroup", getJobGroup())
+ .append("cronExpression", getCronExpression())
+ .append("nextValidTime", getNextValidTime())
+ .append("misfirePolicy", getMisfirePolicy())
+ .append("concurrent", getConcurrent())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
\ No newline at end of file
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java
new file mode 100644
index 0000000..5db9f06
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/domain/SysJobLog.java
@@ -0,0 +1,155 @@
+package com.playlet.quartz.domain;
+
+import java.util.Date;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.core.domain.BaseEntity;
+
+/**
+ * 定时任务调度日志表 sys_job_log
+ *
+ * @author ruoyi
+ */
+public class SysJobLog extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** ID */
+ @Excel(name = "日志序号")
+ private Long jobLogId;
+
+ /** 任务名称 */
+ @Excel(name = "任务名称")
+ private String jobName;
+
+ /** 任务组名 */
+ @Excel(name = "任务组名")
+ private String jobGroup;
+
+ /** 调用目标字符串 */
+ @Excel(name = "调用目标字符串")
+ private String invokeTarget;
+
+ /** 日志信息 */
+ @Excel(name = "日志信息")
+ private String jobMessage;
+
+ /** 执行状态(0正常 1失败) */
+ @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败")
+ private String status;
+
+ /** 异常信息 */
+ @Excel(name = "异常信息")
+ private String exceptionInfo;
+
+ /** 开始时间 */
+ private Date startTime;
+
+ /** 结束时间 */
+ private Date endTime;
+
+ public Long getJobLogId()
+ {
+ return jobLogId;
+ }
+
+ public void setJobLogId(Long jobLogId)
+ {
+ this.jobLogId = jobLogId;
+ }
+
+ public String getJobName()
+ {
+ return jobName;
+ }
+
+ public void setJobName(String jobName)
+ {
+ this.jobName = jobName;
+ }
+
+ public String getJobGroup()
+ {
+ return jobGroup;
+ }
+
+ public void setJobGroup(String jobGroup)
+ {
+ this.jobGroup = jobGroup;
+ }
+
+ public String getInvokeTarget()
+ {
+ return invokeTarget;
+ }
+
+ public void setInvokeTarget(String invokeTarget)
+ {
+ this.invokeTarget = invokeTarget;
+ }
+
+ public String getJobMessage()
+ {
+ return jobMessage;
+ }
+
+ public void setJobMessage(String jobMessage)
+ {
+ this.jobMessage = jobMessage;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getExceptionInfo()
+ {
+ return exceptionInfo;
+ }
+
+ public void setExceptionInfo(String exceptionInfo)
+ {
+ this.exceptionInfo = exceptionInfo;
+ }
+
+ public Date getStartTime()
+ {
+ return startTime;
+ }
+
+ public void setStartTime(Date startTime)
+ {
+ this.startTime = startTime;
+ }
+
+ public Date getEndTime()
+ {
+ return endTime;
+ }
+
+ public void setEndTime(Date endTime)
+ {
+ this.endTime = endTime;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("jobLogId", getJobLogId())
+ .append("jobName", getJobName())
+ .append("jobGroup", getJobGroup())
+ .append("jobMessage", getJobMessage())
+ .append("status", getStatus())
+ .append("exceptionInfo", getExceptionInfo())
+ .append("startTime", getStartTime())
+ .append("endTime", getEndTime())
+ .toString();
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java
new file mode 100644
index 0000000..6195939
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobLogMapper.java
@@ -0,0 +1,64 @@
+package com.playlet.quartz.mapper;
+
+import com.playlet.quartz.domain.SysJobLog;
+import java.util.List;
+
+/**
+ * 调度任务日志信息 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysJobLogMapper
+{
+ /**
+ * 获取quartz调度器日志的计划任务
+ *
+ * @param jobLog 调度日志信息
+ * @return 调度任务日志集合
+ */
+ public List selectJobLogList(SysJobLog jobLog);
+
+ /**
+ * 查询所有调度任务日志
+ *
+ * @return 调度任务日志列表
+ */
+ public List selectJobLogAll();
+
+ /**
+ * 通过调度任务日志ID查询调度信息
+ *
+ * @param jobLogId 调度任务日志ID
+ * @return 调度任务日志对象信息
+ */
+ public SysJobLog selectJobLogById(Long jobLogId);
+
+ /**
+ * 新增任务日志
+ *
+ * @param jobLog 调度日志信息
+ * @return 结果
+ */
+ public int insertJobLog(SysJobLog jobLog);
+
+ /**
+ * 批量删除调度日志信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteJobLogByIds(String[] ids);
+
+ /**
+ * 删除任务日志
+ *
+ * @param jobId 调度日志ID
+ * @return 结果
+ */
+ public int deleteJobLogById(Long jobId);
+
+ /**
+ * 清空任务日志
+ */
+ public void cleanJobLog();
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java
new file mode 100644
index 0000000..4ec961b
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/mapper/SysJobMapper.java
@@ -0,0 +1,67 @@
+package com.playlet.quartz.mapper;
+
+import com.playlet.quartz.domain.SysJob;
+import java.util.List;
+
+/**
+ * 调度任务信息 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysJobMapper
+{
+ /**
+ * 查询调度任务日志集合
+ *
+ * @param job 调度信息
+ * @return 操作日志集合
+ */
+ public List selectJobList(SysJob job);
+
+ /**
+ * 查询所有调度任务
+ *
+ * @return 调度任务列表
+ */
+ public List selectJobAll();
+
+ /**
+ * 通过调度ID查询调度任务信息
+ *
+ * @param jobId 调度ID
+ * @return 角色对象信息
+ */
+ public SysJob selectJobById(Long jobId);
+
+ /**
+ * 通过调度ID删除调度任务信息
+ *
+ * @param jobId 调度ID
+ * @return 结果
+ */
+ public int deleteJobById(Long jobId);
+
+ /**
+ * 批量删除调度任务信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteJobByIds(Long[] ids);
+
+ /**
+ * 修改调度任务信息
+ *
+ * @param job 调度任务信息
+ * @return 结果
+ */
+ public int updateJob(SysJob job);
+
+ /**
+ * 新增调度任务信息
+ *
+ * @param job 调度任务信息
+ * @return 结果
+ */
+ public int insertJob(SysJob job);
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java
new file mode 100644
index 0000000..0463fa4
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobLogService.java
@@ -0,0 +1,56 @@
+package com.playlet.quartz.service;
+
+import java.util.List;
+import com.playlet.quartz.domain.SysJobLog;
+
+/**
+ * 定时任务调度日志信息信息 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysJobLogService
+{
+ /**
+ * 获取quartz调度器日志的计划任务
+ *
+ * @param jobLog 调度日志信息
+ * @return 调度任务日志集合
+ */
+ public List selectJobLogList(SysJobLog jobLog);
+
+ /**
+ * 通过调度任务日志ID查询调度信息
+ *
+ * @param jobLogId 调度任务日志ID
+ * @return 调度任务日志对象信息
+ */
+ public SysJobLog selectJobLogById(Long jobLogId);
+
+ /**
+ * 新增任务日志
+ *
+ * @param jobLog 调度日志信息
+ */
+ public void addJobLog(SysJobLog jobLog);
+
+ /**
+ * 批量删除调度日志信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteJobLogByIds(String ids);
+
+ /**
+ * 删除任务日志
+ *
+ * @param jobId 调度日志ID
+ * @return 结果
+ */
+ public int deleteJobLogById(Long jobId);
+
+ /**
+ * 清空任务日志
+ */
+ public void cleanJobLog();
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java
new file mode 100644
index 0000000..616ba4f
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/ISysJobService.java
@@ -0,0 +1,102 @@
+package com.playlet.quartz.service;
+
+import java.util.List;
+import org.quartz.SchedulerException;
+import com.playlet.common.exception.job.TaskException;
+import com.playlet.quartz.domain.SysJob;
+
+/**
+ * 定时任务调度信息信息 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysJobService
+{
+ /**
+ * 获取quartz调度器的计划任务
+ *
+ * @param job 调度信息
+ * @return 调度任务集合
+ */
+ public List selectJobList(SysJob job);
+
+ /**
+ * 通过调度任务ID查询调度信息
+ *
+ * @param jobId 调度任务ID
+ * @return 调度任务对象信息
+ */
+ public SysJob selectJobById(Long jobId);
+
+ /**
+ * 暂停任务
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int pauseJob(SysJob job) throws SchedulerException;
+
+ /**
+ * 恢复任务
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int resumeJob(SysJob job) throws SchedulerException;
+
+ /**
+ * 删除任务后,所对应的trigger也将被删除
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int deleteJob(SysJob job) throws SchedulerException;
+
+ /**
+ * 批量删除调度信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public void deleteJobByIds(String ids) throws SchedulerException;
+
+ /**
+ * 任务调度状态修改
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int changeStatus(SysJob job) throws SchedulerException;
+
+ /**
+ * 立即运行任务
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public boolean run(SysJob job) throws SchedulerException;
+
+ /**
+ * 新增任务
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int insertJob(SysJob job) throws SchedulerException, TaskException;
+
+ /**
+ * 更新任务
+ *
+ * @param job 调度信息
+ * @return 结果
+ */
+ public int updateJob(SysJob job) throws SchedulerException, TaskException;
+
+ /**
+ * 校验cron表达式是否有效
+ *
+ * @param cronExpression 表达式
+ * @return 结果
+ */
+ public boolean checkCronExpressionIsValid(String cronExpression);
+}
\ No newline at end of file
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java
new file mode 100644
index 0000000..3c3027c
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobLogServiceImpl.java
@@ -0,0 +1,88 @@
+package com.playlet.quartz.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.core.text.Convert;
+import com.playlet.quartz.domain.SysJobLog;
+import com.playlet.quartz.mapper.SysJobLogMapper;
+import com.playlet.quartz.service.ISysJobLogService;
+
+/**
+ * 定时任务调度日志信息 服务层
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysJobLogServiceImpl implements ISysJobLogService
+{
+ @Autowired
+ private SysJobLogMapper jobLogMapper;
+
+ /**
+ * 获取quartz调度器日志的计划任务
+ *
+ * @param jobLog 调度日志信息
+ * @return 调度任务日志集合
+ */
+ @Override
+ public List selectJobLogList(SysJobLog jobLog)
+ {
+ return jobLogMapper.selectJobLogList(jobLog);
+ }
+
+ /**
+ * 通过调度任务日志ID查询调度信息
+ *
+ * @param jobLogId 调度任务日志ID
+ * @return 调度任务日志对象信息
+ */
+ @Override
+ public SysJobLog selectJobLogById(Long jobLogId)
+ {
+ return jobLogMapper.selectJobLogById(jobLogId);
+ }
+
+ /**
+ * 新增任务日志
+ *
+ * @param jobLog 调度日志信息
+ */
+ @Override
+ public void addJobLog(SysJobLog jobLog)
+ {
+ jobLogMapper.insertJobLog(jobLog);
+ }
+
+ /**
+ * 批量删除调度日志信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ @Override
+ public int deleteJobLogByIds(String ids)
+ {
+ return jobLogMapper.deleteJobLogByIds(Convert.toStrArray(ids));
+ }
+
+ /**
+ * 删除任务日志
+ *
+ * @param jobId 调度日志ID
+ */
+ @Override
+ public int deleteJobLogById(Long jobId)
+ {
+ return jobLogMapper.deleteJobLogById(jobId);
+ }
+
+ /**
+ * 清空任务日志
+ */
+ @Override
+ public void cleanJobLog()
+ {
+ jobLogMapper.cleanJobLog();
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java
new file mode 100644
index 0000000..663d04b
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/service/impl/SysJobServiceImpl.java
@@ -0,0 +1,263 @@
+package com.playlet.quartz.service.impl;
+
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.quartz.JobDataMap;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.playlet.common.constant.ScheduleConstants;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.exception.job.TaskException;
+import com.playlet.quartz.domain.SysJob;
+import com.playlet.quartz.mapper.SysJobMapper;
+import com.playlet.quartz.service.ISysJobService;
+import com.playlet.quartz.util.CronUtils;
+import com.playlet.quartz.util.ScheduleUtils;
+
+/**
+ * 定时任务调度信息 服务层
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysJobServiceImpl implements ISysJobService
+{
+ @Autowired
+ private Scheduler scheduler;
+
+ @Autowired
+ private SysJobMapper jobMapper;
+
+ /**
+ * 项目启动时,初始化定时器
+ * 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
+ */
+ @PostConstruct
+ public void init() throws SchedulerException, TaskException
+ {
+ scheduler.clear();
+ List jobList = jobMapper.selectJobAll();
+ for (SysJob job : jobList)
+ {
+ ScheduleUtils.createScheduleJob(scheduler, job);
+ }
+ }
+
+ /**
+ * 获取quartz调度器的计划任务列表
+ *
+ * @param job 调度信息
+ * @return
+ */
+ @Override
+ public List selectJobList(SysJob job)
+ {
+ return jobMapper.selectJobList(job);
+ }
+
+ /**
+ * 通过调度任务ID查询调度信息
+ *
+ * @param jobId 调度任务ID
+ * @return 调度任务对象信息
+ */
+ @Override
+ public SysJob selectJobById(Long jobId)
+ {
+ return jobMapper.selectJobById(jobId);
+ }
+
+ /**
+ * 暂停任务
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int pauseJob(SysJob job) throws SchedulerException
+ {
+ Long jobId = job.getJobId();
+ String jobGroup = job.getJobGroup();
+ job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
+ int rows = jobMapper.updateJob(job);
+ if (rows > 0)
+ {
+ scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+ }
+ return rows;
+ }
+
+ /**
+ * 恢复任务
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int resumeJob(SysJob job) throws SchedulerException
+ {
+ Long jobId = job.getJobId();
+ String jobGroup = job.getJobGroup();
+ job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
+ int rows = jobMapper.updateJob(job);
+ if (rows > 0)
+ {
+ scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+ }
+ return rows;
+ }
+
+ /**
+ * 删除任务后,所对应的trigger也将被删除
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteJob(SysJob job) throws SchedulerException
+ {
+ Long jobId = job.getJobId();
+ String jobGroup = job.getJobGroup();
+ int rows = jobMapper.deleteJobById(jobId);
+ if (rows > 0)
+ {
+ scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+ }
+ return rows;
+ }
+
+ /**
+ * 批量删除调度信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteJobByIds(String ids) throws SchedulerException
+ {
+ Long[] jobIds = Convert.toLongArray(ids);
+ for (Long jobId : jobIds)
+ {
+ SysJob job = jobMapper.selectJobById(jobId);
+ deleteJob(job);
+ }
+ }
+
+ /**
+ * 任务调度状态修改
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int changeStatus(SysJob job) throws SchedulerException
+ {
+ int rows = 0;
+ String status = job.getStatus();
+ if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
+ {
+ rows = resumeJob(job);
+ }
+ else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
+ {
+ rows = pauseJob(job);
+ }
+ return rows;
+ }
+
+ /**
+ * 立即运行任务
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public boolean run(SysJob job) throws SchedulerException
+ {
+ boolean result = false;
+ Long jobId = job.getJobId();
+ SysJob tmpObj = selectJobById(job.getJobId());
+ // 参数
+ JobDataMap dataMap = new JobDataMap();
+ dataMap.put(ScheduleConstants.TASK_PROPERTIES, tmpObj);
+ JobKey jobKey = ScheduleUtils.getJobKey(jobId, tmpObj.getJobGroup());
+ if (scheduler.checkExists(jobKey))
+ {
+ result = true;
+ scheduler.triggerJob(jobKey, dataMap);
+ }
+ return result;
+ }
+
+ /**
+ * 新增任务
+ *
+ * @param job 调度信息 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int insertJob(SysJob job) throws SchedulerException, TaskException
+ {
+ job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
+ int rows = jobMapper.insertJob(job);
+ if (rows > 0)
+ {
+ ScheduleUtils.createScheduleJob(scheduler, job);
+ }
+ return rows;
+ }
+
+ /**
+ * 更新任务的时间表达式
+ *
+ * @param job 调度信息
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int updateJob(SysJob job) throws SchedulerException, TaskException
+ {
+ SysJob properties = selectJobById(job.getJobId());
+ int rows = jobMapper.updateJob(job);
+ if (rows > 0)
+ {
+ updateSchedulerJob(job, properties.getJobGroup());
+ }
+ return rows;
+ }
+
+ /**
+ * 更新任务
+ *
+ * @param job 任务对象
+ * @param jobGroup 任务组名
+ */
+ public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException
+ {
+ Long jobId = job.getJobId();
+ // 判断是否存在
+ JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
+ if (scheduler.checkExists(jobKey))
+ {
+ // 防止创建时存在数据问题 先移除,然后在执行创建操作
+ scheduler.deleteJob(jobKey);
+ }
+ ScheduleUtils.createScheduleJob(scheduler, job);
+ }
+
+ /**
+ * 校验cron表达式是否有效
+ *
+ * @param cronExpression 表达式
+ * @return 结果
+ */
+ @Override
+ public boolean checkCronExpressionIsValid(String cronExpression)
+ {
+ return CronUtils.isValid(cronExpression);
+ }
+}
\ No newline at end of file
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java b/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java
new file mode 100644
index 0000000..aea716e
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/task/RyTask.java
@@ -0,0 +1,28 @@
+package com.playlet.quartz.task;
+
+import org.springframework.stereotype.Component;
+import com.playlet.common.utils.StringUtils;
+
+/**
+ * 定时任务调度测试
+ *
+ * @author ruoyi
+ */
+@Component("ryTask")
+public class RyTask
+{
+ 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)
+ {
+ System.out.println("执行有参方法:" + params);
+ }
+
+ public void ryNoParams()
+ {
+ System.out.println("执行无参方法");
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java
new file mode 100644
index 0000000..613c7c0
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/AbstractQuartzJob.java
@@ -0,0 +1,107 @@
+package com.playlet.quartz.util;
+
+import java.util.Date;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.constant.ScheduleConstants;
+import com.playlet.common.utils.ExceptionUtil;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.bean.BeanUtils;
+import com.playlet.common.utils.spring.SpringUtils;
+import com.playlet.quartz.domain.SysJob;
+import com.playlet.quartz.domain.SysJobLog;
+import com.playlet.quartz.service.ISysJobLogService;
+
+/**
+ * 抽象quartz调用
+ *
+ * @author ruoyi
+ */
+public abstract class AbstractQuartzJob implements Job
+{
+ private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+ /**
+ * 线程本地变量
+ */
+ private static ThreadLocal threadLocal = new ThreadLocal<>();
+
+ @Override
+ public void execute(JobExecutionContext context) throws JobExecutionException
+ {
+ SysJob sysJob = new SysJob();
+ BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
+ try
+ {
+ before(context, sysJob);
+ if (sysJob != null)
+ {
+ doExecute(context, sysJob);
+ }
+ after(context, sysJob, null);
+ }
+ catch (Exception e)
+ {
+ log.error("任务执行异常 - :", e);
+ after(context, sysJob, e);
+ }
+ }
+
+ /**
+ * 执行前
+ *
+ * @param context 工作执行上下文对象
+ * @param sysJob 系统计划任务
+ */
+ protected void before(JobExecutionContext context, SysJob sysJob)
+ {
+ threadLocal.set(new Date());
+ }
+
+ /**
+ * 执行后
+ *
+ * @param context 工作执行上下文对象
+ * @param sysJob 系统计划任务
+ */
+ protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
+ {
+ Date startTime = threadLocal.get();
+ threadLocal.remove();
+
+ final SysJobLog sysJobLog = new SysJobLog();
+ sysJobLog.setJobName(sysJob.getJobName());
+ sysJobLog.setJobGroup(sysJob.getJobGroup());
+ sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+ sysJobLog.setStartTime(startTime);
+ sysJobLog.setEndTime(new Date());
+ long runMs = sysJobLog.getEndTime().getTime() - sysJobLog.getStartTime().getTime();
+ sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+ if (e != null)
+ {
+ sysJobLog.setStatus(Constants.FAIL);
+ String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
+ sysJobLog.setExceptionInfo(errorMsg);
+ }
+ else
+ {
+ sysJobLog.setStatus(Constants.SUCCESS);
+ }
+
+ // 写入数据库当中
+ SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
+ }
+
+ /**
+ * 执行方法,由子类重载
+ *
+ * @param context 工作执行上下文对象
+ * @param sysJob 系统计划任务
+ * @throws Exception 执行过程中的异常
+ */
+ protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java
new file mode 100644
index 0000000..54365e0
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/CronUtils.java
@@ -0,0 +1,94 @@
+package com.playlet.quartz.util;
+
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import org.quartz.CronExpression;
+import org.quartz.TriggerUtils;
+import org.quartz.impl.triggers.CronTriggerImpl;
+import com.playlet.common.utils.DateUtils;
+
+/**
+ * cron表达式工具类
+ *
+ * @author ruoyi
+ *
+ */
+public class CronUtils
+{
+ /**
+ * 返回一个布尔值代表一个给定的Cron表达式的有效性
+ *
+ * @param cronExpression Cron表达式
+ * @return boolean 表达式是否有效
+ */
+ public static boolean isValid(String cronExpression)
+ {
+ return CronExpression.isValidExpression(cronExpression);
+ }
+
+ /**
+ * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
+ *
+ * @param cronExpression Cron表达式
+ * @return String 无效时返回表达式错误描述,如果有效返回null
+ */
+ public static String getInvalidMessage(String cronExpression)
+ {
+ try
+ {
+ new CronExpression(cronExpression);
+ return null;
+ }
+ catch (ParseException pe)
+ {
+ return pe.getMessage();
+ }
+ }
+
+ /**
+ * 返回下一个执行时间根据给定的Cron表达式
+ *
+ * @param cronExpression Cron表达式
+ * @return Date 下次Cron表达式执行时间
+ */
+ public static Date getNextExecution(String cronExpression)
+ {
+ try
+ {
+ CronExpression cron = new CronExpression(cronExpression);
+ return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+ }
+ catch (ParseException e)
+ {
+ throw new IllegalArgumentException(e.getMessage());
+ }
+ }
+
+ /**
+ * 通过表达式获取近10次的执行时间
+ *
+ * @param cron 表达式
+ * @return 时间列表
+ */
+ public static List getRecentTriggerTime(String cron)
+ {
+ List list = new ArrayList();
+ try
+ {
+ CronTriggerImpl cronTriggerImpl = new CronTriggerImpl();
+ cronTriggerImpl.setCronExpression(cron);
+ List dates = TriggerUtils.computeFireTimes(cronTriggerImpl, null, 10);
+ for (Date date : dates)
+ {
+ list.add(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, date));
+ }
+ }
+ catch (ParseException e)
+ {
+ return null;
+ }
+ return list;
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java
new file mode 100644
index 0000000..693f689
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/JobInvokeUtil.java
@@ -0,0 +1,182 @@
+package com.playlet.quartz.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.spring.SpringUtils;
+import com.playlet.quartz.domain.SysJob;
+
+/**
+ * 任务执行工具
+ *
+ * @author ruoyi
+ */
+public class JobInvokeUtil
+{
+ /**
+ * 执行方法
+ *
+ * @param sysJob 系统任务
+ */
+ public static void invokeMethod(SysJob sysJob) throws Exception
+ {
+ String invokeTarget = sysJob.getInvokeTarget();
+ String beanName = getBeanName(invokeTarget);
+ String methodName = getMethodName(invokeTarget);
+ List methodParams = getMethodParams(invokeTarget);
+
+ if (!isValidClassName(beanName))
+ {
+ Object bean = SpringUtils.getBean(beanName);
+ invokeMethod(bean, methodName, methodParams);
+ }
+ else
+ {
+ Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
+ invokeMethod(bean, methodName, methodParams);
+ }
+ }
+
+ /**
+ * 调用任务方法
+ *
+ * @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)
+ {
+ Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+ method.invoke(bean, getMethodParamsValue(methodParams));
+ }
+ else
+ {
+ Method method = bean.getClass().getMethod(methodName);
+ method.invoke(bean);
+ }
+ }
+
+ /**
+ * 校验是否为为class包名
+ *
+ * @param invokeTarget 名称
+ * @return true是 false否
+ */
+ public static boolean isValidClassName(String invokeTarget)
+ {
+ return StringUtils.countMatches(invokeTarget, ".") > 1;
+ }
+
+ /**
+ * 获取bean名称
+ *
+ * @param invokeTarget 目标字符串
+ * @return bean名称
+ */
+ 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)
+ {
+ String methodName = StringUtils.substringBefore(invokeTarget, "(");
+ return StringUtils.substringAfterLast(methodName, ".");
+ }
+
+ /**
+ * 获取method方法参数相关列表
+ *
+ * @param invokeTarget 目标字符串
+ * @return method方法相关参数列表
+ */
+ public static List getMethodParams(String invokeTarget)
+ {
+ String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+ if (StringUtils.isEmpty(methodStr))
+ {
+ return null;
+ }
+ String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+ List classs = new LinkedList<>();
+ 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 });
+ }
+ // boolean布尔类型,等于true或者false
+ 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 });
+ }
+ // double浮点类型,以D结尾
+ 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 });
+ }
+ }
+ return classs;
+ }
+
+ /**
+ * 获取参数类型
+ *
+ * @param methodParams 参数相关列表
+ * @return 参数类型列表
+ */
+ public static Class>[] getMethodParamsType(List methodParams)
+ {
+ Class>[] classs = new Class>[methodParams.size()];
+ int index = 0;
+ for (Object[] os : methodParams)
+ {
+ classs[index] = (Class>) os[1];
+ index++;
+ }
+ return classs;
+ }
+
+ /**
+ * 获取参数值
+ *
+ * @param methodParams 参数相关列表
+ * @return 参数值列表
+ */
+ public static Object[] getMethodParamsValue(List methodParams)
+ {
+ Object[] classs = new Object[methodParams.size()];
+ int index = 0;
+ for (Object[] os : methodParams)
+ {
+ classs[index] = (Object) os[0];
+ index++;
+ }
+ return classs;
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java
new file mode 100644
index 0000000..df907b0
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzDisallowConcurrentExecution.java
@@ -0,0 +1,21 @@
+package com.playlet.quartz.util;
+
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.JobExecutionContext;
+import com.playlet.quartz.domain.SysJob;
+
+/**
+ * 定时任务处理(禁止并发执行)
+ *
+ * @author ruoyi
+ *
+ */
+@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
+{
+ @Override
+ protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
+ {
+ JobInvokeUtil.invokeMethod(sysJob);
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java
new file mode 100644
index 0000000..c7cd447
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/QuartzJobExecution.java
@@ -0,0 +1,19 @@
+package com.playlet.quartz.util;
+
+import org.quartz.JobExecutionContext;
+import com.playlet.quartz.domain.SysJob;
+
+/**
+ * 定时任务处理(允许并发执行)
+ *
+ * @author ruoyi
+ *
+ */
+public class QuartzJobExecution extends AbstractQuartzJob
+{
+ @Override
+ protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
+ {
+ JobInvokeUtil.invokeMethod(sysJob);
+ }
+}
diff --git a/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java b/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java
new file mode 100644
index 0000000..0c74cba
--- /dev/null
+++ b/playlet-quartz/src/main/java/com/playlet/quartz/util/ScheduleUtils.java
@@ -0,0 +1,141 @@
+package com.playlet.quartz.util;
+
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.constant.ScheduleConstants;
+import com.playlet.common.exception.job.TaskException;
+import com.playlet.common.exception.job.TaskException.Code;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.spring.SpringUtils;
+import com.playlet.quartz.domain.SysJob;
+
+/**
+ * 定时任务工具类
+ *
+ * @author ruoyi
+ *
+ */
+public class ScheduleUtils
+{
+ /**
+ * 得到quartz任务类
+ *
+ * @param sysJob 执行计划
+ * @return 具体执行任务类
+ */
+ private static Class extends Job> getQuartzJobClass(SysJob sysJob)
+ {
+ boolean isConcurrent = "0".equals(sysJob.getConcurrent());
+ return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
+ }
+
+ /**
+ * 构建任务触发对象
+ */
+ 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)
+ {
+ return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+ }
+
+ /**
+ * 创建定时任务
+ */
+ public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException
+ {
+ Class extends Job> jobClass = getQuartzJobClass(job);
+ // 构建job信息
+ Long jobId = job.getJobId();
+ String jobGroup = job.getJobGroup();
+ JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
+
+ // 表达式调度构建器
+ CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+ 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.getCronExpression())))
+ {
+ // 执行调度任务
+ scheduler.scheduleJob(jobDetail, trigger);
+ }
+
+ // 暂停任务
+ if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
+ {
+ scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+ }
+ }
+
+ /**
+ * 设置定时任务策略
+ */
+ public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob 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)
+ {
+ String packageName = StringUtils.substringBefore(invokeTarget, "(");
+ int count = StringUtils.countMatches(packageName, ".");
+ if (count > 1)
+ {
+ return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
+ }
+ Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
+ String beanPackageName = obj.getClass().getPackage().getName();
+ return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
+ && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
+ }
+}
\ No newline at end of file
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java b/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java
new file mode 100644
index 0000000..3f2ae76
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysConfig.java
@@ -0,0 +1,110 @@
+package com.playlet.system.domain;
+
+import javax.validation.constraints.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.annotation.Excel.ColumnType;
+import com.playlet.common.core.domain.BaseEntity;
+
+/**
+ * 参数配置表 sys_config
+ *
+ * @author ruoyi
+ */
+public class SysConfig extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 参数主键 */
+ @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
+ private Long configId;
+
+ /** 参数名称 */
+ @Excel(name = "参数名称")
+ private String configName;
+
+ /** 参数键名 */
+ @Excel(name = "参数键名")
+ private String configKey;
+
+ /** 参数键值 */
+ @Excel(name = "参数键值")
+ private String configValue;
+
+ /** 系统内置(Y是 N否) */
+ @Excel(name = "系统内置", readConverterExp = "Y=是,N=否")
+ private String configType;
+
+ public Long getConfigId()
+ {
+ return configId;
+ }
+
+ public void setConfigId(Long configId)
+ {
+ this.configId = configId;
+ }
+
+ @NotBlank(message = "参数名称不能为空")
+ @Size(min = 0, max = 100, message = "参数名称不能超过100个字符")
+ public String getConfigName()
+ {
+ return configName;
+ }
+
+ public void setConfigName(String configName)
+ {
+ this.configName = configName;
+ }
+
+ @NotBlank(message = "参数键名长度不能为空")
+ @Size(min = 0, max = 100, message = "参数键名长度不能超过100个字符")
+ public String getConfigKey()
+ {
+ return configKey;
+ }
+
+ public void setConfigKey(String configKey)
+ {
+ this.configKey = configKey;
+ }
+
+ @NotBlank(message = "参数键值不能为空")
+ @Size(min = 0, max = 500, message = "参数键值长度不能超过500个字符")
+ public String getConfigValue()
+ {
+ return configValue;
+ }
+
+ public void setConfigValue(String configValue)
+ {
+ this.configValue = configValue;
+ }
+
+ public String getConfigType()
+ {
+ return configType;
+ }
+
+ public void setConfigType(String configType)
+ {
+ this.configType = configType;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("configId", getConfigId())
+ .append("configName", getConfigName())
+ .append("configKey", getConfigKey())
+ .append("configValue", getConfigValue())
+ .append("configType", getConfigType())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java b/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java
new file mode 100644
index 0000000..b3c24fe
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysLogininfor.java
@@ -0,0 +1,159 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import java.util.Date;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.annotation.Excel.ColumnType;
+import com.playlet.common.core.domain.BaseEntity;
+
+/**
+ * 系统访问记录表 sys_logininfor
+ *
+ * @author ruoyi
+ */
+public class SysLogininfor extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** ID */
+ @Excel(name = "序号", cellType = ColumnType.NUMERIC)
+ private Long infoId;
+
+ /** 用户账号 */
+ @Excel(name = "用户账号")
+ private String loginName;
+
+ /** 登录状态 0成功 1失败 */
+ @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败")
+ private String status;
+
+ /** 登录IP地址 */
+ @Excel(name = "登录地址")
+ private String ipaddr;
+
+ /** 登录地点 */
+ @Excel(name = "登录地点")
+ private String loginLocation;
+
+ /** 浏览器类型 */
+ @Excel(name = "浏览器")
+ private String browser;
+
+ /** 操作系统 */
+ @Excel(name = "操作系统")
+ private String os;
+
+ /** 提示消息 */
+ @Excel(name = "提示消息")
+ private String msg;
+
+ /** 访问时间 */
+ @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date loginTime;
+
+ public Long getInfoId()
+ {
+ return infoId;
+ }
+
+ public void setInfoId(Long infoId)
+ {
+ this.infoId = infoId;
+ }
+
+ public String getLoginName()
+ {
+ return loginName;
+ }
+
+ public void setLoginName(String loginName)
+ {
+ this.loginName = loginName;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getIpaddr()
+ {
+ return ipaddr;
+ }
+
+ public void setIpaddr(String ipaddr)
+ {
+ this.ipaddr = ipaddr;
+ }
+
+ public String getLoginLocation()
+ {
+ return loginLocation;
+ }
+
+ public void setLoginLocation(String loginLocation)
+ {
+ this.loginLocation = loginLocation;
+ }
+
+ public String getBrowser()
+ {
+ return browser;
+ }
+
+ public void setBrowser(String browser)
+ {
+ this.browser = browser;
+ }
+
+ public String getOs()
+ {
+ return os;
+ }
+
+ public void setOs(String os)
+ {
+ this.os = os;
+ }
+
+ public String getMsg()
+ {
+ return msg;
+ }
+
+ public void setMsg(String msg)
+ {
+ this.msg = msg;
+ }
+
+ public Date getLoginTime()
+ {
+ return loginTime;
+ }
+
+ public void setLoginTime(Date loginTime)
+ {
+ this.loginTime = loginTime;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("infoId", getInfoId())
+ .append("loginName", getLoginName())
+ .append("ipaddr", getIpaddr())
+ .append("loginLocation", getLoginLocation())
+ .append("browser", getBrowser())
+ .append("os", getOs())
+ .append("status", getStatus())
+ .append("msg", getMsg())
+ .append("loginTime", getLoginTime())
+ .toString();
+ }
+}
\ No newline at end of file
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java b/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java
new file mode 100644
index 0000000..1a8cff4
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysNotice.java
@@ -0,0 +1,102 @@
+package com.playlet.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.core.domain.BaseEntity;
+import com.playlet.common.xss.Xss;
+
+/**
+ * 通知公告表 sys_notice
+ *
+ * @author ruoyi
+ */
+public class SysNotice extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 公告ID */
+ private Long noticeId;
+
+ /** 公告标题 */
+ private String noticeTitle;
+
+ /** 公告类型(1通知 2公告) */
+ private String noticeType;
+
+ /** 公告内容 */
+ private String noticeContent;
+
+ /** 公告状态(0正常 1关闭) */
+ private String status;
+
+ public Long getNoticeId()
+ {
+ return noticeId;
+ }
+
+ public void setNoticeId(Long noticeId)
+ {
+ this.noticeId = noticeId;
+ }
+
+ public void setNoticeTitle(String noticeTitle)
+ {
+ this.noticeTitle = noticeTitle;
+ }
+
+ @Xss(message = "公告标题不能包含脚本字符")
+ @NotBlank(message = "公告标题不能为空")
+ @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
+ public String getNoticeTitle()
+ {
+ return noticeTitle;
+ }
+
+ public void setNoticeType(String noticeType)
+ {
+ this.noticeType = noticeType;
+ }
+
+ public String getNoticeType()
+ {
+ return noticeType;
+ }
+
+ public void setNoticeContent(String noticeContent)
+ {
+ this.noticeContent = noticeContent;
+ }
+
+ public String getNoticeContent()
+ {
+ return noticeContent;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("noticeId", getNoticeId())
+ .append("noticeTitle", getNoticeTitle())
+ .append("noticeType", getNoticeType())
+ .append("noticeContent", getNoticeContent())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java b/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java
new file mode 100644
index 0000000..9c4cb1c
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysOperLog.java
@@ -0,0 +1,292 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import java.util.Date;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.annotation.Excel.ColumnType;
+import com.playlet.common.core.domain.BaseEntity;
+
+/**
+ * 操作日志记录表 oper_log
+ *
+ * @author ruoyi
+ */
+public class SysOperLog extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 日志主键 */
+ @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
+ private Long operId;
+
+ /** 操作模块 */
+ @Excel(name = "操作模块")
+ private String title;
+
+ /** 业务类型(0其它 1新增 2修改 3删除) */
+ @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
+ private Integer businessType;
+
+ /** 业务类型数组 */
+ private Integer[] businessTypes;
+
+ /** 请求方法 */
+ @Excel(name = "请求方法")
+ private String method;
+
+ /** 请求方式 */
+ @Excel(name = "请求方式")
+ private String requestMethod;
+
+ /** 操作类别(0其它 1后台用户 2手机端用户) */
+ @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
+ private Integer operatorType;
+
+ /** 操作人员 */
+ @Excel(name = "操作人员")
+ private String operName;
+
+ /** 部门名称 */
+ @Excel(name = "部门名称")
+ private String deptName;
+
+ /** 请求url */
+ @Excel(name = "请求地址")
+ private String operUrl;
+
+ /** 操作地址 */
+ @Excel(name = "操作地址")
+ private String operIp;
+
+ /** 操作地点 */
+ @Excel(name = "操作地点")
+ private String operLocation;
+
+ /** 请求参数 */
+ @Excel(name = "请求参数")
+ private String operParam;
+
+ /** 返回参数 */
+ @Excel(name = "返回参数")
+ private String jsonResult;
+
+ /** 操作状态(0正常 1异常) */
+ @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
+ private Integer status;
+
+ /** 错误消息 */
+ @Excel(name = "错误消息")
+ private String errorMsg;
+
+ /** 操作时间 */
+ @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private Date operTime;
+
+ /** 消耗时间 */
+ @Excel(name = "消耗时间", suffix = "毫秒")
+ private Long costTime;
+
+ public Long getOperId()
+ {
+ return operId;
+ }
+
+ public void setOperId(Long operId)
+ {
+ this.operId = operId;
+ }
+
+ public String getTitle()
+ {
+ return title;
+ }
+
+ public void setTitle(String title)
+ {
+ this.title = title;
+ }
+
+ public Integer getBusinessType()
+ {
+ return businessType;
+ }
+
+ public void setBusinessType(Integer businessType)
+ {
+ this.businessType = businessType;
+ }
+
+ public Integer[] getBusinessTypes()
+ {
+ return businessTypes;
+ }
+
+ public void setBusinessTypes(Integer[] businessTypes)
+ {
+ this.businessTypes = businessTypes;
+ }
+
+ public String getMethod()
+ {
+ return method;
+ }
+
+ public void setMethod(String method)
+ {
+ this.method = method;
+ }
+
+ public String getRequestMethod()
+ {
+ return requestMethod;
+ }
+
+ public void setRequestMethod(String requestMethod)
+ {
+ this.requestMethod = requestMethod;
+ }
+
+ public Integer getOperatorType()
+ {
+ return operatorType;
+ }
+
+ public void setOperatorType(Integer operatorType)
+ {
+ this.operatorType = operatorType;
+ }
+
+ public String getOperName()
+ {
+ return operName;
+ }
+
+ public void setOperName(String operName)
+ {
+ this.operName = operName;
+ }
+
+ public String getDeptName()
+ {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName)
+ {
+ this.deptName = deptName;
+ }
+
+ public String getOperUrl()
+ {
+ return operUrl;
+ }
+
+ public void setOperUrl(String operUrl)
+ {
+ this.operUrl = operUrl;
+ }
+
+ public String getOperIp()
+ {
+ return operIp;
+ }
+
+ public void setOperIp(String operIp)
+ {
+ this.operIp = operIp;
+ }
+
+ public String getOperLocation()
+ {
+ return operLocation;
+ }
+
+ public void setOperLocation(String operLocation)
+ {
+ this.operLocation = operLocation;
+ }
+
+ public String getOperParam()
+ {
+ return operParam;
+ }
+
+ public void setOperParam(String operParam)
+ {
+ this.operParam = operParam;
+ }
+
+ public String getJsonResult()
+ {
+ return jsonResult;
+ }
+
+ public void setJsonResult(String jsonResult)
+ {
+ this.jsonResult = jsonResult;
+ }
+
+ public Integer getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(Integer status)
+ {
+ this.status = status;
+ }
+
+ public String getErrorMsg()
+ {
+ return errorMsg;
+ }
+
+ public void setErrorMsg(String errorMsg)
+ {
+ this.errorMsg = errorMsg;
+ }
+
+ public Date getOperTime()
+ {
+ return operTime;
+ }
+
+ public void setOperTime(Date operTime)
+ {
+ this.operTime = operTime;
+ }
+
+ public Long getCostTime()
+ {
+ return costTime;
+ }
+
+ public void setCostTime(Long costTime)
+ {
+ this.costTime = costTime;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("operId", getOperId())
+ .append("title", getTitle())
+ .append("businessType", getBusinessType())
+ .append("businessTypes", getBusinessTypes())
+ .append("method", getMethod())
+ .append("requestMethod", getRequestMethod())
+ .append("operatorType", getOperatorType())
+ .append("operName", getOperName())
+ .append("deptName", getDeptName())
+ .append("operUrl", getOperUrl())
+ .append("operIp", getOperIp())
+ .append("operLocation", getOperLocation())
+ .append("operParam", getOperParam())
+ .append("status", getStatus())
+ .append("errorMsg", getErrorMsg())
+ .append("operTime", getOperTime())
+ .append("costTime", getCostTime())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java b/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java
new file mode 100644
index 0000000..bd72d07
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysPost.java
@@ -0,0 +1,122 @@
+package com.playlet.system.domain;
+
+import javax.validation.constraints.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.annotation.Excel;
+import com.playlet.common.annotation.Excel.ColumnType;
+import com.playlet.common.core.domain.BaseEntity;
+
+/**
+ * 岗位表 sys_post
+ *
+ * @author ruoyi
+ */
+public class SysPost extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 岗位序号 */
+ @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
+ private Long postId;
+
+ /** 岗位编码 */
+ @Excel(name = "岗位编码")
+ private String postCode;
+
+ /** 岗位名称 */
+ @Excel(name = "岗位名称")
+ private String postName;
+
+ /** 岗位排序 */
+ @Excel(name = "岗位排序", cellType = ColumnType.NUMERIC)
+ private String postSort;
+
+ /** 状态(0正常 1停用) */
+ @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+ private String status;
+
+ /** 用户是否存在此岗位标识 默认不存在 */
+ private boolean flag = false;
+
+ public Long getPostId()
+ {
+ return postId;
+ }
+
+ public void setPostId(Long postId)
+ {
+ this.postId = postId;
+ }
+
+ @NotBlank(message = "岗位编码不能为空")
+ @Size(min = 0, max = 64, message = "岗位编码长度不能超过64个字符")
+ public String getPostCode()
+ {
+ return postCode;
+ }
+
+ public void setPostCode(String postCode)
+ {
+ this.postCode = postCode;
+ }
+
+ @NotBlank(message = "岗位名称不能为空")
+ @Size(min = 0, max = 50, message = "岗位名称长度不能超过50个字符")
+ public String getPostName()
+ {
+ return postName;
+ }
+
+ public void setPostName(String postName)
+ {
+ this.postName = postName;
+ }
+
+ @NotBlank(message = "显示顺序不能为空")
+ public String getPostSort()
+ {
+ return postSort;
+ }
+
+ public void setPostSort(String postSort)
+ {
+ this.postSort = postSort;
+ }
+
+ public String getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(String status)
+ {
+ this.status = status;
+ }
+
+ public boolean isFlag()
+ {
+ return flag;
+ }
+
+ public void setFlag(boolean flag)
+ {
+ this.flag = flag;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("postId", getPostId())
+ .append("postCode", getPostCode())
+ .append("postName", getPostName())
+ .append("postSort", getPostSort())
+ .append("status", getStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .append("remark", getRemark())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java
new file mode 100644
index 0000000..ecca39c
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleDept.java
@@ -0,0 +1,46 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 角色和部门关联 sys_role_dept
+ *
+ * @author ruoyi
+ */
+public class SysRoleDept
+{
+ /** 角色ID */
+ private Long roleId;
+
+ /** 部门ID */
+ private Long deptId;
+
+ public Long getRoleId()
+ {
+ return roleId;
+ }
+
+ public void setRoleId(Long roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ public Long getDeptId()
+ {
+ return deptId;
+ }
+
+ public void setDeptId(Long deptId)
+ {
+ this.deptId = deptId;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("roleId", getRoleId())
+ .append("deptId", getDeptId())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java
new file mode 100644
index 0000000..68aa87a
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysRoleMenu.java
@@ -0,0 +1,46 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 角色和菜单关联 sys_role_menu
+ *
+ * @author ruoyi
+ */
+public class SysRoleMenu
+{
+ /** 角色ID */
+ private Long roleId;
+
+ /** 菜单ID */
+ private Long menuId;
+
+ public Long getRoleId()
+ {
+ return roleId;
+ }
+
+ public void setRoleId(Long roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ public Long getMenuId()
+ {
+ return menuId;
+ }
+
+ public void setMenuId(Long menuId)
+ {
+ this.menuId = menuId;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("roleId", getRoleId())
+ .append("menuId", getMenuId())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java
new file mode 100644
index 0000000..be63a8d
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserOnline.java
@@ -0,0 +1,177 @@
+package com.playlet.system.domain;
+
+import java.util.Date;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.playlet.common.core.domain.BaseEntity;
+import com.playlet.common.enums.OnlineStatus;
+
+/**
+ * 当前在线会话 sys_user_online
+ *
+ * @author ruoyi
+ */
+public class SysUserOnline extends BaseEntity
+{
+ private static final long serialVersionUID = 1L;
+
+ /** 用户会话id */
+ private String sessionId;
+
+ /** 部门名称 */
+ private String deptName;
+
+ /** 登录名称 */
+ private String loginName;
+
+ /** 登录IP地址 */
+ private String ipaddr;
+
+ /** 登录地址 */
+ private String loginLocation;
+
+ /** 浏览器类型 */
+ private String browser;
+
+ /** 操作系统 */
+ private String os;
+
+ /** session创建时间 */
+ private Date startTimestamp;
+
+ /** session最后访问时间 */
+ private Date lastAccessTime;
+
+ /** 超时时间,单位为分钟 */
+ private Long expireTime;
+
+ /** 在线状态 */
+ private OnlineStatus status = OnlineStatus.on_line;
+
+ public String getSessionId()
+ {
+ return sessionId;
+ }
+
+ public void setSessionId(String sessionId)
+ {
+ this.sessionId = sessionId;
+ }
+
+ public String getDeptName()
+ {
+ return deptName;
+ }
+
+ public void setDeptName(String deptName)
+ {
+ this.deptName = deptName;
+ }
+
+ public String getLoginName()
+ {
+ return loginName;
+ }
+
+ public void setLoginName(String loginName)
+ {
+ this.loginName = loginName;
+ }
+
+ public String getIpaddr()
+ {
+ return ipaddr;
+ }
+
+ public void setIpaddr(String ipaddr)
+ {
+ this.ipaddr = ipaddr;
+ }
+
+ public String getLoginLocation()
+ {
+ return loginLocation;
+ }
+
+ public void setLoginLocation(String loginLocation)
+ {
+ this.loginLocation = loginLocation;
+ }
+
+ public String getBrowser()
+ {
+ return browser;
+ }
+
+ public void setBrowser(String browser)
+ {
+ this.browser = browser;
+ }
+
+ public String getOs()
+ {
+ return os;
+ }
+
+ public void setOs(String os)
+ {
+ this.os = os;
+ }
+
+ public Date getStartTimestamp()
+ {
+ return startTimestamp;
+ }
+
+ public void setStartTimestamp(Date startTimestamp)
+ {
+ this.startTimestamp = startTimestamp;
+ }
+
+ public Date getLastAccessTime()
+ {
+ return lastAccessTime;
+ }
+
+ public void setLastAccessTime(Date lastAccessTime)
+ {
+ this.lastAccessTime = lastAccessTime;
+ }
+
+ public Long getExpireTime()
+ {
+ return expireTime;
+ }
+
+ public void setExpireTime(Long expireTime)
+ {
+ this.expireTime = expireTime;
+ }
+
+ public OnlineStatus getStatus()
+ {
+ return status;
+ }
+
+ public void setStatus(OnlineStatus status)
+ {
+ this.status = status;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("sessionId", getSessionId())
+ .append("loginName", getLoginName())
+ .append("deptName", getDeptName())
+ .append("ipaddr", getIpaddr())
+ .append("loginLocation", getLoginLocation())
+ .append("browser", getBrowser())
+ .append("os", getOs())
+ .append("status", getStatus())
+ .append("startTimestamp", getStartTimestamp())
+ .append("lastAccessTime", getLastAccessTime())
+ .append("expireTime", getExpireTime())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java
new file mode 100644
index 0000000..a0c327a
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserPost.java
@@ -0,0 +1,46 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 用户和岗位关联 sys_user_post
+ *
+ * @author ruoyi
+ */
+public class SysUserPost
+{
+ /** 用户ID */
+ private Long userId;
+
+ /** 岗位ID */
+ private Long postId;
+
+ public Long getUserId()
+ {
+ return userId;
+ }
+
+ public void setUserId(Long userId)
+ {
+ this.userId = userId;
+ }
+
+ public Long getPostId()
+ {
+ return postId;
+ }
+
+ public void setPostId(Long postId)
+ {
+ this.postId = postId;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("userId", getUserId())
+ .append("postId", getPostId())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java b/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java
new file mode 100644
index 0000000..bad96b5
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/domain/SysUserRole.java
@@ -0,0 +1,46 @@
+package com.playlet.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 用户和角色关联 sys_user_role
+ *
+ * @author ruoyi
+ */
+public class SysUserRole
+{
+ /** 用户ID */
+ private Long userId;
+
+ /** 角色ID */
+ private Long roleId;
+
+ public Long getUserId()
+ {
+ return userId;
+ }
+
+ public void setUserId(Long userId)
+ {
+ this.userId = userId;
+ }
+
+ public Long getRoleId()
+ {
+ return roleId;
+ }
+
+ public void setRoleId(Long roleId)
+ {
+ this.roleId = roleId;
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+ .append("userId", getUserId())
+ .append("roleId", getRoleId())
+ .toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..e8b4274
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysConfigMapper.java
@@ -0,0 +1,76 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysConfig;
+
+/**
+ * 参数配置 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysConfigMapper
+{
+ /**
+ * 查询参数配置信息
+ *
+ * @param config 参数配置信息
+ * @return 参数配置信息
+ */
+ public SysConfig selectConfig(SysConfig config);
+
+ /**
+ * 通过ID查询配置
+ *
+ * @param configId 参数ID
+ * @return 参数配置信息
+ */
+ public SysConfig selectConfigById(Long configId);
+
+ /**
+ * 查询参数配置列表
+ *
+ * @param config 参数配置信息
+ * @return 参数配置集合
+ */
+ public List selectConfigList(SysConfig config);
+
+ /**
+ * 根据键名查询参数配置信息
+ *
+ * @param configKey 参数键名
+ * @return 参数配置信息
+ */
+ public SysConfig checkConfigKeyUnique(String configKey);
+
+ /**
+ * 新增参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ public int insertConfig(SysConfig config);
+
+ /**
+ * 修改参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ public int updateConfig(SysConfig config);
+
+ /**
+ * 删除参数配置
+ *
+ * @param configId 参数主键
+ * @return 结果
+ */
+ public int deleteConfigById(Long configId);
+
+ /**
+ * 批量删除参数配置
+ *
+ * @param configIds 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteConfigByIds(String[] configIds);
+}
\ No newline at end of file
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..bdf163d
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDeptMapper.java
@@ -0,0 +1,117 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.playlet.common.core.domain.entity.SysDept;
+
+/**
+ * 部门管理 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysDeptMapper
+{
+ /**
+ * 查询下级部门数量
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public int selectDeptCount(SysDept dept);
+
+ /**
+ * 查询部门是否存在用户
+ *
+ * @param deptId 部门ID
+ * @return 结果
+ */
+ public int checkDeptExistUser(Long deptId);
+
+ /**
+ * 查询部门管理数据
+ *
+ * @param dept 部门信息
+ * @return 部门信息集合
+ */
+ public List selectDeptList(SysDept dept);
+
+ /**
+ * 删除部门管理信息
+ *
+ * @param deptId 部门ID
+ * @return 结果
+ */
+ public int deleteDeptById(Long deptId);
+
+ /**
+ * 新增部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public int insertDept(SysDept dept);
+
+ /**
+ * 修改部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public int updateDept(SysDept dept);
+
+ /**
+ * 修改子元素关系
+ *
+ * @param depts 子元素
+ * @return 结果
+ */
+ public int updateDeptChildren(@Param("depts") List depts);
+
+ /**
+ * 根据部门ID查询信息
+ *
+ * @param deptId 部门ID
+ * @return 部门信息
+ */
+ public SysDept selectDeptById(Long deptId);
+
+ /**
+ * 校验部门名称是否唯一
+ *
+ * @param deptName 部门名称
+ * @param parentId 父部门ID
+ * @return 结果
+ */
+ public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
+
+ /**
+ * 根据角色ID查询部门
+ *
+ * @param roleId 角色ID
+ * @return 部门列表
+ */
+ public List selectRoleDeptTree(Long roleId);
+
+ /**
+ * 修改所在部门正常状态
+ *
+ * @param deptIds 部门ID组
+ */
+ public void updateDeptStatusNormal(Long[] deptIds);
+
+ /**
+ * 根据ID查询所有子部门
+ *
+ * @param deptId 部门ID
+ * @return 部门列表
+ */
+ public List selectChildrenDeptById(Long deptId);
+
+ /**
+ * 根据ID查询所有子部门(正常状态)
+ *
+ * @param deptId 部门ID
+ * @return 子部门数
+ */
+ public int selectNormalChildrenDeptById(Long deptId);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..cd963fb
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictDataMapper.java
@@ -0,0 +1,95 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.playlet.common.core.domain.entity.SysDictData;
+
+/**
+ * 字典表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysDictDataMapper
+{
+ /**
+ * 根据条件分页查询字典数据
+ *
+ * @param dictData 字典数据信息
+ * @return 字典数据集合信息
+ */
+ public List selectDictDataList(SysDictData dictData);
+
+ /**
+ * 根据字典类型查询字典数据
+ *
+ * @param dictType 字典类型
+ * @return 字典数据集合信息
+ */
+ public List selectDictDataByType(String dictType);
+
+ /**
+ * 根据字典类型和字典键值查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典键值
+ * @return 字典标签
+ */
+ public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue);
+
+ /**
+ * 根据字典数据ID查询信息
+ *
+ * @param dictCode 字典数据ID
+ * @return 字典数据
+ */
+ public SysDictData selectDictDataById(Long dictCode);
+
+ /**
+ * 查询字典数据
+ *
+ * @param dictType 字典类型
+ * @return 字典数据
+ */
+ public int countDictDataByType(String dictType);
+
+ /**
+ * 通过字典ID删除字典数据信息
+ *
+ * @param dictCode 字典数据ID
+ * @return 结果
+ */
+ public int deleteDictDataById(Long dictCode);
+
+ /**
+ * 批量删除字典数据
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteDictDataByIds(String[] ids);
+
+ /**
+ * 新增字典数据信息
+ *
+ * @param dictData 字典数据信息
+ * @return 结果
+ */
+ public int insertDictData(SysDictData dictData);
+
+ /**
+ * 修改字典数据信息
+ *
+ * @param dictData 字典数据信息
+ * @return 结果
+ */
+ public int updateDictData(SysDictData dictData);
+
+ /**
+ * 同步修改字典类型
+ *
+ * @param oldDictType 旧字典类型
+ * @param newDictType 新旧字典类型
+ * @return 结果
+ */
+ public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..ea2e2ee
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysDictTypeMapper.java
@@ -0,0 +1,83 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.common.core.domain.entity.SysDictType;
+
+/**
+ * 字典表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysDictTypeMapper
+{
+ /**
+ * 根据条件分页查询字典类型
+ *
+ * @param dictType 字典类型信息
+ * @return 字典类型集合信息
+ */
+ public List selectDictTypeList(SysDictType dictType);
+
+ /**
+ * 根据所有字典类型
+ *
+ * @return 字典类型集合信息
+ */
+ public List selectDictTypeAll();
+
+ /**
+ * 根据字典类型ID查询信息
+ *
+ * @param dictId 字典类型ID
+ * @return 字典类型
+ */
+ public SysDictType selectDictTypeById(Long dictId);
+
+ /**
+ * 根据字典类型查询信息
+ *
+ * @param dictType 字典类型
+ * @return 字典类型
+ */
+ public SysDictType selectDictTypeByType(String dictType);
+
+ /**
+ * 通过字典ID删除字典信息
+ *
+ * @param dictId 字典ID
+ * @return 结果
+ */
+ public int deleteDictTypeById(Long dictId);
+
+ /**
+ * 批量删除字典类型
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteDictTypeByIds(Long[] ids);
+
+ /**
+ * 新增字典类型信息
+ *
+ * @param dictType 字典类型信息
+ * @return 结果
+ */
+ public int insertDictType(SysDictType dictType);
+
+ /**
+ * 修改字典类型信息
+ *
+ * @param dictType 字典类型信息
+ * @return 结果
+ */
+ public int updateDictType(SysDictType dictType);
+
+ /**
+ * 校验字典类型称是否唯一
+ *
+ * @param dictType 字典类型
+ * @return 结果
+ */
+ public SysDictType checkDictTypeUnique(String dictType);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java
new file mode 100644
index 0000000..b44a084
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysLogininforMapper.java
@@ -0,0 +1,42 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysLogininfor;
+
+/**
+ * 系统访问日志情况信息 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysLogininforMapper
+{
+ /**
+ * 新增系统登录日志
+ *
+ * @param logininfor 访问日志对象
+ */
+ public void insertLogininfor(SysLogininfor logininfor);
+
+ /**
+ * 查询系统登录日志集合
+ *
+ * @param logininfor 访问日志对象
+ * @return 登录记录集合
+ */
+ public List selectLogininforList(SysLogininfor logininfor);
+
+ /**
+ * 批量删除系统登录日志
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteLogininforByIds(String[] ids);
+
+ /**
+ * 清空系统登录日志
+ *
+ * @return 结果
+ */
+ public int cleanLogininfor();
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..7f1d789
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysMenuMapper.java
@@ -0,0 +1,132 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.playlet.common.core.domain.entity.SysMenu;
+
+/**
+ * 菜单表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysMenuMapper
+{
+ /**
+ * 查询系统所有菜单(含按钮)
+ *
+ * @return 菜单列表
+ */
+ public List selectMenuAll();
+
+ /**
+ * 根据用户ID查询菜单
+ *
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ public List selectMenuAllByUserId(Long userId);
+
+ /**
+ * 查询系统正常显示菜单(不含按钮)
+ *
+ * @return 菜单列表
+ */
+ public List selectMenuNormalAll();
+
+ /**
+ * 根据用户ID查询菜单
+ *
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ public List selectMenusByUserId(Long userId);
+
+ /**
+ * 根据用户ID查询权限
+ *
+ * @param userId 用户ID
+ * @return 权限列表
+ */
+ public List selectPermsByUserId(Long userId);
+
+ /**
+ * 根据角色ID查询权限
+ *
+ * @param roleId 角色ID
+ * @return 权限列表
+ */
+ public List selectPermsByRoleId(Long roleId);
+
+ /**
+ * 根据角色ID查询菜单
+ *
+ * @param roleId 角色ID
+ * @return 菜单列表
+ */
+ public List selectMenuTree(Long roleId);
+
+ /**
+ * 查询系统菜单列表
+ *
+ * @param menu 菜单信息
+ * @return 菜单列表
+ */
+ public List selectMenuList(SysMenu menu);
+
+ /**
+ * 查询系统菜单列表
+ *
+ * @param menu 菜单信息
+ * @return 菜单列表
+ */
+ public List selectMenuListByUserId(SysMenu menu);
+
+ /**
+ * 删除菜单管理信息
+ *
+ * @param menuId 菜单ID
+ * @return 结果
+ */
+ public int deleteMenuById(Long menuId);
+
+ /**
+ * 根据菜单ID查询信息
+ *
+ * @param menuId 菜单ID
+ * @return 菜单信息
+ */
+ public SysMenu selectMenuById(Long menuId);
+
+ /**
+ * 查询菜单数量
+ *
+ * @param parentId 菜单父ID
+ * @return 结果
+ */
+ public int selectCountMenuByParentId(Long parentId);
+
+ /**
+ * 新增菜单信息
+ *
+ * @param menu 菜单信息
+ * @return 结果
+ */
+ public int insertMenu(SysMenu menu);
+
+ /**
+ * 修改菜单信息
+ *
+ * @param menu 菜单信息
+ * @return 结果
+ */
+ public int updateMenu(SysMenu menu);
+
+ /**
+ * 校验菜单名称是否唯一
+ *
+ * @param menuName 菜单名称
+ * @param parentId 父菜单ID
+ * @return 结果
+ */
+ public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java
new file mode 100644
index 0000000..9df5238
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysNoticeMapper.java
@@ -0,0 +1,52 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysNotice;
+
+/**
+ * 公告 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysNoticeMapper
+{
+ /**
+ * 查询公告信息
+ *
+ * @param noticeId 公告ID
+ * @return 公告信息
+ */
+ public SysNotice selectNoticeById(Long noticeId);
+
+ /**
+ * 查询公告列表
+ *
+ * @param notice 公告信息
+ * @return 公告集合
+ */
+ public List selectNoticeList(SysNotice notice);
+
+ /**
+ * 新增公告
+ *
+ * @param notice 公告信息
+ * @return 结果
+ */
+ public int insertNotice(SysNotice notice);
+
+ /**
+ * 修改公告
+ *
+ * @param notice 公告信息
+ * @return 结果
+ */
+ public int updateNotice(SysNotice notice);
+
+ /**
+ * 批量删除公告
+ *
+ * @param noticeIds 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteNoticeByIds(String[] noticeIds);
+}
\ No newline at end of file
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java
new file mode 100644
index 0000000..dad2349
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysOperLogMapper.java
@@ -0,0 +1,48 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysOperLog;
+
+/**
+ * 操作日志 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysOperLogMapper
+{
+ /**
+ * 新增操作日志
+ *
+ * @param operLog 操作日志对象
+ */
+ public void insertOperlog(SysOperLog operLog);
+
+ /**
+ * 查询系统操作日志集合
+ *
+ * @param operLog 操作日志对象
+ * @return 操作日志集合
+ */
+ public List selectOperLogList(SysOperLog operLog);
+
+ /**
+ * 批量删除系统操作日志
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteOperLogByIds(String[] ids);
+
+ /**
+ * 查询操作日志详细
+ *
+ * @param operId 操作ID
+ * @return 操作日志对象
+ */
+ public SysOperLog selectOperLogById(Long operId);
+
+ /**
+ * 清空操作日志
+ */
+ public void cleanOperLog();
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java
new file mode 100644
index 0000000..498feb5
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysPostMapper.java
@@ -0,0 +1,83 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysPost;
+
+/**
+ * 岗位信息 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysPostMapper
+{
+ /**
+ * 查询岗位数据集合
+ *
+ * @param post 岗位信息
+ * @return 岗位数据集合
+ */
+ public List selectPostList(SysPost post);
+
+ /**
+ * 查询所有岗位
+ *
+ * @return 岗位列表
+ */
+ public List selectPostAll();
+
+ /**
+ * 根据用户ID查询岗位
+ *
+ * @param userId 用户ID
+ * @return 岗位列表
+ */
+ public List selectPostsByUserId(Long userId);
+
+ /**
+ * 通过岗位ID查询岗位信息
+ *
+ * @param postId 岗位ID
+ * @return 角色对象信息
+ */
+ public SysPost selectPostById(Long postId);
+
+ /**
+ * 批量删除岗位信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deletePostByIds(Long[] ids);
+
+ /**
+ * 修改岗位信息
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public int updatePost(SysPost post);
+
+ /**
+ * 新增岗位信息
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public int insertPost(SysPost post);
+
+ /**
+ * 校验岗位名称
+ *
+ * @param postName 岗位名称
+ * @return 结果
+ */
+ public SysPost checkPostNameUnique(String postName);
+
+ /**
+ * 校验岗位编码
+ *
+ * @param postCode 岗位编码
+ * @return 结果
+ */
+ public SysPost checkPostCodeUnique(String postCode);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java
new file mode 100644
index 0000000..ea4f0d6
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleDeptMapper.java
@@ -0,0 +1,44 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysRoleDept;
+
+/**
+ * 角色与部门关联表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysRoleDeptMapper
+{
+ /**
+ * 通过角色ID删除角色和部门关联
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public int deleteRoleDeptByRoleId(Long roleId);
+
+ /**
+ * 批量删除角色部门关联信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteRoleDept(Long[] ids);
+
+ /**
+ * 查询部门使用数量
+ *
+ * @param deptId 部门ID
+ * @return 结果
+ */
+ public int selectCountRoleDeptByDeptId(Long deptId);
+
+ /**
+ * 批量新增角色部门信息
+ *
+ * @param roleDeptList 角色部门列表
+ * @return 结果
+ */
+ public int batchRoleDept(List roleDeptList);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..3d1d87a
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMapper.java
@@ -0,0 +1,84 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.common.core.domain.entity.SysRole;
+
+/**
+ * 角色表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysRoleMapper
+{
+ /**
+ * 根据条件分页查询角色数据
+ *
+ * @param role 角色信息
+ * @return 角色数据集合信息
+ */
+ public List selectRoleList(SysRole role);
+
+ /**
+ * 根据用户ID查询角色
+ *
+ * @param userId 用户ID
+ * @return 角色列表
+ */
+ public List selectRolesByUserId(Long userId);
+
+ /**
+ * 通过角色ID查询角色
+ *
+ * @param roleId 角色ID
+ * @return 角色对象信息
+ */
+ public SysRole selectRoleById(Long roleId);
+
+ /**
+ * 通过角色ID删除角色
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public int deleteRoleById(Long roleId);
+
+ /**
+ * 批量角色用户信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteRoleByIds(Long[] ids);
+
+ /**
+ * 修改角色信息
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int updateRole(SysRole role);
+
+ /**
+ * 新增角色信息
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int insertRole(SysRole role);
+
+ /**
+ * 校验角色名称是否唯一
+ *
+ * @param roleName 角色名称
+ * @return 角色信息
+ */
+ public SysRole checkRoleNameUnique(String roleName);
+
+ /**
+ * 校验角色权限是否唯一
+ *
+ * @param roleKey 角色权限
+ * @return 角色信息
+ */
+ public SysRole checkRoleKeyUnique(String roleKey);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..4eb503e
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysRoleMenuMapper.java
@@ -0,0 +1,44 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysRoleMenu;
+
+/**
+ * 角色与菜单关联表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysRoleMenuMapper
+{
+ /**
+ * 通过角色ID删除角色和菜单关联
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public int deleteRoleMenuByRoleId(Long roleId);
+
+ /**
+ * 批量删除角色菜单关联信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteRoleMenu(Long[] ids);
+
+ /**
+ * 查询菜单使用数量
+ *
+ * @param menuId 菜单ID
+ * @return 结果
+ */
+ public int selectCountRoleMenuByMenuId(Long menuId);
+
+ /**
+ * 批量新增角色菜单信息
+ *
+ * @param roleMenuList 角色菜单列表
+ * @return 结果
+ */
+ public int batchRoleMenu(List roleMenuList);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..5dfce04
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserMapper.java
@@ -0,0 +1,124 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.common.core.domain.entity.SysUser;
+
+/**
+ * 用户表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysUserMapper
+{
+ /**
+ * 根据条件分页查询用户列表
+ *
+ * @param sysUser 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectUserList(SysUser sysUser);
+
+ /**
+ * 根据条件分页查询已配用户角色列表
+ *
+ * @param user 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectAllocatedList(SysUser user);
+
+ /**
+ * 根据条件分页查询未分配用户角色列表
+ *
+ * @param user 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectUnallocatedList(SysUser user);
+
+ /**
+ * 通过用户名查询用户
+ *
+ * @param userName 用户名
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByLoginName(String userName);
+
+ /**
+ * 通过手机号码查询用户
+ *
+ * @param phoneNumber 手机号码
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByPhoneNumber(String phoneNumber);
+
+ /**
+ * 通过邮箱查询用户
+ *
+ * @param email 邮箱
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByEmail(String email);
+
+ /**
+ * 通过用户ID查询用户
+ *
+ * @param userId 用户ID
+ * @return 用户对象信息
+ */
+ public SysUser selectUserById(Long userId);
+
+ /**
+ * 通过用户ID删除用户
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public int deleteUserById(Long userId);
+
+ /**
+ * 批量删除用户信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteUserByIds(Long[] ids);
+
+ /**
+ * 修改用户信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int updateUser(SysUser user);
+
+ /**
+ * 新增用户信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int insertUser(SysUser user);
+
+ /**
+ * 校验用户名称是否唯一
+ *
+ * @param loginName 登录名称
+ * @return 结果
+ */
+ public SysUser checkLoginNameUnique(String loginName);
+
+ /**
+ * 校验手机号码是否唯一
+ *
+ * @param phonenumber 手机号码
+ * @return 结果
+ */
+ public SysUser checkPhoneUnique(String phonenumber);
+
+ /**
+ * 校验email是否唯一
+ *
+ * @param email 用户邮箱
+ * @return 结果
+ */
+ public SysUser checkEmailUnique(String email);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java
new file mode 100644
index 0000000..75360a2
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserOnlineMapper.java
@@ -0,0 +1,52 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysUserOnline;
+
+/**
+ * 在线用户 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysUserOnlineMapper
+{
+ /**
+ * 通过会话序号查询信息
+ *
+ * @param sessionId 会话ID
+ * @return 在线用户信息
+ */
+ public SysUserOnline selectOnlineById(String sessionId);
+
+ /**
+ * 通过会话序号删除信息
+ *
+ * @param sessionId 会话ID
+ * @return 在线用户信息
+ */
+ public int deleteOnlineById(String sessionId);
+
+ /**
+ * 保存会话信息
+ *
+ * @param online 会话信息
+ * @return 结果
+ */
+ public int saveOnline(SysUserOnline online);
+
+ /**
+ * 查询会话集合
+ *
+ * @param userOnline 会话参数
+ * @return 会话集合
+ */
+ public List selectUserOnlineList(SysUserOnline userOnline);
+
+ /**
+ * 查询过期会话集合
+ *
+ * @param lastAccessTime 过期时间
+ * @return 会话集合
+ */
+ public List selectOnlineByExpired(String lastAccessTime);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java
new file mode 100644
index 0000000..4e19023
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserPostMapper.java
@@ -0,0 +1,44 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import com.playlet.system.domain.SysUserPost;
+
+/**
+ * 用户与岗位关联表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysUserPostMapper
+{
+ /**
+ * 通过用户ID删除用户和岗位关联
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public int deleteUserPostByUserId(Long userId);
+
+ /**
+ * 通过岗位ID查询岗位使用数量
+ *
+ * @param postId 岗位ID
+ * @return 结果
+ */
+ public int countUserPostById(Long postId);
+
+ /**
+ * 批量删除用户和岗位关联
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteUserPost(Long[] ids);
+
+ /**
+ * 批量新增用户岗位信息
+ *
+ * @param userPostList 用户岗位列表
+ * @return 结果
+ */
+ public int batchUserPost(List userPostList);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..44e04ef
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/mapper/SysUserRoleMapper.java
@@ -0,0 +1,70 @@
+package com.playlet.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.playlet.system.domain.SysUserRole;
+
+/**
+ * 用户与角色关联表 数据层
+ *
+ * @author ruoyi
+ */
+public interface SysUserRoleMapper
+{
+ /**
+ * 通过用户ID查询用户和角色关联
+ *
+ * @param userId 用户ID
+ * @return 用户和角色关联列表
+ */
+ public List selectUserRoleByUserId(Long userId);
+
+ /**
+ * 通过用户ID删除用户和角色关联
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public int deleteUserRoleByUserId(Long userId);
+
+ /**
+ * 批量删除用户和角色关联
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteUserRole(Long[] ids);
+
+ /**
+ * 通过角色ID查询角色使用数量
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public int countUserRoleByRoleId(Long roleId);
+
+ /**
+ * 批量新增用户角色信息
+ *
+ * @param userRoleList 用户角色列表
+ * @return 结果
+ */
+ public int batchUserRole(List userRoleList);
+
+ /**
+ * 删除用户和角色关联信息
+ *
+ * @param userRole 用户和角色关联信息
+ * @return 结果
+ */
+ public int deleteUserRoleInfo(SysUserRole userRole);
+
+ /**
+ * 批量取消授权用户角色
+ *
+ * @param roleId 角色ID
+ * @param userIds 需要删除的用户数据ID
+ * @return 结果
+ */
+ public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java
new file mode 100644
index 0000000..cf276b2
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysConfigService.java
@@ -0,0 +1,82 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.system.domain.SysConfig;
+
+/**
+ * 参数配置 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysConfigService
+{
+ /**
+ * 查询参数配置信息
+ *
+ * @param configId 参数配置ID
+ * @return 参数配置信息
+ */
+ public SysConfig selectConfigById(Long configId);
+
+ /**
+ * 根据键名查询参数配置信息
+ *
+ * @param configKey 参数键名
+ * @return 参数键值
+ */
+ public String selectConfigByKey(String configKey);
+
+ /**
+ * 查询参数配置列表
+ *
+ * @param config 参数配置信息
+ * @return 参数配置集合
+ */
+ public List selectConfigList(SysConfig config);
+
+ /**
+ * 新增参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ public int insertConfig(SysConfig config);
+
+ /**
+ * 修改参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ public int updateConfig(SysConfig config);
+
+ /**
+ * 批量删除参数配置信息
+ *
+ * @param ids 需要删除的数据ID
+ */
+ public void deleteConfigByIds(String ids);
+
+ /**
+ * 加载参数缓存数据
+ */
+ public void loadingConfigCache();
+
+ /**
+ * 清空参数缓存数据
+ */
+ public void clearConfigCache();
+
+ /**
+ * 重置参数缓存数据
+ */
+ public void resetConfigCache();
+
+ /**
+ * 校验参数键名是否唯一
+ *
+ * @param config 参数信息
+ * @return 结果
+ */
+ public boolean checkConfigKeyUnique(SysConfig config);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java
new file mode 100644
index 0000000..ac1e4f3
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDeptService.java
@@ -0,0 +1,117 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysDept;
+import com.playlet.common.core.domain.entity.SysRole;
+
+/**
+ * 部门管理 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysDeptService
+{
+ /**
+ * 查询部门管理数据
+ *
+ * @param dept 部门信息
+ * @return 部门信息集合
+ */
+ public List selectDeptList(SysDept dept);
+
+ /**
+ * 查询部门管理树
+ *
+ * @param dept 部门信息
+ * @return 所有部门信息
+ */
+ public List selectDeptTree(SysDept dept);
+
+ /**
+ * 查询部门管理树(排除下级)
+ *
+ * @param dept 部门信息
+ * @return 所有部门信息
+ */
+ public List selectDeptTreeExcludeChild(SysDept dept);
+
+ /**
+ * 根据角色ID查询菜单
+ *
+ * @param role 角色对象
+ * @return 菜单列表
+ */
+ public List roleDeptTreeData(SysRole role);
+
+ /**
+ * 根据父部门ID查询下级部门数量
+ *
+ * @param parentId 父部门ID
+ * @return 结果
+ */
+ public int selectDeptCount(Long parentId);
+
+ /**
+ * 查询部门是否存在用户
+ *
+ * @param deptId 部门ID
+ * @return 结果 true 存在 false 不存在
+ */
+ public boolean checkDeptExistUser(Long deptId);
+
+ /**
+ * 删除部门管理信息
+ *
+ * @param deptId 部门ID
+ * @return 结果
+ */
+ public int deleteDeptById(Long deptId);
+
+ /**
+ * 新增保存部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public int insertDept(SysDept dept);
+
+ /**
+ * 修改保存部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public int updateDept(SysDept dept);
+
+ /**
+ * 根据部门ID查询信息
+ *
+ * @param deptId 部门ID
+ * @return 部门信息
+ */
+ public SysDept selectDeptById(Long deptId);
+
+ /**
+ * 根据ID查询所有子部门(正常状态)
+ *
+ * @param deptId 部门ID
+ * @return 子部门数
+ */
+ public int selectNormalChildrenDeptById(Long deptId);
+
+ /**
+ * 校验部门名称是否唯一
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ public boolean checkDeptNameUnique(SysDept dept);
+
+ /**
+ * 校验部门是否有数据权限
+ *
+ * @param deptId 部门id
+ */
+ public void checkDeptDataScope(Long deptId);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java
new file mode 100644
index 0000000..5f98651
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDictDataService.java
@@ -0,0 +1,60 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.common.core.domain.entity.SysDictData;
+
+/**
+ * 字典 业务层
+ *
+ * @author ruoyi
+ */
+public interface ISysDictDataService
+{
+ /**
+ * 根据条件分页查询字典数据
+ *
+ * @param dictData 字典数据信息
+ * @return 字典数据集合信息
+ */
+ public List selectDictDataList(SysDictData dictData);
+
+ /**
+ * 根据字典类型和字典键值查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典键值
+ * @return 字典标签
+ */
+ public String selectDictLabel(String dictType, String dictValue);
+
+ /**
+ * 根据字典数据ID查询信息
+ *
+ * @param dictCode 字典数据ID
+ * @return 字典数据
+ */
+ public SysDictData selectDictDataById(Long dictCode);
+
+ /**
+ * 批量删除字典数据
+ *
+ * @param ids 需要删除的数据
+ */
+ public void deleteDictDataByIds(String ids);
+
+ /**
+ * 新增保存字典数据信息
+ *
+ * @param dictData 字典数据信息
+ * @return 结果
+ */
+ public int insertDictData(SysDictData dictData);
+
+ /**
+ * 修改保存字典数据信息
+ *
+ * @param dictData 字典数据信息
+ * @return 结果
+ */
+ public int updateDictData(SysDictData dictData);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java
new file mode 100644
index 0000000..eb2e93d
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysDictTypeService.java
@@ -0,0 +1,107 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysDictData;
+import com.playlet.common.core.domain.entity.SysDictType;
+
+/**
+ * 字典 业务层
+ *
+ * @author ruoyi
+ */
+public interface ISysDictTypeService
+{
+ /**
+ * 根据条件分页查询字典类型
+ *
+ * @param dictType 字典类型信息
+ * @return 字典类型集合信息
+ */
+ public List selectDictTypeList(SysDictType dictType);
+
+ /**
+ * 根据所有字典类型
+ *
+ * @return 字典类型集合信息
+ */
+ public List selectDictTypeAll();
+
+ /**
+ * 根据字典类型查询字典数据
+ *
+ * @param dictType 字典类型
+ * @return 字典数据集合信息
+ */
+ public List selectDictDataByType(String dictType);
+
+ /**
+ * 根据字典类型ID查询信息
+ *
+ * @param dictId 字典类型ID
+ * @return 字典类型
+ */
+ public SysDictType selectDictTypeById(Long dictId);
+
+ /**
+ * 根据字典类型查询信息
+ *
+ * @param dictType 字典类型
+ * @return 字典类型
+ */
+ public SysDictType selectDictTypeByType(String dictType);
+
+ /**
+ * 批量删除字典类型
+ *
+ * @param ids 需要删除的数据
+ */
+ public void deleteDictTypeByIds(String ids);
+
+ /**
+ * 加载字典缓存数据
+ */
+ public void loadingDictCache();
+
+ /**
+ * 清空字典缓存数据
+ */
+ public void clearDictCache();
+
+ /**
+ * 重置字典缓存数据
+ */
+ public void resetDictCache();
+
+ /**
+ * 新增保存字典类型信息
+ *
+ * @param dictType 字典类型信息
+ * @return 结果
+ */
+ public int insertDictType(SysDictType dictType);
+
+ /**
+ * 修改保存字典类型信息
+ *
+ * @param dictType 字典类型信息
+ * @return 结果
+ */
+ public int updateDictType(SysDictType dictType);
+
+ /**
+ * 校验字典类型称是否唯一
+ *
+ * @param dictType 字典类型
+ * @return 结果
+ */
+ public boolean checkDictTypeUnique(SysDictType dictType);
+
+ /**
+ * 查询字典类型树
+ *
+ * @param dictType 字典类型
+ * @return 所有字典类型
+ */
+ public List selectDictTree(SysDictType dictType);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java
new file mode 100644
index 0000000..65fd514
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysLogininforService.java
@@ -0,0 +1,40 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.system.domain.SysLogininfor;
+
+/**
+ * 系统访问日志情况信息 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysLogininforService
+{
+ /**
+ * 新增系统登录日志
+ *
+ * @param logininfor 访问日志对象
+ */
+ public void insertLogininfor(SysLogininfor logininfor);
+
+ /**
+ * 查询系统登录日志集合
+ *
+ * @param logininfor 访问日志对象
+ * @return 登录记录集合
+ */
+ public List selectLogininforList(SysLogininfor logininfor);
+
+ /**
+ * 批量删除系统登录日志
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteLogininforByIds(String ids);
+
+ /**
+ * 清空系统登录日志
+ */
+ public void cleanLogininfor();
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java
new file mode 100644
index 0000000..cb2ab1e
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysMenuService.java
@@ -0,0 +1,139 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysMenu;
+import com.playlet.common.core.domain.entity.SysRole;
+import com.playlet.common.core.domain.entity.SysUser;
+
+/**
+ * 菜单 业务层
+ *
+ * @author ruoyi
+ */
+public interface ISysMenuService
+{
+ /**
+ * 根据用户ID查询菜单
+ *
+ * @param user 用户信息
+ * @return 菜单列表
+ */
+ public List selectMenusByUser(SysUser user);
+
+ /**
+ * 查询系统菜单列表
+ *
+ * @param menu 菜单信息
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ public List selectMenuList(SysMenu menu, Long userId);
+
+ /**
+ * 查询菜单集合
+ *
+ * @param userId 用户ID
+ * @return 所有菜单信息
+ */
+ public List selectMenuAll(Long userId);
+
+ /**
+ * 根据用户ID查询权限
+ *
+ * @param userId 用户ID
+ * @return 权限列表
+ */
+ public Set selectPermsByUserId(Long userId);
+
+ /**
+ * 根据角色ID查询权限
+ *
+ * @param roleId 角色ID
+ * @return 权限列表
+ */
+ public Set selectPermsByRoleId(Long roleId);
+
+ /**
+ * 根据角色ID查询菜单
+ *
+ * @param role 角色对象
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ public List roleMenuTreeData(SysRole role, Long userId);
+
+ /**
+ * 查询所有菜单信息
+ *
+ * @param userId 用户ID
+ * @return 菜单列表
+ */
+ public List menuTreeData(Long userId);
+
+ /**
+ * 查询系统所有权限
+ *
+ * @param userId 用户ID
+ * @return 权限列表
+ */
+ public Map selectPermsAll(Long userId);
+
+ /**
+ * 删除菜单管理信息
+ *
+ * @param menuId 菜单ID
+ * @return 结果
+ */
+ public int deleteMenuById(Long menuId);
+
+ /**
+ * 根据菜单ID查询信息
+ *
+ * @param menuId 菜单ID
+ * @return 菜单信息
+ */
+ public SysMenu selectMenuById(Long menuId);
+
+ /**
+ * 查询菜单数量
+ *
+ * @param parentId 菜单父ID
+ * @return 结果
+ */
+ public int selectCountMenuByParentId(Long parentId);
+
+ /**
+ * 查询菜单使用数量
+ *
+ * @param menuId 菜单ID
+ * @return 结果
+ */
+ public int selectCountRoleMenuByMenuId(Long menuId);
+
+ /**
+ * 新增保存菜单信息
+ *
+ * @param menu 菜单信息
+ * @return 结果
+ */
+ public int insertMenu(SysMenu menu);
+
+ /**
+ * 修改保存菜单信息
+ *
+ * @param menu 菜单信息
+ * @return 结果
+ */
+ public int updateMenu(SysMenu menu);
+
+ /**
+ * 校验菜单名称是否唯一
+ *
+ * @param menu 菜单信息
+ * @return 结果
+ */
+ public boolean checkMenuNameUnique(SysMenu menu);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java
new file mode 100644
index 0000000..21922b8
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysNoticeService.java
@@ -0,0 +1,52 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.system.domain.SysNotice;
+
+/**
+ * 公告 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysNoticeService
+{
+ /**
+ * 查询公告信息
+ *
+ * @param noticeId 公告ID
+ * @return 公告信息
+ */
+ public SysNotice selectNoticeById(Long noticeId);
+
+ /**
+ * 查询公告列表
+ *
+ * @param notice 公告信息
+ * @return 公告集合
+ */
+ public List selectNoticeList(SysNotice notice);
+
+ /**
+ * 新增公告
+ *
+ * @param notice 公告信息
+ * @return 结果
+ */
+ public int insertNotice(SysNotice notice);
+
+ /**
+ * 修改公告
+ *
+ * @param notice 公告信息
+ * @return 结果
+ */
+ public int updateNotice(SysNotice notice);
+
+ /**
+ * 删除公告信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deleteNoticeByIds(String ids);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java
new file mode 100644
index 0000000..746ac87
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysOperLogService.java
@@ -0,0 +1,48 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.system.domain.SysOperLog;
+
+/**
+ * 操作日志 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysOperLogService
+{
+ /**
+ * 新增操作日志
+ *
+ * @param operLog 操作日志对象
+ */
+ public void insertOperlog(SysOperLog operLog);
+
+ /**
+ * 查询系统操作日志集合
+ *
+ * @param operLog 操作日志对象
+ * @return 操作日志集合
+ */
+ public List selectOperLogList(SysOperLog operLog);
+
+ /**
+ * 批量删除系统操作日志
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ public int deleteOperLogByIds(String ids);
+
+ /**
+ * 查询操作日志详细
+ *
+ * @param operId 操作ID
+ * @return 操作日志对象
+ */
+ public SysOperLog selectOperLogById(Long operId);
+
+ /**
+ * 清空操作日志
+ */
+ public void cleanOperLog();
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java
new file mode 100644
index 0000000..ea99f7a
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysPostService.java
@@ -0,0 +1,91 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.system.domain.SysPost;
+
+/**
+ * 岗位信息 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysPostService
+{
+ /**
+ * 查询岗位信息集合
+ *
+ * @param post 岗位信息
+ * @return 岗位信息集合
+ */
+ public List selectPostList(SysPost post);
+
+ /**
+ * 查询所有岗位
+ *
+ * @return 岗位列表
+ */
+ public List selectPostAll();
+
+ /**
+ * 根据用户ID查询岗位
+ *
+ * @param userId 用户ID
+ * @return 岗位列表
+ */
+ public List selectPostsByUserId(Long userId);
+
+ /**
+ * 通过岗位ID查询岗位信息
+ *
+ * @param postId 岗位ID
+ * @return 角色对象信息
+ */
+ public SysPost selectPostById(Long postId);
+
+ /**
+ * 批量删除岗位信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ */
+ public int deletePostByIds(String ids);
+
+ /**
+ * 新增保存岗位信息
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public int insertPost(SysPost post);
+
+ /**
+ * 修改保存岗位信息
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public int updatePost(SysPost post);
+
+ /**
+ * 通过岗位ID查询岗位使用数量
+ *
+ * @param postId 岗位ID
+ * @return 结果
+ */
+ public int countUserPostById(Long postId);
+
+ /**
+ * 校验岗位名称
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public boolean checkPostNameUnique(SysPost post);
+
+ /**
+ * 校验岗位编码
+ *
+ * @param post 岗位信息
+ * @return 结果
+ */
+ public boolean checkPostCodeUnique(SysPost post);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java
new file mode 100644
index 0000000..13b594f
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysRoleService.java
@@ -0,0 +1,166 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import java.util.Set;
+import com.playlet.common.core.domain.entity.SysRole;
+import com.playlet.system.domain.SysUserRole;
+
+/**
+ * 角色业务层
+ *
+ * @author ruoyi
+ */
+public interface ISysRoleService
+{
+ /**
+ * 根据条件分页查询角色数据
+ *
+ * @param role 角色信息
+ * @return 角色数据集合信息
+ */
+ public List selectRoleList(SysRole role);
+
+ /**
+ * 根据用户ID查询角色列表
+ *
+ * @param userId 用户ID
+ * @return 权限列表
+ */
+ public Set selectRoleKeys(Long userId);
+
+ /**
+ * 根据用户ID查询角色权限
+ *
+ * @param userId 用户ID
+ * @return 角色列表
+ */
+ public List selectRolesByUserId(Long userId);
+
+ /**
+ * 查询所有角色
+ *
+ * @return 角色列表
+ */
+ public List selectRoleAll();
+
+ /**
+ * 通过角色ID查询角色
+ *
+ * @param roleId 角色ID
+ * @return 角色对象信息
+ */
+ public SysRole selectRoleById(Long roleId);
+
+ /**
+ * 通过角色ID删除角色
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public boolean deleteRoleById(Long roleId);
+
+ /**
+ * 批量删除角色用户信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ * @throws Exception 异常
+ */
+ public int deleteRoleByIds(String ids);
+
+ /**
+ * 新增保存角色信息
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int insertRole(SysRole role);
+
+ /**
+ * 修改保存角色信息
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int updateRole(SysRole role);
+
+ /**
+ * 修改数据权限信息
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int authDataScope(SysRole role);
+
+ /**
+ * 校验角色名称是否唯一
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public boolean checkRoleNameUnique(SysRole role);
+
+ /**
+ * 校验角色权限是否唯一
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public boolean checkRoleKeyUnique(SysRole role);
+
+ /**
+ * 校验角色是否允许操作
+ *
+ * @param role 角色信息
+ */
+ public void checkRoleAllowed(SysRole role);
+
+ /**
+ * 校验角色是否有数据权限
+ *
+ * @param roleId 角色id
+ */
+ public void checkRoleDataScope(Long roleId);
+
+ /**
+ * 通过角色ID查询角色使用数量
+ *
+ * @param roleId 角色ID
+ * @return 结果
+ */
+ public int countUserRoleByRoleId(Long roleId);
+
+ /**
+ * 角色状态修改
+ *
+ * @param role 角色信息
+ * @return 结果
+ */
+ public int changeStatus(SysRole role);
+
+ /**
+ * 取消授权用户角色
+ *
+ * @param userRole 用户和角色关联信息
+ * @return 结果
+ */
+ public int deleteAuthUser(SysUserRole userRole);
+
+ /**
+ * 批量取消授权用户角色
+ *
+ * @param roleId 角色ID
+ * @param userIds 需要删除的用户数据ID
+ * @return 结果
+ */
+ public int deleteAuthUsers(Long roleId, String userIds);
+
+ /**
+ * 批量选择授权用户角色
+ *
+ * @param roleId 角色ID
+ * @param userIds 需要删除的用户数据ID
+ * @return 结果
+ */
+ public int insertAuthUsers(Long roleId, String userIds);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java
new file mode 100644
index 0000000..ad05399
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysUserOnlineService.java
@@ -0,0 +1,75 @@
+package com.playlet.system.service;
+
+import java.util.Date;
+import java.util.List;
+import com.playlet.system.domain.SysUserOnline;
+
+/**
+ * 在线用户 服务层
+ *
+ * @author ruoyi
+ */
+public interface ISysUserOnlineService
+{
+ /**
+ * 通过会话序号查询信息
+ *
+ * @param sessionId 会话ID
+ * @return 在线用户信息
+ */
+ public SysUserOnline selectOnlineById(String sessionId);
+
+ /**
+ * 通过会话序号删除信息
+ *
+ * @param sessionId 会话ID
+ * @return 在线用户信息
+ */
+ public void deleteOnlineById(String sessionId);
+
+ /**
+ * 通过会话序号删除信息
+ *
+ * @param sessions 会话ID集合
+ * @return 在线用户信息
+ */
+ public void batchDeleteOnline(List sessions);
+
+ /**
+ * 保存会话信息
+ *
+ * @param online 会话信息
+ */
+ public void saveOnline(SysUserOnline online);
+
+ /**
+ * 查询会话集合
+ *
+ * @param userOnline 分页参数
+ * @return 会话集合
+ */
+ public List selectUserOnlineList(SysUserOnline userOnline);
+
+ /**
+ * 强退用户
+ *
+ * @param sessionId 会话ID
+ */
+ public void forceLogout(String sessionId);
+
+ /**
+ * 清理用户缓存
+ *
+ * @param loginName 登录名称
+ * @param sessionId 会话ID
+ */
+ public void removeUserCache(String loginName, String sessionId);
+
+ /**
+ * 查询会话集合
+ *
+ * @param expiredDate 有效期
+ * @return 会话集合
+ */
+ public List selectOnlineByExpired(Date expiredDate);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java b/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java
new file mode 100644
index 0000000..65b20f4
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/ISysUserService.java
@@ -0,0 +1,214 @@
+package com.playlet.system.service;
+
+import java.util.List;
+import com.playlet.common.core.domain.entity.SysUser;
+import com.playlet.system.domain.SysUserRole;
+
+/**
+ * 用户 业务层
+ *
+ * @author ruoyi
+ */
+public interface ISysUserService
+{
+ /**
+ * 根据条件分页查询用户列表
+ *
+ * @param user 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectUserList(SysUser user);
+
+ /**
+ * 根据条件分页查询已分配用户角色列表
+ *
+ * @param user 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectAllocatedList(SysUser user);
+
+ /**
+ * 根据条件分页查询未分配用户角色列表
+ *
+ * @param user 用户信息
+ * @return 用户信息集合信息
+ */
+ public List selectUnallocatedList(SysUser user);
+
+ /**
+ * 通过用户名查询用户
+ *
+ * @param userName 用户名
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByLoginName(String userName);
+
+ /**
+ * 通过手机号码查询用户
+ *
+ * @param phoneNumber 手机号码
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByPhoneNumber(String phoneNumber);
+
+ /**
+ * 通过邮箱查询用户
+ *
+ * @param email 邮箱
+ * @return 用户对象信息
+ */
+ public SysUser selectUserByEmail(String email);
+
+ /**
+ * 通过用户ID查询用户
+ *
+ * @param userId 用户ID
+ * @return 用户对象信息
+ */
+ public SysUser selectUserById(Long userId);
+
+ /**
+ * 通过用户ID查询用户和角色关联
+ *
+ * @param userId 用户ID
+ * @return 用户和角色关联列表
+ */
+ public List selectUserRoleByUserId(Long userId);
+
+ /**
+ * 通过用户ID删除用户
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public int deleteUserById(Long userId);
+
+ /**
+ * 批量删除用户信息
+ *
+ * @param ids 需要删除的数据ID
+ * @return 结果
+ * @throws Exception 异常
+ */
+ public int deleteUserByIds(String ids);
+
+ /**
+ * 保存用户信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int insertUser(SysUser user);
+
+ /**
+ * 注册用户信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public boolean registerUser(SysUser user);
+
+ /**
+ * 保存用户信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int updateUser(SysUser user);
+
+ /**
+ * 修改用户详细信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int updateUserInfo(SysUser user);
+
+ /**
+ * 用户授权角色
+ *
+ * @param userId 用户ID
+ * @param roleIds 角色组
+ */
+ public void insertUserAuth(Long userId, Long[] roleIds);
+
+ /**
+ * 修改用户密码信息
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int resetUserPwd(SysUser user);
+
+ /**
+ * 校验用户名称是否唯一
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public boolean checkLoginNameUnique(SysUser user);
+
+ /**
+ * 校验手机号码是否唯一
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public boolean checkPhoneUnique(SysUser user);
+
+ /**
+ * 校验email是否唯一
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public boolean checkEmailUnique(SysUser user);
+
+ /**
+ * 校验用户是否允许操作
+ *
+ * @param user 用户信息
+ */
+ public void checkUserAllowed(SysUser user);
+
+ /**
+ * 校验用户是否有数据权限
+ *
+ * @param userId 用户id
+ */
+ public void checkUserDataScope(Long userId);
+
+ /**
+ * 根据用户ID查询用户所属角色组
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public String selectUserRoleGroup(Long userId);
+
+ /**
+ * 根据用户ID查询用户所属岗位组
+ *
+ * @param userId 用户ID
+ * @return 结果
+ */
+ public String selectUserPostGroup(Long userId);
+
+ /**
+ * 导入用户数据
+ *
+ * @param userList 用户数据列表
+ * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
+ * @param operName 操作用户
+ * @return 结果
+ */
+ public String importUser(List userList, Boolean isUpdateSupport, String operName);
+
+ /**
+ * 用户状态修改
+ *
+ * @param user 用户信息
+ * @return 结果
+ */
+ public int changeStatus(SysUser user);
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..8b54a18
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,219 @@
+package com.playlet.system.service.impl;
+
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.constant.Constants;
+import com.playlet.common.constant.UserConstants;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.exception.ServiceException;
+import com.playlet.common.utils.CacheUtils;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.system.domain.SysConfig;
+import com.playlet.system.mapper.SysConfigMapper;
+import com.playlet.system.service.ISysConfigService;
+
+/**
+ * 参数配置 服务层实现
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysConfigServiceImpl implements ISysConfigService
+{
+ @Autowired
+ private SysConfigMapper configMapper;
+
+ /**
+ * 项目启动时,初始化参数到缓存
+ */
+ @PostConstruct
+ public void init()
+ {
+ loadingConfigCache();
+ }
+
+ /**
+ * 查询参数配置信息
+ *
+ * @param configId 参数配置ID
+ * @return 参数配置信息
+ */
+ @Override
+ public SysConfig selectConfigById(Long configId)
+ {
+ SysConfig config = new SysConfig();
+ config.setConfigId(configId);
+ return configMapper.selectConfig(config);
+ }
+
+ /**
+ * 根据键名查询参数配置信息
+ *
+ * @param configKey 参数key
+ * @return 参数键值
+ */
+ @Override
+ public String selectConfigByKey(String configKey)
+ {
+ String configValue = Convert.toStr(CacheUtils.get(getCacheName(), getCacheKey(configKey)));
+ if (StringUtils.isNotEmpty(configValue))
+ {
+ return configValue;
+ }
+ SysConfig config = new SysConfig();
+ config.setConfigKey(configKey);
+ SysConfig retConfig = configMapper.selectConfig(config);
+ if (StringUtils.isNotNull(retConfig))
+ {
+ CacheUtils.put(getCacheName(), getCacheKey(configKey), retConfig.getConfigValue());
+ return retConfig.getConfigValue();
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 查询参数配置列表
+ *
+ * @param config 参数配置信息
+ * @return 参数配置集合
+ */
+ @Override
+ public List selectConfigList(SysConfig config)
+ {
+ return configMapper.selectConfigList(config);
+ }
+
+ /**
+ * 新增参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ @Override
+ public int insertConfig(SysConfig config)
+ {
+ int row = configMapper.insertConfig(config);
+ if (row > 0)
+ {
+ CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());
+ }
+ return row;
+ }
+
+ /**
+ * 修改参数配置
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ @Override
+ public int updateConfig(SysConfig config)
+ {
+ SysConfig temp = configMapper.selectConfigById(config.getConfigId());
+ if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
+ {
+ CacheUtils.remove(getCacheName(), getCacheKey(temp.getConfigKey()));
+ }
+
+ int row = configMapper.updateConfig(config);
+ if (row > 0)
+ {
+ CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());
+ }
+ return row;
+ }
+
+ /**
+ * 批量删除参数配置对象
+ *
+ * @param ids 需要删除的数据ID
+ */
+ @Override
+ public void deleteConfigByIds(String ids)
+ {
+ Long[] configIds = Convert.toLongArray(ids);
+ for (Long configId : configIds)
+ {
+ SysConfig config = selectConfigById(configId);
+ if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
+ {
+ throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
+ }
+ configMapper.deleteConfigById(configId);
+ CacheUtils.remove(getCacheName(), getCacheKey(config.getConfigKey()));
+ }
+ }
+
+ /**
+ * 加载参数缓存数据
+ */
+ @Override
+ public void loadingConfigCache()
+ {
+ List configsList = configMapper.selectConfigList(new SysConfig());
+ for (SysConfig config : configsList)
+ {
+ CacheUtils.put(getCacheName(), getCacheKey(config.getConfigKey()), config.getConfigValue());
+ }
+ }
+
+ /**
+ * 清空参数缓存数据
+ */
+ @Override
+ public void clearConfigCache()
+ {
+ CacheUtils.removeAll(getCacheName());
+ }
+
+ /**
+ * 重置参数缓存数据
+ */
+ @Override
+ public void resetConfigCache()
+ {
+ clearConfigCache();
+ loadingConfigCache();
+ }
+
+ /**
+ * 校验参数键名是否唯一
+ *
+ * @param config 参数配置信息
+ * @return 结果
+ */
+ @Override
+ public boolean checkConfigKeyUnique(SysConfig config)
+ {
+ Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+ SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());
+ if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue())
+ {
+ return UserConstants.NOT_UNIQUE;
+ }
+ return UserConstants.UNIQUE;
+ }
+
+ /**
+ * 获取cache name
+ *
+ * @return 缓存名
+ */
+ private String getCacheName()
+ {
+ return Constants.SYS_CONFIG_CACHE;
+ }
+
+ /**
+ * 设置cache key
+ *
+ * @param configKey 参数键
+ * @return 缓存键key
+ */
+ private String getCacheKey(String configKey)
+ {
+ return Constants.SYS_CONFIG_KEY + configKey;
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..5dc7e70
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDeptServiceImpl.java
@@ -0,0 +1,328 @@
+package com.playlet.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.playlet.common.annotation.DataScope;
+import com.playlet.common.constant.UserConstants;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysDept;
+import com.playlet.common.core.domain.entity.SysRole;
+import com.playlet.common.core.domain.entity.SysUser;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.exception.ServiceException;
+import com.playlet.common.utils.ShiroUtils;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.common.utils.spring.SpringUtils;
+import com.playlet.system.mapper.SysDeptMapper;
+import com.playlet.system.service.ISysDeptService;
+
+/**
+ * 部门管理 服务实现
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysDeptServiceImpl implements ISysDeptService
+{
+ @Autowired
+ private SysDeptMapper deptMapper;
+
+ /**
+ * 查询部门管理数据
+ *
+ * @param dept 部门信息
+ * @return 部门信息集合
+ */
+ @Override
+ @DataScope(deptAlias = "d")
+ public List selectDeptList(SysDept dept)
+ {
+ return deptMapper.selectDeptList(dept);
+ }
+
+ /**
+ * 查询部门管理树
+ *
+ * @param dept 部门信息
+ * @return 所有部门信息
+ */
+ @Override
+ @DataScope(deptAlias = "d")
+ public List selectDeptTree(SysDept dept)
+ {
+ List deptList = deptMapper.selectDeptList(dept);
+ List ztrees = initZtree(deptList);
+ return ztrees;
+ }
+
+ /**
+ * 查询部门管理树(排除下级)
+ *
+ * @param deptId 部门ID
+ * @return 所有部门信息
+ */
+ @Override
+ @DataScope(deptAlias = "d")
+ public List selectDeptTreeExcludeChild(SysDept dept)
+ {
+ Long excludeId = dept.getExcludeId();
+ List depts = deptMapper.selectDeptList(dept);
+ if (excludeId.intValue() > 0)
+ {
+ depts.removeIf(d -> d.getDeptId().intValue() == excludeId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), excludeId + ""));
+ }
+ List ztrees = initZtree(depts);
+ return ztrees;
+ }
+
+ /**
+ * 根据角色ID查询部门(数据权限)
+ *
+ * @param role 角色对象
+ * @return 部门列表(数据权限)
+ */
+ @Override
+ public List roleDeptTreeData(SysRole role)
+ {
+ Long roleId = role.getRoleId();
+ List ztrees = new ArrayList();
+ List deptList = SpringUtils.getAopProxy(this).selectDeptList(new SysDept());
+ if (StringUtils.isNotNull(roleId))
+ {
+ List roleDeptList = deptMapper.selectRoleDeptTree(roleId);
+ ztrees = initZtree(deptList, roleDeptList);
+ }
+ else
+ {
+ ztrees = initZtree(deptList);
+ }
+ return ztrees;
+ }
+
+ /**
+ * 对象转部门树
+ *
+ * @param deptList 部门列表
+ * @return 树结构列表
+ */
+ public List initZtree(List deptList)
+ {
+ return initZtree(deptList, null);
+ }
+
+ /**
+ * 对象转部门树
+ *
+ * @param deptList 部门列表
+ * @param roleDeptList 角色已存在菜单列表
+ * @return 树结构列表
+ */
+ public List initZtree(List deptList, List roleDeptList)
+ {
+
+ List ztrees = new ArrayList();
+ boolean isCheck = StringUtils.isNotNull(roleDeptList);
+ for (SysDept dept : deptList)
+ {
+ if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()))
+ {
+ Ztree ztree = new Ztree();
+ ztree.setId(dept.getDeptId());
+ ztree.setpId(dept.getParentId());
+ ztree.setName(dept.getDeptName());
+ ztree.setTitle(dept.getDeptName());
+ if (isCheck)
+ {
+ ztree.setChecked(roleDeptList.contains(dept.getDeptId() + dept.getDeptName()));
+ }
+ ztrees.add(ztree);
+ }
+ }
+ return ztrees;
+ }
+
+ /**
+ * 根据父部门ID查询下级部门数量
+ *
+ * @param parentId 部门ID
+ * @return 结果
+ */
+ @Override
+ public int selectDeptCount(Long parentId)
+ {
+ SysDept dept = new SysDept();
+ dept.setParentId(parentId);
+ return deptMapper.selectDeptCount(dept);
+ }
+
+ /**
+ * 查询部门是否存在用户
+ *
+ * @param deptId 部门ID
+ * @return 结果 true 存在 false 不存在
+ */
+ @Override
+ public boolean checkDeptExistUser(Long deptId)
+ {
+ int result = deptMapper.checkDeptExistUser(deptId);
+ return result > 0;
+ }
+
+ /**
+ * 删除部门管理信息
+ *
+ * @param deptId 部门ID
+ * @return 结果
+ */
+ @Override
+ public int deleteDeptById(Long deptId)
+ {
+ return deptMapper.deleteDeptById(deptId);
+ }
+
+ /**
+ * 新增保存部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ @Override
+ public int insertDept(SysDept dept)
+ {
+ SysDept info = deptMapper.selectDeptById(dept.getParentId());
+ // 如果父节点不为"正常"状态,则不允许新增子节点
+ if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
+ {
+ throw new ServiceException("部门停用,不允许新增");
+ }
+ dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
+ return deptMapper.insertDept(dept);
+ }
+
+ /**
+ * 修改保存部门信息
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int updateDept(SysDept dept)
+ {
+ SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
+ SysDept oldDept = selectDeptById(dept.getDeptId());
+ if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
+ {
+ String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
+ String oldAncestors = oldDept.getAncestors();
+ dept.setAncestors(newAncestors);
+ updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
+ }
+ int result = deptMapper.updateDept(dept);
+ if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+ && !StringUtils.equals("0", dept.getAncestors()))
+ {
+ // 如果该部门是启用状态,则启用该部门的所有上级部门
+ updateParentDeptStatusNormal(dept);
+ }
+ return result;
+ }
+
+ /**
+ * 修改该部门的父级部门状态
+ *
+ * @param dept 当前部门
+ */
+ private void updateParentDeptStatusNormal(SysDept dept)
+ {
+ String ancestors = dept.getAncestors();
+ Long[] deptIds = Convert.toLongArray(ancestors);
+ deptMapper.updateDeptStatusNormal(deptIds);
+ }
+
+ /**
+ * 修改子元素关系
+ *
+ * @param deptId 被修改的部门ID
+ * @param newAncestors 新的父ID集合
+ * @param oldAncestors 旧的父ID集合
+ */
+ public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
+ {
+ List children = deptMapper.selectChildrenDeptById(deptId);
+ for (SysDept child : children)
+ {
+ child.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
+ }
+ if (children.size() > 0)
+ {
+ deptMapper.updateDeptChildren(children);
+ }
+ }
+
+ /**
+ * 根据部门ID查询信息
+ *
+ * @param deptId 部门ID
+ * @return 部门信息
+ */
+ @Override
+ public SysDept selectDeptById(Long deptId)
+ {
+ return deptMapper.selectDeptById(deptId);
+ }
+
+ /**
+ * 根据ID查询所有子部门(正常状态)
+ *
+ * @param deptId 部门ID
+ * @return 子部门数
+ */
+ @Override
+ public int selectNormalChildrenDeptById(Long deptId)
+ {
+ return deptMapper.selectNormalChildrenDeptById(deptId);
+ }
+
+ /**
+ * 校验部门名称是否唯一
+ *
+ * @param dept 部门信息
+ * @return 结果
+ */
+ @Override
+ public boolean checkDeptNameUnique(SysDept dept)
+ {
+ Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
+ SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
+ if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())
+ {
+ return UserConstants.NOT_UNIQUE;
+ }
+ return UserConstants.UNIQUE;
+ }
+
+ /**
+ * 校验部门是否有数据权限
+ *
+ * @param deptId 部门id
+ */
+ @Override
+ public void checkDeptDataScope(Long deptId)
+ {
+ if (!SysUser.isAdmin(ShiroUtils.getUserId()))
+ {
+ SysDept dept = new SysDept();
+ dept.setDeptId(deptId);
+ List depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
+ if (StringUtils.isEmpty(depts))
+ {
+ throw new ServiceException("没有权限访问部门数据!");
+ }
+ }
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..c81861f
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictDataServiceImpl.java
@@ -0,0 +1,113 @@
+package com.playlet.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.core.domain.entity.SysDictData;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.utils.DictUtils;
+import com.playlet.system.mapper.SysDictDataMapper;
+import com.playlet.system.service.ISysDictDataService;
+
+/**
+ * 字典 业务层处理
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysDictDataServiceImpl implements ISysDictDataService
+{
+ @Autowired
+ private SysDictDataMapper dictDataMapper;
+
+ /**
+ * 根据条件分页查询字典数据
+ *
+ * @param dictData 字典数据信息
+ * @return 字典数据集合信息
+ */
+ @Override
+ public List selectDictDataList(SysDictData dictData)
+ {
+ return dictDataMapper.selectDictDataList(dictData);
+ }
+
+ /**
+ * 根据字典类型和字典键值查询字典数据信息
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典键值
+ * @return 字典标签
+ */
+ @Override
+ public String selectDictLabel(String dictType, String dictValue)
+ {
+ return dictDataMapper.selectDictLabel(dictType, dictValue);
+ }
+
+ /**
+ * 根据字典数据ID查询信息
+ *
+ * @param dictCode 字典数据ID
+ * @return 字典数据
+ */
+ @Override
+ public SysDictData selectDictDataById(Long dictCode)
+ {
+ return dictDataMapper.selectDictDataById(dictCode);
+ }
+
+ /**
+ * 批量删除字典数据
+ *
+ * @param ids 需要删除的数据
+ */
+ @Override
+ public void deleteDictDataByIds(String ids)
+ {
+ Long[] dictCodes = Convert.toLongArray(ids);
+ for (Long dictCode : dictCodes)
+ {
+ SysDictData data = selectDictDataById(dictCode);
+ dictDataMapper.deleteDictDataById(dictCode);
+ List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+ DictUtils.setDictCache(data.getDictType(), dictDatas);
+ }
+ }
+
+ /**
+ * 新增保存字典数据信息
+ *
+ * @param data 字典数据信息
+ * @return 结果
+ */
+ @Override
+ public int insertDictData(SysDictData data)
+ {
+ int row = dictDataMapper.insertDictData(data);
+ if (row > 0)
+ {
+ List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+ DictUtils.setDictCache(data.getDictType(), dictDatas);
+ }
+ return row;
+ }
+
+ /**
+ * 修改保存字典数据信息
+ *
+ * @param data 字典数据信息
+ * @return 结果
+ */
+ @Override
+ public int updateDictData(SysDictData data)
+ {
+ int row = dictDataMapper.updateDictData(data);
+ if (row > 0)
+ {
+ List dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+ DictUtils.setDictCache(data.getDictType(), dictDatas);
+ }
+ return row;
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..8fdcd23
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysDictTypeServiceImpl.java
@@ -0,0 +1,260 @@
+package com.playlet.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.playlet.common.constant.UserConstants;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysDictData;
+import com.playlet.common.core.domain.entity.SysDictType;
+import com.playlet.common.core.text.Convert;
+import com.playlet.common.exception.ServiceException;
+import com.playlet.common.utils.DictUtils;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.system.mapper.SysDictDataMapper;
+import com.playlet.system.mapper.SysDictTypeMapper;
+import com.playlet.system.service.ISysDictTypeService;
+
+/**
+ * 字典 业务层处理
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysDictTypeServiceImpl implements ISysDictTypeService
+{
+ @Autowired
+ private SysDictTypeMapper dictTypeMapper;
+
+ @Autowired
+ private SysDictDataMapper dictDataMapper;
+
+ /**
+ * 项目启动时,初始化字典到缓存
+ */
+ @PostConstruct
+ public void init()
+ {
+ loadingDictCache();
+ }
+
+ /**
+ * 根据条件分页查询字典类型
+ *
+ * @param dictType 字典类型信息
+ * @return 字典类型集合信息
+ */
+ @Override
+ public List selectDictTypeList(SysDictType dictType)
+ {
+ return dictTypeMapper.selectDictTypeList(dictType);
+ }
+
+ /**
+ * 根据所有字典类型
+ *
+ * @return 字典类型集合信息
+ */
+ @Override
+ public List selectDictTypeAll()
+ {
+ return dictTypeMapper.selectDictTypeAll();
+ }
+
+ /**
+ * 根据字典类型查询字典数据
+ *
+ * @param dictType 字典类型
+ * @return 字典数据集合信息
+ */
+ @Override
+ public List selectDictDataByType(String dictType)
+ {
+ List dictDatas = DictUtils.getDictCache(dictType);
+ if (StringUtils.isNotEmpty(dictDatas))
+ {
+ return dictDatas;
+ }
+ dictDatas = dictDataMapper.selectDictDataByType(dictType);
+ if (StringUtils.isNotEmpty(dictDatas))
+ {
+ DictUtils.setDictCache(dictType, dictDatas);
+ return dictDatas;
+ }
+ return null;
+ }
+
+ /**
+ * 根据字典类型ID查询信息
+ *
+ * @param dictId 字典类型ID
+ * @return 字典类型
+ */
+ @Override
+ public SysDictType selectDictTypeById(Long dictId)
+ {
+ return dictTypeMapper.selectDictTypeById(dictId);
+ }
+
+ /**
+ * 根据字典类型查询信息
+ *
+ * @param dictType 字典类型
+ * @return 字典类型
+ */
+ @Override
+ public SysDictType selectDictTypeByType(String dictType)
+ {
+ return dictTypeMapper.selectDictTypeByType(dictType);
+ }
+
+ /**
+ * 批量删除字典类型
+ *
+ * @param ids 需要删除的数据
+ */
+ @Override
+ public void deleteDictTypeByIds(String ids)
+ {
+ Long[] dictIds = Convert.toLongArray(ids);
+ for (Long dictId : dictIds)
+ {
+ SysDictType dictType = selectDictTypeById(dictId);
+ if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0)
+ {
+ throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
+ }
+ dictTypeMapper.deleteDictTypeById(dictId);
+ DictUtils.removeDictCache(dictType.getDictType());
+ }
+ }
+
+ /**
+ * 加载字典缓存数据
+ */
+ @Override
+ public void loadingDictCache()
+ {
+ SysDictData dictData = new SysDictData();
+ dictData.setStatus("0");
+ Map> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
+ for (Map.Entry> entry : dictDataMap.entrySet())
+ {
+ DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
+ }
+ }
+
+ /**
+ * 清空字典缓存数据
+ */
+ @Override
+ public void clearDictCache()
+ {
+ DictUtils.clearDictCache();
+ }
+
+ /**
+ * 重置字典缓存数据
+ */
+ @Override
+ public void resetDictCache()
+ {
+ clearDictCache();
+ loadingDictCache();
+ }
+
+ /**
+ * 新增保存字典类型信息
+ *
+ * @param dict 字典类型信息
+ * @return 结果
+ */
+ @Override
+ public int insertDictType(SysDictType dict)
+ {
+ int row = dictTypeMapper.insertDictType(dict);
+ if (row > 0)
+ {
+ DictUtils.setDictCache(dict.getDictType(), null);
+ }
+ return row;
+ }
+
+ /**
+ * 修改保存字典类型信息
+ *
+ * @param dict 字典类型信息
+ * @return 结果
+ */
+ @Override
+ @Transactional
+ public int updateDictType(SysDictType dict)
+ {
+ SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());
+ dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());
+ int row = dictTypeMapper.updateDictType(dict);
+ if (row > 0)
+ {
+ List dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
+ DictUtils.setDictCache(dict.getDictType(), dictDatas);
+ }
+ return row;
+ }
+
+ /**
+ * 校验字典类型称是否唯一
+ *
+ * @param dict 字典类型
+ * @return 结果
+ */
+ @Override
+ public boolean checkDictTypeUnique(SysDictType dict)
+ {
+ Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
+ SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());
+ if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue())
+ {
+ return UserConstants.NOT_UNIQUE;
+ }
+ return UserConstants.UNIQUE;
+ }
+
+ /**
+ * 查询字典类型树
+ *
+ * @param dictType 字典类型
+ * @return 所有字典类型
+ */
+ @Override
+ public List selectDictTree(SysDictType dictType)
+ {
+ List ztrees = new ArrayList();
+ List dictList = dictTypeMapper.selectDictTypeList(dictType);
+ for (SysDictType dict : dictList)
+ {
+ if (UserConstants.DICT_NORMAL.equals(dict.getStatus()))
+ {
+ Ztree ztree = new Ztree();
+ ztree.setId(dict.getDictId());
+ ztree.setName(transDictName(dict));
+ ztree.setTitle(dict.getDictType());
+ ztrees.add(ztree);
+ }
+ }
+ return ztrees;
+ }
+
+ public String transDictName(SysDictType dictType)
+ {
+ StringBuffer sb = new StringBuffer();
+ sb.append("(" + dictType.getDictName() + ")");
+ sb.append(" " + dictType.getDictType());
+ return sb.toString();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java
new file mode 100644
index 0000000..e382e32
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysLogininforServiceImpl.java
@@ -0,0 +1,66 @@
+package com.playlet.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.core.text.Convert;
+import com.playlet.system.domain.SysLogininfor;
+import com.playlet.system.mapper.SysLogininforMapper;
+import com.playlet.system.service.ISysLogininforService;
+
+/**
+ * 系统访问日志情况信息 服务层处理
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysLogininforServiceImpl implements ISysLogininforService
+{
+
+ @Autowired
+ private SysLogininforMapper logininforMapper;
+
+ /**
+ * 新增系统登录日志
+ *
+ * @param logininfor 访问日志对象
+ */
+ @Override
+ public void insertLogininfor(SysLogininfor logininfor)
+ {
+ logininforMapper.insertLogininfor(logininfor);
+ }
+
+ /**
+ * 查询系统登录日志集合
+ *
+ * @param logininfor 访问日志对象
+ * @return 登录记录集合
+ */
+ @Override
+ public List selectLogininforList(SysLogininfor logininfor)
+ {
+ return logininforMapper.selectLogininforList(logininfor);
+ }
+
+ /**
+ * 批量删除系统登录日志
+ *
+ * @param ids 需要删除的数据
+ * @return 结果
+ */
+ @Override
+ public int deleteLogininforByIds(String ids)
+ {
+ return logininforMapper.deleteLogininforByIds(Convert.toStrArray(ids));
+ }
+
+ /**
+ * 清空系统登录日志
+ */
+ @Override
+ public void cleanLogininfor()
+ {
+ logininforMapper.cleanLogininfor();
+ }
+}
diff --git a/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java b/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..df1d431
--- /dev/null
+++ b/playlet-system/src/main/java/com/playlet/system/service/impl/SysMenuServiceImpl.java
@@ -0,0 +1,410 @@
+package com.playlet.system.service.impl;
+
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.playlet.common.constant.UserConstants;
+import com.playlet.common.core.domain.Ztree;
+import com.playlet.common.core.domain.entity.SysMenu;
+import com.playlet.common.core.domain.entity.SysRole;
+import com.playlet.common.core.domain.entity.SysUser;
+import com.playlet.common.utils.StringUtils;
+import com.playlet.system.mapper.SysMenuMapper;
+import com.playlet.system.mapper.SysRoleMenuMapper;
+import com.playlet.system.service.ISysMenuService;
+
+/**
+ * 菜单 业务层处理
+ *
+ * @author ruoyi
+ */
+@Service
+public class SysMenuServiceImpl implements ISysMenuService
+{
+ public static final String PREMISSION_STRING = "perms[\"{0}\"]";
+
+ @Autowired
+ private SysMenuMapper menuMapper;
+
+ @Autowired
+ private SysRoleMenuMapper roleMenuMapper;
+
+ /**
+ * 根据用户查询菜单
+ *
+ * @param user 用户信息
+ * @return 菜单列表
+ */
+ @Override
+ public List selectMenusByUser(SysUser user)
+ {
+ List menus = new LinkedList