-
org.springframework.boot
@@ -56,10 +91,27 @@
import
+
+
+ cn.hutool
+ hutool-bom
+ ${hutool.version}
+ pom
+ import
+
+
+
+
+ com.ruoyi
+ ruoyi-common-bom
+ ${revision}
+ pom
+ import
+
+
org.springframework.boot
spring-boot-starter-jdbc
- ${spring-boot.version}
@@ -76,6 +128,30 @@
${mybatis-flex.version}
+
+
+ cn.dev33
+ sa-token-spring-boot3-starter
+ ${satoken.version}
+
+
+
+ cn.dev33
+ sa-token-jwt
+ ${satoken.version}
+
+
+ cn.hutool
+ hutool-all
+
+
+
+
+ cn.dev33
+ sa-token-core
+ ${satoken.version}
+
+
mysql
@@ -124,12 +200,30 @@
+
+ org.apache.poi
+ poi
+ ${poi.version}
+
+
org.apache.poi
poi-ooxml
${poi.version}
+
+ com.alibaba
+ easyexcel
+ ${easyexcel.version}
+
+
+ org.apache.poi
+ poi-ooxml-schemas
+
+
+
+
org.apache.velocity
@@ -185,7 +279,6 @@
${springdoc.version}
-
org.springdoc
springdoc-openapi-starter-common
@@ -198,6 +291,45 @@
${therapi-runtime-javadoc.version}
+
+ io.github.linpeilie
+ mapstruct-plus-spring-boot-starter
+ ${mapstruct-plus.version}
+
+
+
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+
+
+ org.redisson
+ redisson-spring-boot-starter
+ ${redisson.version}
+
+
+
+ com.baomidou
+ lock4j-redisson-spring-boot-starter
+ ${lock4j.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ ${spring-boot.version}
+
+
+
+ com.alibaba
+ transmittable-thread-local
+ ${alibaba-ttl.version}
+
+
com.ruoyi
@@ -212,13 +344,6 @@
${revision}
-
-
- com.ruoyi
- ruoyi-framework
- ${revision}
-
-
com.ruoyi
@@ -226,20 +351,6 @@
${revision}
-
-
- com.ruoyi
- ruoyi-common-core
- ${revision}
-
-
-
-
- com.ruoyi
- ruoyi-common-springdoc
- ${revision}
-
-
com.ruoyi
@@ -252,8 +363,8 @@
ruoyi-admin
- ruoyi-framework
ruoyi-common
+ ruoyi-extra
ruoyi-modules
pom
@@ -274,7 +385,35 @@
therapi-runtime-javadoc-scribe
${therapi-runtime-javadoc.version}
+
+ org.projectlombok
+ lombok
+ ${lombok.version}
+
+
+ org.springframework.boot
+ spring-boot-configuration-processor
+ ${spring-boot.version}
+
+
+ io.github.linpeilie
+ mapstruct-plus-processor
+ ${mapstruct-plus.version}
+
+
+ org.projectlombok
+ lombok-mapstruct-binding
+ ${mapstruct-plus.lombok.version}
+
+
+ com.mybatis-flex
+ mybatis-flex-processor
+ ${mybatis-flex.version}
+
+
+ -parameters
+
@@ -307,6 +446,24 @@
+
+
+ src/main/resources
+
+ false
+
+
+ src/main/resources
+
+
+ application*
+ bootstrap*
+ banner*
+
+
+ true
+
+
@@ -334,4 +491,4 @@
-
\ No newline at end of file
+
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
index 587a65e..fa9e812 100644
--- a/ruoyi-admin/pom.xml
+++ b/ruoyi-admin/pom.xml
@@ -3,12 +3,13 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- ruoyi-flex
com.ruoyi
+ ruoyi-flex
${revision}
4.0.0
jar
+
ruoyi-admin
@@ -30,16 +31,22 @@
mysql-connector-java
+
+
+ org.postgresql
+ postgresql
+
+
com.mybatis-flex
mybatis-flex-spring-boot-starter
-
+
com.ruoyi
- ruoyi-framework
+ ruoyi-system
@@ -54,13 +61,6 @@
ruoyi-generator
-
-
- com.ruoyi
- ruoyi-common-springdoc
- ${revision}
-
-
com.ruoyi
@@ -74,29 +74,34 @@
org.springframework.boot
spring-boot-maven-plugin
- 2.1.1.RELEASE
+ ${spring-boot.version}
- true
+
-
-
-
- repackage
-
-
-
+
+
+
+
+
+
+
-
- org.apache.maven.plugins
- maven-war-plugin
- 3.1.0
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ ${maven-jar-plugin.version}
+
+
+ org.apache.maven.plugins
+ maven-war-plugin
+ ${maven-war-plugin.version}
false
${project.artifactId}
-
-
+
+
${project.artifactId}
-
\ No newline at end of file
+
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
index 68c7cd2..b69b609 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -5,7 +5,7 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 启动程序
- *
+ *
* @author ruoyi
*/
@SpringBootApplication
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java
new file mode 100644
index 0000000..40cb4aa
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/AuthController.java
@@ -0,0 +1,151 @@
+package com.ruoyi.web.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import cn.hutool.core.util.ObjectUtil;
+import com.mybatisflex.core.query.QueryWrapper;
+import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.core.core.domain.AjaxResult;
+import com.ruoyi.common.core.core.domain.model.LoginUser;
+import com.ruoyi.common.security.utils.LoginHelper;
+import com.ruoyi.system.domain.SysMenu;
+import com.ruoyi.system.domain.SysUser;
+import com.ruoyi.system.service.*;
+import jakarta.annotation.Resource;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import com.ruoyi.common.core.core.domain.R;
+import com.ruoyi.common.core.core.domain.model.LoginBody;
+import com.ruoyi.common.core.core.domain.model.RegisterBody;
+import com.ruoyi.common.core.utils.MessageUtils;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.system.domain.SysClient;
+import com.ruoyi.web.service.IAuthStrategy;
+import com.ruoyi.web.service.SysLoginService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+import java.util.Set;
+
+import static com.ruoyi.system.domain.table.SysClientTableDef.SYS_CLIENT;
+
+
+/**
+ * 认证
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@SaIgnore
+@Validated
+@RequiredArgsConstructor
+@RestController
+public class AuthController {
+
+ @Resource
+ private final SysLoginService loginService;
+ @Resource
+ private final ISysClientService clientService;
+ @Resource
+ private final ISysUserService sysUserService;
+ @Resource
+ private final ISysPermissionService permissionService;
+ @Resource
+ private ISysMenuService menuService;
+
+ /**
+ * 登录方法
+ *
+ * @param loginBody 登录信息
+ * @return 结果
+ */
+ @PostMapping("/login")
+ public AjaxResult login(@Validated @RequestBody LoginBody loginBody) {
+
+ AjaxResult ajax = AjaxResult.success();
+ // 授权类型和客户端id
+ String clientId = loginBody.getClientId();
+ String grantType = loginBody.getGrantType();
+ QueryWrapper query=QueryWrapper.create().from(SYS_CLIENT).where(SYS_CLIENT.CLIENT_ID.eq(clientId));
+ SysClient client = clientService.getOne(query);
+ // 查询不到 client 或 client 内不包含 grantType
+ if (ObjectUtil.isNull(client) || !StringUtils.contains(client.getGrantType(), grantType)) {
+ log.info("客户端id: {} 认证类型:{} 异常!.", clientId, grantType);
+ return AjaxResult.error(MessageUtils.message("auth.grant.type.error"));
+ }
+
+ // TODO:校验租户
+ //loginService.checkTenant(loginBody.getTenantId());
+
+ // 生成令牌
+ String token =IAuthStrategy.login(loginBody, client);
+ ajax.put(Constants.TOKEN, token);
+
+ // 登录
+ return ajax;
+ }
+
+ /**
+ * 获取用户信息
+ *
+ * @return 用户信息
+ */
+ @GetMapping("/getInfo")
+ public AjaxResult getInfo() {
+
+ LoginUser loginUser = LoginHelper.getLoginUser();
+
+ //TODO:多租户 超级管理员 如果重新加载用户信息需清除动态租户
+
+ SysUser user = sysUserService.selectUserById(loginUser.getUserId());
+ // 角色集合
+ Set roles = permissionService.getRolePermission(user.getUserId());
+ // 权限集合
+ Set permissions = permissionService.getMenuPermission(user.getUserId());
+
+ AjaxResult ajax = AjaxResult.success();
+ ajax.put("user", user);
+ ajax.put("roles", roles);
+ ajax.put("permissions", permissions);
+ return ajax;
+ }
+
+ /**
+ * 获取路由信息
+ *
+ * @return 路由信息
+ */
+ @GetMapping("/getRouters")
+ public AjaxResult getRouters()
+ {
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ // 用户信息
+ SysUser user = sysUserService.selectUserById(loginUser.getUserId());
+ List menus = menuService.selectMenuTreeByUserId(user.getUserId());
+ return AjaxResult.success(menuService.buildMenus(menus));
+ }
+
+ /**
+ * 退出登录
+ */
+ @PostMapping("/logout")
+ public AjaxResult logout() {
+ loginService.logout();
+ return AjaxResult.error("退出成功!");
+ }
+
+ /**
+ * 用户注册
+ */
+ @PostMapping("LoginHelper.getUserId()")
+ public R register(@Validated @RequestBody RegisterBody user) {
+ //if (!configService.selectRegisterEnabled(user.getTenantId())) // TODO:注册代码
+ {
+ return R.fail("当前系统没有开启注册功能!");
+ }
+// registerService.register(user);
+// return R.ok();
+ }
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java
new file mode 100644
index 0000000..99a0dc6
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/CaptchaController.java
@@ -0,0 +1,84 @@
+package com.ruoyi.web.controller;
+
+import cn.dev33.satoken.annotation.SaIgnore;
+import java.time.Duration;
+
+import cn.hutool.captcha.AbstractCaptcha;
+import cn.hutool.captcha.generator.CodeGenerator;
+import cn.hutool.core.util.IdUtil;
+import com.ruoyi.common.core.constant.GlobalConstants;
+import com.ruoyi.common.core.core.domain.AjaxResult;
+import com.ruoyi.common.core.utils.StringUtils;
+import com.ruoyi.common.core.utils.reflect.ReflectUtils;
+import com.ruoyi.common.core.utils.SpringUtils;
+import com.ruoyi.common.core.core.domain.R;
+import com.ruoyi.common.redis.utils.RedisUtils;
+import com.ruoyi.common.web.enums.CaptchaType;
+import com.ruoyi.web.domain.vo.CaptchaVo;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.expression.Expression;
+import org.springframework.expression.ExpressionParser;
+import org.springframework.expression.spel.standard.SpelExpressionParser;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.core.constant.Constants;
+import com.ruoyi.common.web.config.properties.CaptchaProperties;
+
+/**
+ * 验证码操作处理
+ *
+ * @author ruoyi
+ */
+@SaIgnore
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+public class CaptchaController
+{
+ private final CaptchaProperties captchaProperties;
+
+ /**
+ * 生成验证码
+ */
+ @GetMapping("/captchaImage")
+ public AjaxResult getCode() {
+ CaptchaVo captchaVo = new CaptchaVo();
+ boolean captchaEnabled = captchaProperties.getEnable();
+ if (!captchaEnabled) {
+ captchaVo.setCaptchaEnabled(false);
+ return AjaxResult.success(captchaVo);
+ }
+ // 保存验证码信息
+ String uuid = IdUtil.simpleUUID();
+ String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
+ // 生成验证码
+ CaptchaType captchaType = captchaProperties.getType();
+ boolean isMath = CaptchaType.MATH == captchaType;
+ Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength();
+ CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length);
+ AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
+ captcha.setGenerator(codeGenerator);
+ captcha.createCode();
+ String code = captcha.getCode();
+ if (isMath) {
+ ExpressionParser parser = new SpelExpressionParser();
+ Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
+ code = exp.getValue(String.class);
+ }
+ RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+
+// AjaxResult ajax = AjaxResult.success();
+// ajax.put("uuid", uuid);
+// ajax.put("img", captcha.getImageBase64());
+// return ajax;
+
+ captchaVo.setUuid(uuid);
+ captchaVo.setImg(captcha.getImageBase64());
+ return AjaxResult.success(captchaVo);
+
+
+ }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java
similarity index 84%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
rename to ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java
index 645bb5f..f600ce2 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/SysIndexController.java
@@ -1,5 +1,7 @@
-package com.ruoyi.web.controller.system;
+package com.ruoyi.web.controller;
+import cn.dev33.satoken.annotation.SaIgnore;
+import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -11,11 +13,12 @@ import com.ruoyi.common.core.utils.StringUtils;
*
* @author ruoyi
*/
+@SaIgnore
@RestController
public class SysIndexController
{
/** 系统基础配置 */
- @Autowired
+ @Resource
private RuoYiConfig ruoyiConfig;
/**
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
deleted file mode 100644
index 79002cb..0000000
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
+++ /dev/null
@@ -1,94 +0,0 @@
-package com.ruoyi.web.controller.common;
-
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import jakarta.annotation.Resource;
-import javax.imageio.ImageIO;
-import jakarta.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.FastByteArrayOutputStream;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.google.code.kaptcha.Producer;
-import com.ruoyi.common.core.config.RuoYiConfig;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.constant.Constants;
-import com.ruoyi.common.core.core.domain.AjaxResult;
-import com.ruoyi.common.core.core.redis.RedisCache;
-import com.ruoyi.common.core.utils.sign.Base64;
-import com.ruoyi.common.core.utils.uuid.IdUtils;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 验证码操作处理
- *
- * @author ruoyi
- */
-@RestController
-public class CaptchaController
-{
- @Resource(name = "captchaProducer")
- private Producer captchaProducer;
-
- @Resource(name = "captchaProducerMath")
- private Producer captchaProducerMath;
-
- @Autowired
- private RedisCache redisCache;
-
- @Autowired
- private ISysConfigService configService;
- /**
- * 生成验证码
- */
- @GetMapping("/captchaImage")
- public AjaxResult getCode(HttpServletResponse response) throws IOException
- {
- AjaxResult ajax = AjaxResult.success();
- boolean captchaEnabled = configService.selectCaptchaEnabled();
- ajax.put("captchaEnabled", captchaEnabled);
- if (!captchaEnabled)
- {
- return ajax;
- }
-
- // 保存验证码信息
- String uuid = IdUtils.simpleUUID();
- String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
-
- String capStr = null, code = null;
- BufferedImage image = null;
-
- // 生成验证码
- String captchaType = RuoYiConfig.getCaptchaType();
- if ("math".equals(captchaType))
- {
- String capText = captchaProducerMath.createText();
- capStr = capText.substring(0, capText.lastIndexOf("@"));
- code = capText.substring(capText.lastIndexOf("@") + 1);
- image = captchaProducerMath.createImage(capStr);
- }
- else if ("char".equals(captchaType))
- {
- capStr = code = captchaProducer.createText();
- image = captchaProducer.createImage(capStr);
- }
-
- redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
- // 转换流信息写出
- FastByteArrayOutputStream os = new FastByteArrayOutputStream();
- try
- {
- ImageIO.write(image, "jpg", os);
- }
- catch (IOException e)
- {
- return AjaxResult.error(e.getMessage());
- }
-
- ajax.put("uuid", uuid);
- ajax.put("img", Base64.encode(os.toByteArray()));
- return ajax;
- }
-}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
index 88e197a..ac261cc 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -19,11 +19,11 @@ import com.ruoyi.common.core.core.domain.AjaxResult;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.core.utils.file.FileUploadUtils;
import com.ruoyi.common.core.utils.file.FileUtils;
-import com.ruoyi.framework.config.ServerConfig;
+import com.ruoyi.system.config.ServerConfig;
/**
* 通用请求处理
- *
+ *
* @author ruoyi
*/
@RestController
@@ -39,7 +39,7 @@ public class CommonController
/**
* 通用下载请求
- *
+ *
* @param fileName 文件名称
* @param delete 是否删除
*/
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
deleted file mode 100644
index e0ffd5a..0000000
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.ruoyi.web.controller.monitor;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.security.access.prepost.PreAuthorize;
-import org.springframework.web.bind.annotation.DeleteMapping;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PathVariable;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.core.domain.AjaxResult;
-import com.ruoyi.common.core.utils.StringUtils;
-import com.ruoyi.system.domain.SysCache;
-
-/**
- * 缓存监控
- *
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/cache")
-public class CacheController
-{
- @Autowired
- private RedisTemplate redisTemplate;
-
- private final static List caches = new ArrayList();
- {
- caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
- caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
- caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
- caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
- caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
- caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
- caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
- }
-
- @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
- @GetMapping()
- public AjaxResult getInfo() throws Exception
- {
- Properties info = (Properties) redisTemplate.execute((RedisCallback
-
-
- org.springframework.boot
- spring-boot-starter-security
-
-
-
-
- com.github.pagehelper
- pagehelper
-
-
-
-
- com.mybatis-flex
- mybatis-flex-spring-boot-starter
-
-
org.springframework.boot
@@ -64,7 +47,7 @@
org.apache.commons
commons-lang3
-
+
com.fasterxml.jackson.core
@@ -108,12 +91,6 @@
2.3.1
-
-
- org.springframework.boot
- spring-boot-starter-data-redis
-
-
org.apache.commons
@@ -132,6 +109,51 @@
jakarta.servlet-api
+
+
+ org.projectlombok
+ lombok
+
+
+
+
+ cn.hutool
+ hutool-core
+
+
+
+ cn.hutool
+ hutool-http
+
+
+
+ cn.hutool
+ hutool-extra
+
+
+
+ cn.hutool
+ hutool-json
+ provided
+
+
+
+
+ io.github.linpeilie
+ mapstruct-plus-spring-boot-starter
+
+
+
+
+ com.github.pagehelper
+ pagehelper-spring-boot-starter
+
+
+ com.github.pagehelper
+ pagehelper
+
+
+
-
\ No newline at end of file
+
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java
deleted file mode 100644
index 6f836dc..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/DataSource.java
+++ /dev/null
@@ -1,28 +0,0 @@
-package com.ruoyi.common.core.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Inherited;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.ruoyi.common.core.enums.DataSourceType;
-
-/**
- * 自定义多数据源切换注解
- *
- * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
- *
- * @author ruoyi
- */
-@Target({ ElementType.METHOD, ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@Inherited
-public @interface DataSource
-{
- /**
- * 切换数据源名称
- */
- public DataSourceType value() default DataSourceType.MASTER;
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java
deleted file mode 100644
index f283537..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/annotation/Log.java
+++ /dev/null
@@ -1,51 +0,0 @@
-package com.ruoyi.common.core.annotation;
-
-import java.lang.annotation.Documented;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import com.ruoyi.common.core.enums.BusinessType;
-import com.ruoyi.common.core.enums.OperatorType;
-
-/**
- * 自定义操作日志记录注解
- *
- * @author ruoyi
- *
- */
-@Target({ ElementType.PARAMETER, ElementType.METHOD })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Log
-{
- /**
- * 模块
- */
- public String title() default "";
-
- /**
- * 功能
- */
- public BusinessType businessType() default BusinessType.OTHER;
-
- /**
- * 操作人类别
- */
- public OperatorType operatorType() default OperatorType.MANAGE;
-
- /**
- * 是否保存请求的参数
- */
- public boolean isSaveRequestData() default true;
-
- /**
- * 是否保存响应的参数
- */
- public boolean isSaveResponseData() default true;
-
- /**
- * 排除指定的请求参数
- */
- public String[] excludeParamNames() default {};
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java
new file mode 100644
index 0000000..0bfa503
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ApplicationConfig.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.core.config;
+
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * 程序注解配置
+ *
+ * @author ruoyi
+ */
+@AutoConfiguration
+// 表示通过aop框架暴露该代理对象,AopContext能够访问
+@EnableAspectJAutoProxy(exposeProxy = true)
+// 指定要扫描的Mapper类的包的路径
+public class ApplicationConfig
+{
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java
new file mode 100644
index 0000000..14dc801
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/AsyncConfig.java
@@ -0,0 +1,48 @@
+package com.ruoyi.common.core.config;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.ruoyi.common.core.exception.ServiceException;
+import com.ruoyi.common.core.utils.SpringUtils;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+
+/**
+ * 异步配置
+ *
+ * @author Lion Li
+ */
+@EnableAsync(proxyTargetClass = true)
+@AutoConfiguration
+public class AsyncConfig implements AsyncConfigurer {
+
+ /**
+ * 自定义 @Async 注解使用系统线程池
+ */
+ @Override
+ public Executor getAsyncExecutor() {
+ return SpringUtils.getBean("scheduledExecutorService");
+ }
+
+ /**
+ * 异步执行异常处理
+ */
+ @Override
+ public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+ return (throwable, method, objects) -> {
+ throwable.printStackTrace();
+ StringBuilder sb = new StringBuilder();
+ sb.append("Exception message - ").append(throwable.getMessage())
+ .append(", Method name - ").append(method.getName());
+ if (ArrayUtil.isNotEmpty(objects)) {
+ sb.append(", Parameter value - ").append(Arrays.toString(objects));
+ }
+ throw new ServiceException(sb.toString());
+ };
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java
index c9fcffc..8b6fe87 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/RuoYiConfig.java
@@ -1,76 +1,53 @@
package com.ruoyi.common.core.config;
+import lombok.Data;
+import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 读取项目相关配置
- *
+ *
* @author ruoyi
*/
+@Data
@Component
@ConfigurationProperties(prefix = "ruoyi")
-public class RuoYiConfig
-{
- /** 项目名称 */
+public class RuoYiConfig {
+
+ /**
+ * 项目名称
+ */
private String name;
- /** 版本 */
+ /**
+ * 版本
+ */
private String version;
- /** 版权年份 */
+ /**
+ * 版权年份
+ */
private String copyrightYear;
- /** 实例演示开关 */
+ /**
+ * 实例演示开关
+ */
private boolean demoEnabled;
- /** 上传路径 */
+ /**
+ * 文件路径
+ */
private static String profile;
- /** 获取地址开关 */
+ /**
+ * 获取地址开关
+ */
+ @Getter
private static boolean addressEnabled;
- /** 验证码类型 */
- private static String captchaType;
-
- public String getName()
- {
- return name;
- }
-
- public void setName(String name)
- {
- this.name = name;
- }
-
- public String getVersion()
- {
- return version;
- }
-
- public void setVersion(String version)
- {
- this.version = version;
- }
-
- public String getCopyrightYear()
- {
- return copyrightYear;
- }
-
- public void setCopyrightYear(String copyrightYear)
- {
- this.copyrightYear = copyrightYear;
- }
-
- public boolean isDemoEnabled()
- {
- return demoEnabled;
- }
-
- public void setDemoEnabled(boolean demoEnabled)
- {
- this.demoEnabled = demoEnabled;
+ public void setAddressEnabled(boolean addressEnabled) {
+ RuoYiConfig.addressEnabled = addressEnabled;
}
public static String getProfile()
@@ -78,29 +55,6 @@ public class RuoYiConfig
return profile;
}
- public void setProfile(String profile)
- {
- RuoYiConfig.profile = profile;
- }
-
- public static boolean isAddressEnabled()
- {
- return addressEnabled;
- }
-
- public void setAddressEnabled(boolean addressEnabled)
- {
- RuoYiConfig.addressEnabled = addressEnabled;
- }
-
- public static String getCaptchaType() {
- return captchaType;
- }
-
- public void setCaptchaType(String captchaType) {
- RuoYiConfig.captchaType = captchaType;
- }
-
/**
* 获取导入上传路径
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..727ad67
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ThreadPoolConfig.java
@@ -0,0 +1,76 @@
+package com.ruoyi.common.core.config;
+
+import com.ruoyi.common.core.config.properties.ThreadPoolProperties;
+import com.ruoyi.common.core.utils.Threads;
+import jakarta.annotation.PreDestroy;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 线程池配置
+ *
+ * @author ruoyi
+ **/
+@Slf4j
+@AutoConfiguration
+@EnableConfigurationProperties(ThreadPoolProperties.class)
+public class ThreadPoolConfig
+{
+ /**
+ * 核心线程数 = cpu 核心数 + 1
+ */
+ private final int core = Runtime.getRuntime().availableProcessors() + 1;
+
+ private ScheduledExecutorService scheduledExecutorService;
+
+ @Bean(name = "threadPoolTaskExecutor")
+ @ConditionalOnProperty(prefix = "thread-pool", name = "enabled", havingValue = "true")
+ public ThreadPoolTaskExecutor threadPoolTaskExecutor(ThreadPoolProperties threadPoolProperties) {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(core);
+ executor.setMaxPoolSize(core * 2);
+ executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
+ executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+ return executor;
+ }
+
+ /**
+ * 执行周期性或定时任务
+ */
+ @Bean(name = "scheduledExecutorService")
+ protected ScheduledExecutorService scheduledExecutorService() {
+ ScheduledThreadPoolExecutor scheduledThreadPoolExecutor = new ScheduledThreadPoolExecutor(core,
+ new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build(),
+ new ThreadPoolExecutor.CallerRunsPolicy()) {
+ @Override
+ protected void afterExecute(Runnable r, Throwable t) {
+ super.afterExecute(r, t);
+ Threads.printException(r, t);
+ }
+ };
+ this.scheduledExecutorService = scheduledThreadPoolExecutor;
+ return scheduledThreadPoolExecutor;
+ }
+
+ /**
+ * 销毁事件
+ */
+ @PreDestroy
+ public void destroy() {
+ try {
+ log.info("====关闭后台任务任务线程池====");
+ Threads.shutdownAndAwaitTermination(scheduledExecutorService);
+ } catch (Exception e) {
+ log.error(e.getMessage(), e);
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java
new file mode 100644
index 0000000..cb0d786
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/ValidatorConfig.java
@@ -0,0 +1,40 @@
+package com.ruoyi.common.core.config;
+
+import jakarta.validation.Validator;
+import org.hibernate.validator.HibernateValidator;
+import org.springframework.boot.autoconfigure.AutoConfiguration;
+import org.springframework.context.MessageSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
+
+import java.util.Properties;
+
+/**
+ * 校验框架配置类
+ *
+ * @author Lion Li
+ */
+@AutoConfiguration
+public class ValidatorConfig {
+
+ /**
+ * 配置校验框架 快速返回模式
+ */
+ @Bean
+ public Validator validator(MessageSource messageSource) {
+ try (LocalValidatorFactoryBean factoryBean = new LocalValidatorFactoryBean()) {
+ // 国际化
+ factoryBean.setValidationMessageSource(messageSource);
+ // 设置使用 HibernateValidator 校验器
+ factoryBean.setProviderClass(HibernateValidator.class);
+ Properties properties = new Properties();
+ // 设置 快速异常返回
+ properties.setProperty("hibernate.validator.fail_fast", "true");
+ factoryBean.setValidationProperties(properties);
+ // 加载配置
+ factoryBean.afterPropertiesSet();
+ return factoryBean.getValidator();
+ }
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java
new file mode 100644
index 0000000..d7f4678
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/config/properties/ThreadPoolProperties.java
@@ -0,0 +1,30 @@
+package com.ruoyi.common.core.config.properties;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * 线程池 配置属性
+ *
+ * @author Lion Li
+ */
+@Data
+@ConfigurationProperties(prefix = "thread-pool")
+public class ThreadPoolProperties {
+
+ /**
+ * 是否开启线程池
+ */
+ private boolean enabled;
+
+ /**
+ * 队列最大长度
+ */
+ private int queueCapacity;
+
+ /**
+ * 线程池维护线程所允许的空闲时间
+ */
+ private int keepAliveSeconds;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
index 3a871ad..77dd8ea 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheConstants.java
@@ -7,6 +7,11 @@ package com.ruoyi.common.core.constant;
*/
public class CacheConstants
{
+ /**
+ * 在线用户 redis key
+ */
+ public static final String ONLINE_TOKEN_KEY = "online_tokens:";
+
/**
* 登录用户 redis key
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java
new file mode 100644
index 0000000..81e92f5
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/CacheNames.java
@@ -0,0 +1,63 @@
+package com.ruoyi.common.core.constant;
+
+/**
+ * 缓存组名称常量
+ *
+ * key 格式为 cacheNames#ttl#maxIdleTime#maxSize
+ *
+ * ttl 过期时间 如果设置为0则不过期 默认为0
+ * maxIdleTime 最大空闲时间 根据LRU算法清理空闲数据 如果设置为0则不检测 默认为0
+ * maxSize 组最大长度 根据LRU算法清理溢出数据 如果设置为0则无限长 默认为0
+ *
+ * 例子: test#60s、test#0#60s、test#0#1m#1000、test#1h#0#500
+ *
+ * @author Lion Li
+ */
+public interface CacheNames {
+
+ /**
+ * 演示案例
+ */
+ String DEMO_CACHE = "demo:cache#60s#10m#20";
+
+ /**
+ * 系统配置
+ */
+ String SYS_CONFIG = "sys_config";
+
+ /**
+ * 数据字典
+ */
+ String SYS_DICT = "sys_dict";
+
+ /**
+ * 租户
+ */
+ String SYS_TENANT = GlobalConstants.GLOBAL_REDIS_KEY + "sys_tenant#30d";
+
+ /**
+ * 用户账户
+ */
+ String SYS_USER_NAME = "sys_user_name#30d";
+
+ /**
+ * 部门
+ */
+ String SYS_DEPT = "sys_dept#30d";
+
+ /**
+ * OSS内容
+ */
+ String SYS_OSS = "sys_oss#30d";
+
+ /**
+ * OSS配置
+ */
+ String SYS_OSS_CONFIG = "sys_oss_config";
+
+ /**
+ * 在线用户
+ */
+ String ONLINE_TOKEN = "online_tokens";
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
index f646e76..49bafa0 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/Constants.java
@@ -69,6 +69,11 @@ public class Constants
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
+ /**
+ * 登录用户 redis key
+ */
+ public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
/**
* 令牌
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java
new file mode 100644
index 0000000..60fb162
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/GlobalConstants.java
@@ -0,0 +1,39 @@
+package com.ruoyi.common.core.constant;
+
+/**
+ * 全局的key常量 (业务无关的key)
+ *
+ * @author Lion Li
+ */
+public interface GlobalConstants {
+
+ /**
+ * 全局 redis key (业务无关的key)
+ */
+ String GLOBAL_REDIS_KEY = "global:";
+
+ /**
+ * 验证码 redis key
+ */
+ String CAPTCHA_CODE_KEY = GLOBAL_REDIS_KEY + "captcha_codes:";
+
+ /**
+ * 防重提交 redis key
+ */
+ String REPEAT_SUBMIT_KEY = GLOBAL_REDIS_KEY + "repeat_submit:";
+
+ /**
+ * 限流 redis key
+ */
+ String RATE_LIMIT_KEY = GLOBAL_REDIS_KEY + "rate_limit:";
+
+ /**
+ * 登录账户密码错误次数 redis key
+ */
+ String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";
+
+ /**
+ * 三方认证 redis key
+ */
+ String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java
new file mode 100644
index 0000000..6411ba4
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/TenantConstants.java
@@ -0,0 +1,45 @@
+package com.ruoyi.common.core.constant;
+
+/**
+ * 租户常量信息
+ *
+ * @author Lion Li
+ */
+public interface TenantConstants {
+
+ /**
+ * 租户正常状态
+ */
+ String NORMAL = "0";
+
+ /**
+ * 租户封禁状态
+ */
+ String DISABLE = "1";
+
+ /**
+ * 超级管理员ID
+ */
+ Long SUPER_ADMIN_ID = 1L;
+
+ /**
+ * 超级管理员角色 roleKey
+ */
+ String SUPER_ADMIN_ROLE_KEY = "superadmin";
+
+ /**
+ * 租户管理员角色 roleKey
+ */
+ String TENANT_ADMIN_ROLE_KEY = "admin";
+
+ /**
+ * 租户管理员角色名称
+ */
+ String TENANT_ADMIN_ROLE_NAME = "管理员";
+
+ /**
+ * 默认租户ID
+ */
+ String DEFAULT_TENANT_ID = "000000";
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java
index c3f4282..f696fe9 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/constant/UserConstants.java
@@ -2,65 +2,118 @@ package com.ruoyi.common.core.constant;
/**
* 用户常量信息
- *
+ *
* @author ruoyi
*/
-public class UserConstants
-{
+public class UserConstants {
/**
* 平台内系统用户的唯一标志
*/
public static final String SYS_USER = "SYS_USER";
- /** 正常状态 */
+ /**
+ * 正常状态
+ */
public static final String NORMAL = "0";
- /** 异常状态 */
+ /**
+ * 异常状态
+ */
public static final String EXCEPTION = "1";
- /** 用户封禁状态 */
+ /**
+ * 用户正常状态
+ */
+ public static final String USER_NORMAL = "0";
+
+ /**
+ * 用户封禁状态
+ */
public static final String USER_DISABLE = "1";
- /** 角色封禁状态 */
+ /**
+ * 角色正常状态
+ */
+ public static final String ROLE_NORMAL = "0";
+
+ /**
+ * 角色封禁状态
+ */
public static final String ROLE_DISABLE = "1";
- /** 部门正常状态 */
+ /**
+ * 部门正常状态
+ */
public static final String DEPT_NORMAL = "0";
- /** 部门停用状态 */
+ /**
+ * 部门停用状态
+ */
public static final String DEPT_DISABLE = "1";
- /** 字典正常状态 */
+ /**
+ * 岗位正常状态
+ */
+ public static final String POST_NORMAL = "0";
+
+ /**
+ * 岗位停用状态
+ */
+ public static final String POST_DISABLE = "1";
+
+ /**
+ * 字典正常状态
+ */
public static final String DICT_NORMAL = "0";
- /** 是否为系统默认(是) */
+ /**
+ * 是否为系统默认(是)
+ */
public static final String YES = "Y";
- /** 是否菜单外链(是) */
+ /**
+ * 是否菜单外链(是)
+ */
public static final String YES_FRAME = "0";
- /** 是否菜单外链(否) */
+ /**
+ * 是否菜单外链(否)
+ */
public static final String NO_FRAME = "1";
- /** 菜单类型(目录) */
+ /**
+ * 菜单类型(目录)
+ */
public static final String TYPE_DIR = "M";
- /** 菜单类型(菜单) */
+ /**
+ * 菜单类型(菜单)
+ */
public static final String TYPE_MENU = "C";
- /** 菜单类型(按钮) */
+ /**
+ * 菜单类型(按钮)
+ */
public static final String TYPE_BUTTON = "F";
- /** Layout组件标识 */
+ /**
+ * Layout组件标识
+ */
public final static String LAYOUT = "Layout";
-
- /** ParentView组件标识 */
+
+ /**
+ * ParentView组件标识
+ */
public final static String PARENT_VIEW = "ParentView";
- /** InnerLink组件标识 */
+ /**
+ * InnerLink组件标识
+ */
public final static String INNER_LINK = "InnerLink";
- /** 校验是否唯一的返回标识 */
+ /**
+ * 校验是否唯一的返回标识
+ */
public final static boolean UNIQUE = true;
public final static boolean NOT_UNIQUE = false;
@@ -75,4 +128,9 @@ public class UserConstants
*/
public static final int PASSWORD_MIN_LENGTH = 5;
public static final int PASSWORD_MAX_LENGTH = 20;
+
+ /**
+ * 超级管理员ID
+ */
+ public static final Long SUPER_ADMIN_ID = 1L;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java
index 16364c0..31ea6bd 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/AjaxResult.java
@@ -7,7 +7,7 @@ import com.ruoyi.common.core.utils.StringUtils;
/**
* 操作消息提醒
- *
+ *
* @author ruoyi
*/
public class AjaxResult extends HashMap
@@ -32,7 +32,7 @@ public class AjaxResult extends HashMap
/**
* 初始化一个新创建的 AjaxResult 对象
- *
+ *
* @param code 状态码
* @param msg 返回内容
*/
@@ -44,7 +44,7 @@ public class AjaxResult extends HashMap
/**
* 初始化一个新创建的 AjaxResult 对象
- *
+ *
* @param code 状态码
* @param msg 返回内容
* @param data 数据对象
@@ -61,7 +61,7 @@ public class AjaxResult extends HashMap
/**
* 返回成功消息
- *
+ *
* @return 成功消息
*/
public static AjaxResult success()
@@ -71,7 +71,7 @@ public class AjaxResult extends HashMap
/**
* 返回成功数据
- *
+ *
* @return 成功消息
*/
public static AjaxResult success(Object data)
@@ -81,7 +81,7 @@ public class AjaxResult extends HashMap
/**
* 返回成功消息
- *
+ *
* @param msg 返回内容
* @return 成功消息
*/
@@ -92,7 +92,7 @@ public class AjaxResult extends HashMap
/**
* 返回成功消息
- *
+ *
* @param msg 返回内容
* @param data 数据对象
* @return 成功消息
@@ -127,7 +127,7 @@ public class AjaxResult extends HashMap
/**
* 返回错误消息
- *
+ *
* @return 错误消息
*/
public static AjaxResult error()
@@ -137,7 +137,7 @@ public class AjaxResult extends HashMap
/**
* 返回错误消息
- *
+ *
* @param msg 返回内容
* @return 错误消息
*/
@@ -148,7 +148,7 @@ public class AjaxResult extends HashMap
/**
* 返回错误消息
- *
+ *
* @param msg 返回内容
* @param data 数据对象
* @return 错误消息
@@ -160,7 +160,7 @@ public class AjaxResult extends HashMap
/**
* 返回错误消息
- *
+ *
* @param code 状态码
* @param msg 返回内容
* @return 错误消息
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java
deleted file mode 100644
index 0ac99f0..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/BaseEntity.java
+++ /dev/null
@@ -1,121 +0,0 @@
-package com.ruoyi.common.core.core.domain;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.mybatisflex.annotation.Column;
-
-/**
- * Entity基类
- *
- * @author ruoyi
- */
-public class BaseEntity implements Serializable
-{
- private static final long serialVersionUID = 1L;
-
- /** 搜索值 */
- @JsonIgnore
- @Column(ignore = true)
- private String searchValue;
-
- /** 创建者 */
- private String createBy;
-
- /** 创建时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date createTime;
-
- /** 更新者 */
- private String updateBy;
-
- /** 更新时间 */
- @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
- private Date updateTime;
-
- /** 备注 */
- private String remark;
-
- /** 请求参数 */
- @JsonInclude(JsonInclude.Include.NON_EMPTY)
- @Column(ignore = true)
- private Map params;
-
- public String getSearchValue()
- {
- return searchValue;
- }
-
- public void setSearchValue(String searchValue)
- {
- this.searchValue = searchValue;
- }
-
- public String getCreateBy()
- {
- return createBy;
- }
-
- public void setCreateBy(String createBy)
- {
- this.createBy = createBy;
- }
-
- public Date getCreateTime()
- {
- return createTime;
- }
-
- public void setCreateTime(Date createTime)
- {
- this.createTime = createTime;
- }
-
- public String getUpdateBy()
- {
- return updateBy;
- }
-
- public void setUpdateBy(String updateBy)
- {
- this.updateBy = updateBy;
- }
-
- public Date getUpdateTime()
- {
- return updateTime;
- }
-
- public void setUpdateTime(Date updateTime)
- {
- this.updateTime = updateTime;
- }
-
- public String getRemark()
- {
- return remark;
- }
-
- public void setRemark(String remark)
- {
- this.remark = remark;
- }
-
- public Map getParams()
- {
- if (params == null)
- {
- params = new HashMap<>();
- }
- return params;
- }
-
- public void setParams(Map params)
- {
- this.params = params;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java
index dad3fe3..65b1266 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/R.java
@@ -1,15 +1,21 @@
package com.ruoyi.common.core.core.domain;
+import java.io.Serial;
import java.io.Serializable;
import com.ruoyi.common.core.constant.HttpStatus;
+import lombok.Data;
+import lombok.NoArgsConstructor;
/**
* 响应信息主体
*
* @author ruoyi
*/
+@Data
+@NoArgsConstructor
public class R implements Serializable
{
+ @Serial
private static final long serialVersionUID = 1L;
/** 成功 */
@@ -34,6 +40,10 @@ public class R implements Serializable
return restResult(data, SUCCESS, "操作成功");
}
+ public static R ok(String msg) {
+ return restResult(null, SUCCESS, msg);
+ }
+
public static R ok(T data, String msg)
{
return restResult(data, SUCCESS, msg);
@@ -54,7 +64,7 @@ public class R implements Serializable
return restResult(data, FAIL, "操作失败");
}
- public static R fail(T data, String msg)
+ public static R fail(String msg, T data)
{
return restResult(data, FAIL, msg);
}
@@ -64,6 +74,27 @@ public class R implements Serializable
return restResult(null, code, msg);
}
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @return 警告消息
+ */
+ public static R warn(String msg) {
+ return restResult(null, HttpStatus.WARN, msg);
+ }
+
+ /**
+ * 返回警告消息
+ *
+ * @param msg 返回内容
+ * @param data 数据对象
+ * @return 警告消息
+ */
+ public static R warn(String msg, T data) {
+ return restResult(data, HttpStatus.WARN, msg);
+ }
+
private static R restResult(T data, int code, String msg)
{
R apiResult = new R<>();
@@ -73,36 +104,6 @@ public class R implements Serializable
return apiResult;
}
- public int getCode()
- {
- return code;
- }
-
- public void setCode(int code)
- {
- this.code = code;
- }
-
- public String getMsg()
- {
- return msg;
- }
-
- public void setMsg(String msg)
- {
- this.msg = msg;
- }
-
- public T getData()
- {
- return data;
- }
-
- public void setData(T data)
- {
- this.data = data;
- }
-
public static Boolean isError(R ret)
{
return !isSuccess(ret);
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java
new file mode 100644
index 0000000..bf488ce
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/RoleDTO.java
@@ -0,0 +1,38 @@
+package com.ruoyi.common.core.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 角色
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+public class RoleDTO implements Serializable {
+
+ /**
+ * 角色ID
+ */
+ private Long roleId;
+
+ /**
+ * 角色名称
+ */
+ private String roleName;
+
+ /**
+ * 角色权限
+ */
+ private String roleKey;
+
+ /**
+ * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+ */
+ private String dataScope;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java
new file mode 100644
index 0000000..542f6ec
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/dto/UserOnlineDTO.java
@@ -0,0 +1,62 @@
+package com.ruoyi.common.core.core.domain.dto;
+
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 当前在线会话
+ *
+ * @author ruoyi
+ */
+
+@Data
+@NoArgsConstructor
+public class UserOnlineDTO implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 会话编号
+ */
+ private String tokenId;
+
+ /**
+ * 部门名称
+ */
+ private String deptName;
+
+ /**
+ * 用户名称
+ */
+ private String userName;
+
+ /**
+ * 登录IP地址
+ */
+ private String ipaddr;
+
+ /**
+ * 登录地址
+ */
+ private String loginLocation;
+
+ /**
+ * 浏览器类型
+ */
+ private String browser;
+
+ /**
+ * 操作系统
+ */
+ private String os;
+
+ /**
+ * 登录时间
+ */
+ private Long loginTime;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java
new file mode 100644
index 0000000..189a4c9
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/EmailLoginBody.java
@@ -0,0 +1,35 @@
+package com.ruoyi.common.core.core.domain.model;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+/**
+ * 邮件登录对象
+ *
+ * @author Lion Li
+ */
+
+@Data
+public class EmailLoginBody {
+
+ /**
+ * 租户ID
+ */
+ @NotBlank(message = "{tenant.number.not.blank}")
+ private String tenantId;
+
+ /**
+ * 邮箱
+ */
+ @NotBlank(message = "{user.email.not.blank}")
+ @Email(message = "{user.email.not.valid}")
+ private String email;
+
+ /**
+ * 邮箱code
+ */
+ @NotBlank(message = "{email.code.not.blank}")
+ private String emailCode;
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java
index edd9607..ad8ecab 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginBody.java
@@ -1,20 +1,60 @@
package com.ruoyi.common.core.core.domain.model;
+import com.ruoyi.common.core.constant.UserConstants;
+import com.ruoyi.common.core.validate.auth.*;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
/**
* 用户登录对象
- *
+ *
* @author ruoyi
*/
+@Data
public class LoginBody
{
+ /**
+ * 客户端id
+ */
+ @NotBlank(message = "{auth.clientid.not.blank}")
+ private String clientId;
+
+ /**
+ * 客户端key
+ */
+ private String clientKey;
+
+ /**
+ * 客户端秘钥
+ */
+ private String clientSecret;
+
+ /**
+ * 授权类型
+ */
+ @NotBlank(message = "{auth.grant.type.not.blank}")
+ private String grantType;
+
+ /**
+ * 租户ID
+ */
+ //@NotBlank(message = "{tenant.number.not.blank}")
+ private Long tenantId;
+
/**
* 用户名
*/
+ @NotBlank(message = "{user.username.not.blank}", groups = {PasswordGroup.class})
+ @Length(min = UserConstants.USERNAME_MIN_LENGTH, max = UserConstants.USERNAME_MAX_LENGTH, message = "{user.username.length.valid}", groups = {PasswordGroup.class})
private String username;
/**
* 用户密码
*/
+ @NotBlank(message = "{user.password.not.blank}", groups = {PasswordGroup.class})
+ @Length(min = UserConstants.PASSWORD_MIN_LENGTH, max = UserConstants.PASSWORD_MAX_LENGTH, message = "{user.password.length.valid}", groups = {PasswordGroup.class})
private String password;
/**
@@ -27,43 +67,52 @@ public class LoginBody
*/
private String uuid;
- public String getUsername()
- {
- return username;
- }
+ /**
+ * 手机号
+ */
+ @NotBlank(message = "{user.phonenumber.not.blank}", groups = {SmsGroup.class})
+ private String phonenumber;
- public void setUsername(String username)
- {
- this.username = username;
- }
+ /**
+ * 短信code
+ */
+ @NotBlank(message = "{sms.code.not.blank}", groups = {SmsGroup.class})
+ private String smsCode;
- public String getPassword()
- {
- return password;
- }
+ /**
+ * 邮箱
+ */
+ @NotBlank(message = "{user.email.not.blank}", groups = {EmailGroup.class})
+ @Email(message = "{user.email.not.valid}")
+ private String email;
- public void setPassword(String password)
- {
- this.password = password;
- }
+ /**
+ * 邮箱code
+ */
+ @NotBlank(message = "{email.code.not.blank}", groups = {EmailGroup.class})
+ private String emailCode;
- public String getCode()
- {
- return code;
- }
+ /**
+ * 小程序code
+ */
+ @NotBlank(message = "{xcx.code.not.blank}", groups = {WechatGroup.class})
+ private String xcxCode;
- public void setCode(String code)
- {
- this.code = code;
- }
+ /**
+ * 第三方登录平台
+ */
+ @NotBlank(message = "{social.source.not.blank}" , groups = {SocialGroup.class})
+ private String source;
- public String getUuid()
- {
- return uuid;
- }
+ /**
+ * 第三方登录code
+ */
+ @NotBlank(message = "{social.code.not.blank}" , groups = {SocialGroup.class})
+ private String socialCode;
- public void setUuid(String uuid)
- {
- this.uuid = uuid;
- }
+ /**
+ * 第三方登录socialState
+ */
+ @NotBlank(message = "{social.state.not.blank}" , groups = {SocialGroup.class})
+ private String socialState;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java
index 8aac305..3de891a 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/LoginUser.java
@@ -1,21 +1,30 @@
package com.ruoyi.common.core.core.domain.model;
-import com.alibaba.fastjson2.annotation.JSONField;
-import com.ruoyi.common.core.core.domain.entity.SysUser;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import java.util.Collection;
+import com.ruoyi.common.core.core.domain.dto.RoleDTO;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
import java.util.Set;
+import java.io.Serial;
/**
* 登录用户身份权限
- *
- * @author ruoyi
+ *
+ * @author Lion Li
*/
-public class LoginUser implements UserDetails
+@Data
+@NoArgsConstructor
+public class LoginUser
{
+ @Serial
private static final long serialVersionUID = 1L;
+ /**
+ * 租户ID
+ */
+ private Long tenantId;
+
/**
* 用户ID
*/
@@ -26,11 +35,21 @@ public class LoginUser implements UserDetails
*/
private Long deptId;
+ /**
+ * 部门名
+ */
+ private String deptName;
+
/**
* 用户唯一标识
*/
private String token;
+ /**
+ * 用户类型
+ */
+ private String userType;
+
/**
* 登录时间
*/
@@ -62,205 +81,47 @@ public class LoginUser implements UserDetails
private String os;
/**
- * 权限列表
+ * 菜单权限
*/
- private Set permissions;
+ private Set menuPermission;
/**
- * 用户信息
+ * 角色权限
*/
- private SysUser user;
-
- public LoginUser()
- {
- }
-
- public LoginUser(SysUser user, Set permissions)
- {
- this.user = user;
- this.permissions = permissions;
- }
-
- public LoginUser(Long userId, Long deptId, SysUser user, Set permissions)
- {
- this.userId = userId;
- this.deptId = deptId;
- this.user = user;
- this.permissions = permissions;
- }
-
- public Long getUserId()
- {
- return userId;
- }
-
- public void setUserId(Long userId)
- {
- this.userId = userId;
- }
-
- public Long getDeptId()
- {
- return deptId;
- }
-
- public void setDeptId(Long deptId)
- {
- this.deptId = deptId;
- }
-
- public String getToken()
- {
- return token;
- }
-
- public void setToken(String token)
- {
- this.token = token;
- }
-
- @JSONField(serialize = false)
- @Override
- public String getPassword()
- {
- return user.getPassword();
- }
-
- @Override
- public String getUsername()
- {
- return user.getUserName();
- }
+ private Set rolePermission;
/**
- * 账户是否未过期,过期无法验证
+ * 用户名
*/
- @JSONField(serialize = false)
- @Override
- public boolean isAccountNonExpired()
- {
- return true;
- }
+ private String username;
/**
- * 指定用户是否解锁,锁定的用户无法进行身份验证
- *
- * @return
+ * 用户昵称
*/
- @JSONField(serialize = false)
- @Override
- public boolean isAccountNonLocked()
- {
- return true;
- }
+ private String nickname;
+
/**
- * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
- *
- * @return
+ * 角色对象
*/
- @JSONField(serialize = false)
- @Override
- public boolean isCredentialsNonExpired()
- {
- return true;
- }
+ private List roles;
/**
- * 是否可用 ,禁用的用户不能身份验证
- *
- * @return
+ * 数据权限 当前角色ID
*/
- @JSONField(serialize = false)
- @Override
- public boolean isEnabled()
- {
- return true;
+ private Long roleId;
+
+ /**
+ * 获取登录id
+ */
+ public String getLoginId() {
+ if (userType == null) {
+ throw new IllegalArgumentException("用户类型不能为空");
+ }
+ if (userId == null) {
+ throw new IllegalArgumentException("用户ID不能为空");
+ }
+ return userType + ":" + userId;
}
- public Long getLoginTime()
- {
- return loginTime;
}
-
- public void setLoginTime(Long loginTime)
- {
- this.loginTime = loginTime;
- }
-
- 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 Long getExpireTime()
- {
- return expireTime;
- }
-
- public void setExpireTime(Long expireTime)
- {
- this.expireTime = expireTime;
- }
-
- public Set getPermissions()
- {
- return permissions;
- }
-
- public void setPermissions(Set permissions)
- {
- this.permissions = permissions;
- }
-
- public SysUser getUser()
- {
- return user;
- }
-
- public void setUser(SysUser user)
- {
- this.user = user;
- }
-
- @Override
- public Collection extends GrantedAuthority> getAuthorities()
- {
- return null;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java
index 4438255..8135a93 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/domain/model/RegisterBody.java
@@ -1,11 +1,16 @@
package com.ruoyi.common.core.core.domain.model;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
/**
* 用户注册对象
- *
+ *
* @author ruoyi
*/
+@Data
+@EqualsAndHashCode(callSuper = true)
public class RegisterBody extends LoginBody
{
-
+ private String userType;
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java
index 464036a..c46c821 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/PageDomain.java
@@ -4,7 +4,7 @@ import com.ruoyi.common.core.utils.StringUtils;
/**
* 分页数据
- *
+ *
* @author ruoyi
*/
public class PageDomain
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java
index 6370751..4f4cd26 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableDataInfo.java
@@ -1,15 +1,19 @@
package com.ruoyi.common.core.core.page;
+import cn.hutool.http.HttpStatus;
+
+import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 表格分页数据对象
- *
+ *
* @author ruoyi
*/
public class TableDataInfo implements Serializable
{
+ @Serial
private static final long serialVersionUID = 1L;
/** 总记录数 */
@@ -33,7 +37,7 @@ public class TableDataInfo implements Serializable
/**
* 分页
- *
+ *
* @param list 列表数据
* @param total 总记录数
*/
@@ -43,6 +47,15 @@ public class TableDataInfo implements Serializable
this.total = total;
}
+ public static TableDataInfo build(List> list) {
+ TableDataInfo rspData = new TableDataInfo();
+ rspData.setCode(HttpStatus.HTTP_OK);
+ rspData.setMsg("查询成功");
+ rspData.setRows(list);
+ rspData.setTotal(list.size());
+ return rspData;
+ }
+
public long getTotal()
{
return total;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java
index 99ec195..b979878 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/page/TableSupport.java
@@ -5,7 +5,7 @@ import com.ruoyi.common.core.utils.ServletUtils;
/**
* 表格数据处理
- *
+ *
* @author ruoyi
*/
public class TableSupport
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java
deleted file mode 100644
index 248fd6b..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/redis/RedisCache.java
+++ /dev/null
@@ -1,268 +0,0 @@
-package com.ruoyi.common.core.core.redis;
-
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.TimeUnit;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.BoundSetOperations;
-import org.springframework.data.redis.core.HashOperations;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.ValueOperations;
-import org.springframework.stereotype.Component;
-
-/**
- * spring redis 工具类
- *
- * @author ruoyi
- **/
-@SuppressWarnings(value = { "unchecked", "rawtypes" })
-@Component
-public class RedisCache
-{
- @Autowired
- public RedisTemplate redisTemplate;
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- */
- public void setCacheObject(final String key, final T value)
- {
- redisTemplate.opsForValue().set(key, value);
- }
-
- /**
- * 缓存基本的对象,Integer、String、实体类等
- *
- * @param key 缓存的键值
- * @param value 缓存的值
- * @param timeout 时间
- * @param timeUnit 时间颗粒度
- */
- public void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
- {
- redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout)
- {
- return expire(key, timeout, TimeUnit.SECONDS);
- }
-
- /**
- * 设置有效时间
- *
- * @param key Redis键
- * @param timeout 超时时间
- * @param unit 时间单位
- * @return true=设置成功;false=设置失败
- */
- public boolean expire(final String key, final long timeout, final TimeUnit unit)
- {
- return redisTemplate.expire(key, timeout, unit);
- }
-
- /**
- * 获取有效时间
- *
- * @param key Redis键
- * @return 有效时间
- */
- public long getExpire(final String key)
- {
- return redisTemplate.getExpire(key);
- }
-
- /**
- * 判断 key是否存在
- *
- * @param key 键
- * @return true 存在 false不存在
- */
- public Boolean hasKey(String key)
- {
- return redisTemplate.hasKey(key);
- }
-
- /**
- * 获得缓存的基本对象。
- *
- * @param key 缓存键值
- * @return 缓存键值对应的数据
- */
- public T getCacheObject(final String key)
- {
- ValueOperations operation = redisTemplate.opsForValue();
- return operation.get(key);
- }
-
- /**
- * 删除单个对象
- *
- * @param key
- */
- public boolean deleteObject(final String key)
- {
- return redisTemplate.delete(key);
- }
-
- /**
- * 删除集合对象
- *
- * @param collection 多个对象
- * @return
- */
- public boolean deleteObject(final Collection collection)
- {
- return redisTemplate.delete(collection) > 0;
- }
-
- /**
- * 缓存List数据
- *
- * @param key 缓存的键值
- * @param dataList 待缓存的List数据
- * @return 缓存的对象
- */
- public long setCacheList(final String key, final List dataList)
- {
- Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
- return count == null ? 0 : count;
- }
-
- /**
- * 获得缓存的list对象
- *
- * @param key 缓存的键值
- * @return 缓存键值对应的数据
- */
- public List getCacheList(final String key)
- {
- return redisTemplate.opsForList().range(key, 0, -1);
- }
-
- /**
- * 缓存Set
- *
- * @param key 缓存键值
- * @param dataSet 缓存的数据
- * @return 缓存数据的对象
- */
- public BoundSetOperations setCacheSet(final String key, final Set dataSet)
- {
- BoundSetOperations setOperation = redisTemplate.boundSetOps(key);
- Iterator it = dataSet.iterator();
- while (it.hasNext())
- {
- setOperation.add(it.next());
- }
- return setOperation;
- }
-
- /**
- * 获得缓存的set
- *
- * @param key
- * @return
- */
- public Set getCacheSet(final String key)
- {
- return redisTemplate.opsForSet().members(key);
- }
-
- /**
- * 缓存Map
- *
- * @param key
- * @param dataMap
- */
- public void setCacheMap(final String key, final Map dataMap)
- {
- if (dataMap != null) {
- redisTemplate.opsForHash().putAll(key, dataMap);
- }
- }
-
- /**
- * 获得缓存的Map
- *
- * @param key
- * @return
- */
- public Map getCacheMap(final String key)
- {
- return redisTemplate.opsForHash().entries(key);
- }
-
- /**
- * 往Hash中存入数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @param value 值
- */
- public void setCacheMapValue(final String key, final String hKey, final T value)
- {
- redisTemplate.opsForHash().put(key, hKey, value);
- }
-
- /**
- * 获取Hash中的数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @return Hash中的对象
- */
- public T getCacheMapValue(final String key, final String hKey)
- {
- HashOperations opsForHash = redisTemplate.opsForHash();
- return opsForHash.get(key, hKey);
- }
-
- /**
- * 获取多个Hash中的数据
- *
- * @param key Redis键
- * @param hKeys Hash键集合
- * @return Hash对象集合
- */
- public List getMultiCacheMapValue(final String key, final Collection hKeys)
- {
- return redisTemplate.opsForHash().multiGet(key, hKeys);
- }
-
- /**
- * 删除Hash中的某条数据
- *
- * @param key Redis键
- * @param hKey Hash键
- * @return 是否成功
- */
- public boolean deleteCacheMapValue(final String key, final String hKey)
- {
- return redisTemplate.opsForHash().delete(key, hKey) > 0;
- }
-
- /**
- * 获得缓存的基本对象列表
- *
- * @param pattern 字符串前缀
- * @return 对象列表
- */
- public Collection keys(final String pattern)
- {
- return redisTemplate.keys(pattern);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java
index 8f46300..cd7d751 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/CharsetKit.java
@@ -6,7 +6,7 @@ import com.ruoyi.common.core.utils.StringUtils;
/**
* 字符集工具类
- *
+ *
* @author ruoyi
*/
public class CharsetKit
@@ -27,7 +27,7 @@ public class CharsetKit
/**
* 转换为Charset对象
- *
+ *
* @param charset 字符集,为空则返回默认字符集
* @return Charset
*/
@@ -38,7 +38,7 @@ public class CharsetKit
/**
* 转换字符串的字符集编码
- *
+ *
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
@@ -51,7 +51,7 @@ public class CharsetKit
/**
* 转换字符串的字符集编码
- *
+ *
* @param source 字符串
* @param srcCharset 源字符集,默认ISO-8859-1
* @param destCharset 目标字符集,默认UTF-8
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java
index 7d2d555..cc32d0e 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/core/text/StrFormatter.java
@@ -4,7 +4,7 @@ import com.ruoyi.common.core.utils.StringUtils;
/**
* 字符串格式化
- *
+ *
* @author ruoyi
*/
public class StrFormatter
@@ -22,7 +22,7 @@ public class StrFormatter
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
- *
+ *
* @param strPattern 字符串模板
* @param argArray 参数列表
* @return 结果
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java
deleted file mode 100644
index 2fdb2a7..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DataSourceType.java
+++ /dev/null
@@ -1,19 +0,0 @@
-package com.ruoyi.common.core.enums;
-
-/**
- * 数据源
- *
- * @author ruoyi
- */
-public enum DataSourceType
-{
- /**
- * 主库
- */
- MASTER,
-
- /**
- * 从库
- */
- SLAVE
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java
new file mode 100644
index 0000000..f449ded
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/DeviceType.java
@@ -0,0 +1,35 @@
+package com.ruoyi.common.core.enums;
+
+/**
+ * 设备类型
+ * 针对一套 用户体系
+ *
+ * @author Lion Li
+ */
+public enum DeviceType {
+ /**
+ * pc端
+ */
+ PC("pc"),
+
+ /**
+ * app端
+ */
+ APP("app"),
+
+ /**
+ * 小程序端
+ */
+ XCX("xcx"),
+
+ /**
+ * social第三方端
+ */
+ SOCIAL("social");
+
+ private final String device;
+
+ private DeviceType(String device) {
+ this.device = device;
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java
new file mode 100644
index 0000000..dbd6de1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/LoginType.java
@@ -0,0 +1,44 @@
+package com.ruoyi.common.core.enums;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 登录类型
+ *
+ * @author Lion Li
+ */
+@Getter
+@AllArgsConstructor
+public enum LoginType {
+
+ /**
+ * 密码登录
+ */
+ PASSWORD("user.password.retry.limit.exceed", "user.password.retry.limit.count"),
+
+ /**
+ * 短信登录
+ */
+ SMS("sms.code.retry.limit.exceed", "sms.code.retry.limit.count"),
+
+ /**
+ * 邮箱登录
+ */
+ EMAIL("email.code.retry.limit.exceed", "email.code.retry.limit.count"),
+
+ /**
+ * 小程序登录
+ */
+ XCX("", "");
+
+ /**
+ * 登录重试超出限制提示
+ */
+ final String retryLimitExceed;
+
+ /**
+ * 登录重试限制计数提示
+ */
+ final String retryLimitCount;
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java
new file mode 100644
index 0000000..79cd304
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/enums/UserType.java
@@ -0,0 +1,41 @@
+package com.ruoyi.common.core.enums;
+
+import com.ruoyi.common.core.utils.StringUtils;
+
+/**
+ * 设备类型
+ * 针对多套 用户体系
+ *
+ * @author Lion Li
+ */
+public enum UserType {
+
+ /**
+ * pc端
+ */
+ SYS_USER("sys_user"),
+
+ /**
+ * app端
+ */
+ APP_USER("app_user");
+
+ private final String userType;
+
+ UserType(String userType) {
+ this.userType = userType;
+ }
+
+ public String getUserType() {
+ return userType;
+ }
+
+ public static UserType getUserType(String str) {
+ for (UserType value : values()) {
+ if (StringUtils.contains(str, value.getUserType())) {
+ return value;
+ }
+ }
+ throw new RuntimeException("'UserType' not found By " + str);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java
index b55c7cd..cd59447 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/GlobalException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception;
+import java.io.Serial;
+
/**
* 全局异常
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception;
*/
public class GlobalException extends RuntimeException
{
+ @Serial
private static final long serialVersionUID = 1L;
/**
@@ -17,7 +20,6 @@ public class GlobalException extends RuntimeException
/**
* 错误明细,内部调试错误
*
- * 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java
index 4983866..53477b5 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/ServiceException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception;
+import java.io.Serial;
+
/**
* 业务异常
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception;
*/
public final class ServiceException extends RuntimeException
{
+ @Serial
private static final long serialVersionUID = 1L;
/**
@@ -22,7 +25,6 @@ public final class ServiceException extends RuntimeException
/**
* 错误明细,内部调试错误
*
- * 和 {@link CommonResult#getDetailMessage()} 一致的设计
*/
private String detailMessage;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java
index 18c7be8..2674028 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/UtilException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception;
+import java.io.Serial;
+
/**
* 工具类异常
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception;
*/
public class UtilException extends RuntimeException
{
+ @Serial
private static final long serialVersionUID = 8247610319171014183L;
public UtilException(Throwable e)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java
index ddd4ee5..404df1d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/base/BaseException.java
@@ -3,6 +3,8 @@ package com.ruoyi.common.core.exception.base;
import com.ruoyi.common.core.utils.MessageUtils;
import com.ruoyi.common.core.utils.StringUtils;
+import java.io.Serial;
+
/**
* 基础异常
*
@@ -10,6 +12,7 @@ import com.ruoyi.common.core.utils.StringUtils;
*/
public class BaseException extends RuntimeException
{
+ @Serial
private static final long serialVersionUID = 1L;
/**
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java
index 8989dcd..62b42c0 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileException.java
@@ -2,6 +2,8 @@ package com.ruoyi.common.core.exception.file;
import com.ruoyi.common.core.exception.base.BaseException;
+import java.io.Serial;
+
/**
* 文件信息异常类
*
@@ -9,6 +11,7 @@ import com.ruoyi.common.core.exception.base.BaseException;
*/
public class FileException extends BaseException
{
+ @Serial
private static final long serialVersionUID = 1L;
public FileException(String code, Object[] args)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java
index 9135a00..a71b5d9 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileNameLengthLimitExceededException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.file;
+import java.io.Serial;
+
/**
* 文件名称超长限制异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.file;
*/
public class FileNameLengthLimitExceededException extends FileException
{
+ @Serial
private static final long serialVersionUID = 1L;
public FileNameLengthLimitExceededException(int defaultFileNameLength)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java
index a5f8bc1..6180bf8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileSizeLimitExceededException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.file;
+import java.io.Serial;
+
/**
* 文件名大小限制异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.file;
*/
public class FileSizeLimitExceededException extends FileException
{
+ @Serial
private static final long serialVersionUID = 1L;
public FileSizeLimitExceededException(long defaultMaxSize)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java
index c0f57cb..78a781d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/FileUploadException.java
@@ -2,6 +2,7 @@ package com.ruoyi.common.core.exception.file;
import java.io.PrintStream;
import java.io.PrintWriter;
+import java.io.Serial;
/**
* 文件上传异常类
@@ -10,7 +11,7 @@ import java.io.PrintWriter;
*/
public class FileUploadException extends Exception
{
-
+ @Serial
private static final long serialVersionUID = 1L;
private final Throwable cause;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java
index 420520f..088e935 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/file/InvalidExtensionException.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.exception.file;
+import java.io.Serial;
import java.util.Arrays;
/**
@@ -9,6 +10,7 @@ import java.util.Arrays;
*/
public class InvalidExtensionException extends FileUploadException
{
+ @Serial
private static final long serialVersionUID = 1L;
private String[] allowedExtension;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java
index 6cc3e58..4464587 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/job/TaskException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.job;
+import java.io.Serial;
+
/**
* 计划策略异常
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.job;
*/
public class TaskException extends Exception
{
+ @Serial
private static final long serialVersionUID = 1L;
private Code code;
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java
index 1b09cdf..dbe688d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/BlackListException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 黑名单IP异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class BlackListException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public BlackListException()
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java
index f74c3dd..725d133 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 验证码错误异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class CaptchaException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public CaptchaException()
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java
index ec68864..2caae30 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/CaptchaExpireException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 验证码失效异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class CaptchaExpireException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public CaptchaExpireException()
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java
index 8ae8ea3..e4249b7 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserException.java
@@ -2,16 +2,19 @@ package com.ruoyi.common.core.exception.user;
import com.ruoyi.common.core.exception.base.BaseException;
+import java.io.Serial;
+
/**
* 用户信息异常类
- *
+ *
* @author ruoyi
*/
public class UserException extends BaseException
{
+ @Serial
private static final long serialVersionUID = 1L;
- public UserException(String code, Object[] args)
+ public UserException(String code, Object... args)
{
super("user", code, args, null);
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java
index 95a6854..76f0c1d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserNotExistsException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 用户不存在异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class UserNotExistsException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public UserNotExistsException()
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java
index 2e1a6b1..0c38d77 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordNotMatchException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 用户密码不正确或不符合规范异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class UserPasswordNotMatchException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public UserPasswordNotMatchException()
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java
index 336875b..4f0c98d 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/exception/user/UserPasswordRetryLimitExceedException.java
@@ -1,5 +1,7 @@
package com.ruoyi.common.core.exception.user;
+import java.io.Serial;
+
/**
* 用户错误最大次数异常类
*
@@ -7,6 +9,7 @@ package com.ruoyi.common.core.exception.user;
*/
public class UserPasswordRetryLimitExceedException extends UserException
{
+ @Serial
private static final long serialVersionUID = 1L;
public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java
new file mode 100644
index 0000000..014033e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/factory/YmlPropertySourceFactory.java
@@ -0,0 +1,31 @@
+package com.ruoyi.common.core.factory;
+
+import com.ruoyi.common.core.utils.StringUtils;
+import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
+import org.springframework.core.env.PropertiesPropertySource;
+import org.springframework.core.env.PropertySource;
+import org.springframework.core.io.support.DefaultPropertySourceFactory;
+import org.springframework.core.io.support.EncodedResource;
+
+import java.io.IOException;
+
+/**
+ * yml 配置源工厂
+ *
+ * @author Lion Li
+ */
+public class YmlPropertySourceFactory extends DefaultPropertySourceFactory {
+
+ @Override
+ public PropertySource> createPropertySource(String name, EncodedResource resource) throws IOException {
+ String sourceName = resource.getResource().getFilename();
+ if (StringUtils.isNotBlank(sourceName) && StringUtils.endsWithAny(sourceName, ".yml", ".yaml")) {
+ YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
+ factory.setResources(resource.getResource());
+ factory.afterPropertiesSet();
+ return new PropertiesPropertySource(sourceName, factory.getObject());
+ }
+ return super.createPropertySource(name, resource);
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java
deleted file mode 100644
index 2cebada..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/filter/PropertyPreExcludeFilter.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.ruoyi.common.core.filter;
-
-import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
-
-/**
- * 排除JSON敏感属性
- *
- * @author ruoyi
- */
-public class PropertyPreExcludeFilter extends SimplePropertyPreFilter
-{
- public PropertyPreExcludeFilter()
- {
- }
-
- public PropertyPreExcludeFilter addExcludes(String... filters)
- {
- for (int i = 0; i < filters.length; i++)
- {
- this.getExcludes().add(filters[i]);
- }
- return this;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java
new file mode 100644
index 0000000..0a6df41
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/manager/ShutdownManager.java
@@ -0,0 +1,41 @@
+package com.ruoyi.common.core.manager;
+
+import com.ruoyi.common.core.utils.Threads;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.stereotype.Component;
+import jakarta.annotation.PreDestroy;
+import java.util.concurrent.ScheduledExecutorService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 确保应用退出时能关闭后台线程
+ *
+ * @author ruoyi
+ */
+@Component
+public class ShutdownManager
+{
+ private static final Logger logger = LoggerFactory.getLogger("ShutdownManager");
+ @Resource
+ @Qualifier("scheduledExecutorService")
+ private ScheduledExecutorService scheduledExecutorService;
+
+ @PreDestroy
+ public void destroy() {
+ shutdownAsyncManager();
+ }
+
+ /**
+ * 停止异步执行任务
+ */
+ private void shutdownAsyncManager() {
+ try {
+ logger.info("====关闭后台任务任务线程池====");
+ Threads.shutdownAndAwaitTermination(scheduledExecutorService);
+ } catch (Exception e) {
+ logger.error(e.getMessage(), e);
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java
new file mode 100644
index 0000000..c6badf6
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/ConfigService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.core.service;
+
+/**
+ * 通用 参数配置服务
+ *
+ * @author Lion Li
+ */
+public interface ConfigService {
+
+ /**
+ * 根据参数 key 获取参数值
+ *
+ * @param configKey 参数 key
+ * @return 参数值
+ */
+ String getConfigValue(String configKey);
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java
new file mode 100644
index 0000000..c27f461
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DeptService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.core.service;
+
+/**
+ * 通用 部门服务
+ *
+ * @author Lion Li
+ */
+public interface DeptService {
+
+ /**
+ * 通过部门ID查询部门名称
+ *
+ * @param deptIds 部门ID串逗号分隔
+ * @return 部门名称串逗号分隔
+ */
+ String selectDeptNameByIds(String deptIds);
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java
new file mode 100644
index 0000000..22b8439
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/DictService.java
@@ -0,0 +1,67 @@
+package com.ruoyi.common.core.service;
+
+import java.util.Map;
+
+/**
+ * 通用 字典服务
+ *
+ * @author Lion Li
+ */
+public interface DictService {
+
+ /**
+ * 分隔符
+ */
+ String SEPARATOR = ",";
+
+ /**
+ * 根据字典类型和字典值获取字典标签
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典值
+ * @return 字典标签
+ */
+ default String getDictLabel(String dictType, String dictValue) {
+ return getDictLabel(dictType, dictValue, SEPARATOR);
+ }
+
+ /**
+ * 根据字典类型和字典标签获取字典值
+ *
+ * @param dictType 字典类型
+ * @param dictLabel 字典标签
+ * @return 字典值
+ */
+ default String getDictValue(String dictType, String dictLabel) {
+ return getDictValue(dictType, dictLabel, SEPARATOR);
+ }
+
+ /**
+ * 根据字典类型和字典值获取字典标签
+ *
+ * @param dictType 字典类型
+ * @param dictValue 字典值
+ * @param separator 分隔符
+ * @return 字典标签
+ */
+ String getDictLabel(String dictType, String dictValue, String separator);
+
+ /**
+ * 根据字典类型和字典标签获取字典值
+ *
+ * @param dictType 字典类型
+ * @param dictLabel 字典标签
+ * @param separator 分隔符
+ * @return 字典值
+ */
+ String getDictValue(String dictType, String dictLabel, String separator);
+
+ /**
+ * 获取字典下所有的字典值与标签
+ *
+ * @param dictType 字典类型
+ * @return dictValue为key,dictLabel为值组成的Map
+ */
+ Map getAllDictByDictType(String dictType);
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java
new file mode 100644
index 0000000..d2206c8
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/service/UserService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.core.service;
+
+/**
+ * 通用 用户服务
+ *
+ * @author Lion Li
+ */
+public interface UserService {
+
+ /**
+ * 通过用户ID查询用户账户
+ *
+ * @param userId 用户ID
+ * @return 用户账户
+ */
+ String selectUserNameById(Long userId);
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java
deleted file mode 100644
index 89a4b83..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/DictUtils.java
+++ /dev/null
@@ -1,186 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import java.util.Collection;
-import java.util.List;
-import com.alibaba.fastjson2.JSONArray;
-import com.ruoyi.common.core.constant.CacheConstants;
-import com.ruoyi.common.core.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.core.redis.RedisCache;
-import com.ruoyi.common.core.utils.spring.SpringUtils;
-
-/**
- * 字典工具类
- *
- * @author ruoyi
- */
-public class DictUtils
-{
- /**
- * 分隔符
- */
- public static final String SEPARATOR = ",";
-
- /**
- * 设置字典缓存
- *
- * @param key 参数键
- * @param dictDatas 字典数据列表
- */
- public static void setDictCache(String key, List dictDatas)
- {
- SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
- }
-
- /**
- * 获取字典缓存
- *
- * @param key 参数键
- * @return dictDatas 字典数据列表
- */
- public static List getDictCache(String key)
- {
- JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
- if (StringUtils.isNotNull(arrayCache))
- {
- return arrayCache.toList(SysDictData.class);
- }
- return null;
- }
-
- /**
- * 根据字典类型和字典值获取字典标签
- *
- * @param dictType 字典类型
- * @param dictValue 字典值
- * @return 字典标签
- */
- public static String getDictLabel(String dictType, String dictValue)
- {
- return getDictLabel(dictType, dictValue, SEPARATOR);
- }
-
- /**
- * 根据字典类型和字典标签获取字典值
- *
- * @param dictType 字典类型
- * @param dictLabel 字典标签
- * @return 字典值
- */
- public static String getDictValue(String dictType, String dictLabel)
- {
- return getDictValue(dictType, dictLabel, SEPARATOR);
- }
-
- /**
- * 根据字典类型和字典值获取字典标签
- *
- * @param dictType 字典类型
- * @param dictValue 字典值
- * @param separator 分隔符
- * @return 字典标签
- */
- public static String getDictLabel(String dictType, String dictValue, String separator)
- {
- StringBuilder propertyString = new StringBuilder();
- List datas = getDictCache(dictType);
-
- if (StringUtils.isNotNull(datas))
- {
- if (StringUtils.containsAny(separator, dictValue))
- {
- for (SysDictData dict : datas)
- {
- for (String value : dictValue.split(separator))
- {
- if (value.equals(dict.getDictValue()))
- {
- propertyString.append(dict.getDictLabel()).append(separator);
- break;
- }
- }
- }
- }
- else
- {
- for (SysDictData dict : datas)
- {
- if (dictValue.equals(dict.getDictValue()))
- {
- return dict.getDictLabel();
- }
- }
- }
- }
- return StringUtils.stripEnd(propertyString.toString(), separator);
- }
-
- /**
- * 根据字典类型和字典标签获取字典值
- *
- * @param dictType 字典类型
- * @param dictLabel 字典标签
- * @param separator 分隔符
- * @return 字典值
- */
- public static String getDictValue(String dictType, String dictLabel, String separator)
- {
- StringBuilder propertyString = new StringBuilder();
- List datas = getDictCache(dictType);
-
- if (StringUtils.containsAny(separator, dictLabel) && StringUtils.isNotEmpty(datas))
- {
- for (SysDictData dict : datas)
- {
- for (String label : dictLabel.split(separator))
- {
- if (label.equals(dict.getDictLabel()))
- {
- propertyString.append(dict.getDictValue()).append(separator);
- break;
- }
- }
- }
- }
- else
- {
- for (SysDictData dict : datas)
- {
- if (dictLabel.equals(dict.getDictLabel()))
- {
- return dict.getDictValue();
- }
- }
- }
- return StringUtils.stripEnd(propertyString.toString(), separator);
- }
-
- /**
- * 删除指定字典缓存
- *
- * @param key 字典键
- */
- public static void removeDictCache(String key)
- {
- SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
- }
-
- /**
- * 清空字典缓存
- */
- public static void clearDictCache()
- {
- Collection keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
- SpringUtils.getBean(RedisCache.class).deleteObject(keys);
- }
-
- /**
- * 设置cache key
- *
- * @param configKey 参数键
- * @return 缓存键key
- */
- public static String getCacheKey(String configKey)
- {
- return CacheConstants.SYS_DICT_KEY + configKey;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java
deleted file mode 100644
index f170231..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/LogUtils.java
+++ /dev/null
@@ -1,18 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-/**
- * 处理并记录日志文件
- *
- * @author ruoyi
- */
-public class LogUtils
-{
- public static String getBlock(Object msg)
- {
- if (msg == null)
- {
- msg = "";
- }
- return "[" + msg.toString() + "]";
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java
new file mode 100644
index 0000000..3f6b633
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MapstructUtils.java
@@ -0,0 +1,93 @@
+package com.ruoyi.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.ObjectUtil;
+import io.github.linpeilie.Converter;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Mapstruct 工具类
+ * 参考文档:mapstruct-plus
+ *
+ *
+ * @author Michelle.Chung
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class MapstructUtils {
+
+ private final static Converter CONVERTER = SpringUtils.getBean(Converter.class);
+
+ /**
+ * 将 T 类型对象,转换为 desc 类型的对象并返回
+ *
+ * @param source 数据来源实体
+ * @param desc 描述对象 转换后的对象
+ * @return desc
+ */
+ public static V convert(T source, Class desc) {
+ if (ObjectUtil.isNull(source)) {
+ return null;
+ }
+ if (ObjectUtil.isNull(desc)) {
+ return null;
+ }
+ return CONVERTER.convert(source, desc);
+ }
+
+ /**
+ * 将 T 类型对象,按照配置的映射字段规则,给 desc 类型的对象赋值并返回 desc 对象
+ *
+ * @param source 数据来源实体
+ * @param desc 转换后的对象
+ * @return desc
+ */
+ public static V convert(T source, V desc) {
+ if (ObjectUtil.isNull(source)) {
+ return null;
+ }
+ if (ObjectUtil.isNull(desc)) {
+ return null;
+ }
+ return CONVERTER.convert(source, desc);
+ }
+
+ /**
+ * 将 T 类型的集合,转换为 desc 类型的集合并返回
+ *
+ * @param sourceList 数据来源实体列表
+ * @param desc 描述对象 转换后的对象
+ * @return desc
+ */
+ public static List convert(List sourceList, Class desc) {
+ if (ObjectUtil.isNull(sourceList)) {
+ return null;
+ }
+ if (CollUtil.isEmpty(sourceList)) {
+ return CollUtil.newArrayList();
+ }
+ return CONVERTER.convert(sourceList, desc);
+ }
+
+ /**
+ * 将 Map 转换为 beanClass 类型的集合并返回
+ *
+ * @param map 数据来源
+ * @param beanClass bean类
+ * @return bean对象
+ */
+ public static T convert(Map map, Class beanClass) {
+ if (MapUtil.isEmpty(map)) {
+ return null;
+ }
+ if (ObjectUtil.isNull(beanClass)) {
+ return null;
+ }
+ return CONVERTER.convert(map, beanClass);
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java
index 92bbd91..c346188 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/MessageUtils.java
@@ -2,11 +2,10 @@ package com.ruoyi.common.core.utils;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
-import com.ruoyi.common.core.utils.spring.SpringUtils;
/**
* 获取i18n资源文件
- *
+ *
* @author ruoyi
*/
public class MessageUtils
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
index a4c1735..79838a5 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/PageUtils.java
@@ -7,7 +7,7 @@ import com.ruoyi.common.core.utils.sql.SqlUtil;
/**
* 分页工具类
- *
+ *
* @author ruoyi
*/
public class PageUtils extends PageHelper
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java
deleted file mode 100644
index b51fdfc..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SecurityUtils.java
+++ /dev/null
@@ -1,120 +0,0 @@
-package com.ruoyi.common.core.utils;
-
-import com.ruoyi.common.core.core.domain.model.LoginUser;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import com.ruoyi.common.core.constant.HttpStatus;
-import com.ruoyi.common.core.exception.ServiceException;
-
-/**
- * 安全服务工具类
- *
- * @author ruoyi
- */
-public class SecurityUtils
-{
- /**
- * 用户ID
- **/
- public static Long getUserId()
- {
- try
- {
- return getLoginUser().getUserId();
- }
- catch (Exception e)
- {
- throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
- }
- }
-
- /**
- * 获取部门ID
- **/
- public static Long getDeptId()
- {
- try
- {
- return getLoginUser().getDeptId();
- }
- catch (Exception e)
- {
- throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
- }
- }
-
- /**
- * 获取用户账户
- **/
- public static String getUsername()
- {
- try
- {
- return getLoginUser().getUsername();
- }
- catch (Exception e)
- {
- throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
- }
- }
-
- /**
- * 获取用户
- **/
- public static LoginUser getLoginUser()
- {
- try
- {
- return (LoginUser) getAuthentication().getPrincipal();
- }
- catch (Exception e)
- {
- throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
- }
- }
-
- /**
- * 获取Authentication
- */
- public static Authentication getAuthentication()
- {
- return SecurityContextHolder.getContext().getAuthentication();
- }
-
- /**
- * 生成BCryptPasswordEncoder密码
- *
- * @param password 密码
- * @return 加密字符串
- */
- public static String encryptPassword(String password)
- {
- BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
- return passwordEncoder.encode(password);
- }
-
- /**
- * 判断密码是否相同
- *
- * @param rawPassword 真实密码
- * @param encodedPassword 加密后字符
- * @return 结果
- */
- public static boolean matchesPassword(String rawPassword, String encodedPassword)
- {
- BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
- return passwordEncoder.matches(rawPassword, encodedPassword);
- }
-
- /**
- * 是否为管理员
- *
- * @param userId 用户ID
- * @return 结果
- */
- public static boolean isAdmin(Long userId)
- {
- return userId != null && 1L == userId;
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
index 41f6432..2c5a47b 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ServletUtils.java
@@ -17,13 +17,14 @@ import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import com.ruoyi.common.core.constant.Constants;
+import cn.hutool.extra.servlet.JakartaServletUtil;
/**
* 客户端工具类
- *
+ *
* @author ruoyi
*/
-public class ServletUtils
+public class ServletUtils extends JakartaServletUtil
{
/**
* 获取String参数
@@ -133,7 +134,7 @@ public class ServletUtils
/**
* 将字符串渲染到客户端
- *
+ *
* @param response 渲染对象
* @param string 待渲染的字符串
*/
@@ -154,7 +155,7 @@ public class ServletUtils
/**
* 是否是Ajax异步请求
- *
+ *
* @param request
*/
public static boolean isAjaxRequest(HttpServletRequest request)
@@ -181,9 +182,13 @@ public class ServletUtils
return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
}
+ public static String getClientIP() {
+ return getClientIP(getRequest());
+ }
+
/**
* 内容编码
- *
+ *
* @param str 内容
* @return 编码后的内容
*/
@@ -201,7 +206,7 @@ public class ServletUtils
/**
* 内容解码
- *
+ *
* @param str 内容
* @return 解码后的内容
*/
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java
new file mode 100644
index 0000000..30624c3
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/SpringUtils.java
@@ -0,0 +1,101 @@
+package com.ruoyi.common.core.utils;
+
+import cn.hutool.extra.spring.SpringUtil;
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring工具类,方便在非spring管理环境中获取bean
+ *
+ * @author ruoyi
+ */
+@Component
+public final class SpringUtils extends SpringUtil
+{
+ /**
+ * 获取spring上下文
+ */
+ public static ApplicationContext context() {
+ return getApplicationContext();
+ }
+
+ /**
+ * 获取aop代理对象
+ */
+ @SuppressWarnings("unchecked")
+ public static T getAopProxy(T invoker) {
+ return (T) AopContext.currentProxy();
+ }
+
+ /**
+ * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
+ *
+ * @param name
+ * @return boolean
+ */
+ public static boolean containsBean(String name)
+ {
+ return getBeanFactory().containsBean(name);
+ }
+
+ /**
+ * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
+ *
+ * @param name
+ * @return boolean
+ * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+ *
+ */
+ public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
+ {
+ return getBeanFactory().isSingleton(name);
+ }
+
+ /**
+ * @param name
+ * @return Class 注册对象的类型
+ * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+ *
+ */
+ public static Class> getType(String name) throws NoSuchBeanDefinitionException
+ {
+ return getBeanFactory().getType(name);
+ }
+
+ /**
+ * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+ *
+ * @param name
+ * @return
+ * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+ *
+ */
+ public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+ {
+ return getBeanFactory().getAliases(name);
+ }
+
+ /**
+ * 获取当前的环境配置,无配置返回null
+ *
+ * @return 当前的环境配置
+ */
+ public static String[] getActiveProfiles()
+ {
+ return context().getEnvironment().getActiveProfiles();
+ }
+
+ /**
+ * 获取当前的环境配置,当有多个环境配置时,只获取第一个
+ *
+ * @return 当前的环境配置
+ */
+ public static String getActiveProfile()
+ {
+ final String[] activeProfiles = getActiveProfiles();
+ return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java
new file mode 100644
index 0000000..068d8d5
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StreamUtils.java
@@ -0,0 +1,254 @@
+package com.ruoyi.common.core.utils;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.map.MapUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import java.util.*;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+/**
+ * stream 流工具类
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class StreamUtils {
+
+ /**
+ * 将collection过滤
+ *
+ * @param collection 需要转化的集合
+ * @param function 过滤方法
+ * @return 过滤后的list
+ */
+ public static List filter(Collection collection, Predicate function) {
+ if (CollUtil.isEmpty(collection)) {
+ return CollUtil.newArrayList();
+ }
+ // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
+ return collection.stream().filter(function).collect(Collectors.toList());
+ }
+
+ /**
+ * 将collection拼接
+ *
+ * @param collection 需要转化的集合
+ * @param function 拼接方法
+ * @return 拼接后的list
+ */
+ public static String join(Collection collection, Function function) {
+ return join(collection, function, StringUtils.SEPARATOR);
+ }
+
+ /**
+ * 将collection拼接
+ *
+ * @param collection 需要转化的集合
+ * @param function 拼接方法
+ * @param delimiter 拼接符
+ * @return 拼接后的list
+ */
+ public static String join(Collection collection, Function function, CharSequence delimiter) {
+ if (CollUtil.isEmpty(collection)) {
+ return StringUtils.EMPTY;
+ }
+ return collection.stream().map(function).filter(Objects::nonNull).collect(Collectors.joining(delimiter));
+ }
+
+ /**
+ * 将collection排序
+ *
+ * @param collection 需要转化的集合
+ * @param comparing 排序方法
+ * @return 排序后的list
+ */
+ public static List sorted(Collection collection, Comparator comparing) {
+ if (CollUtil.isEmpty(collection)) {
+ return CollUtil.newArrayList();
+ }
+ // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
+ return collection.stream().filter(Objects::nonNull).sorted(comparing).collect(Collectors.toList());
+ }
+
+ /**
+ * 将collection转化为类型不变的map
+ * {@code Collection ----> Map}
+ *
+ * @param collection 需要转化的集合
+ * @param key V类型转化为K类型的lambda方法
+ * @param collection中的泛型
+ * @param map中的key类型
+ * @return 转化后的map
+ */
+ public static Map toIdentityMap(Collection collection, Function key) {
+ if (CollUtil.isEmpty(collection)) {
+ return MapUtil.newHashMap();
+ }
+ return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, Function.identity(), (l, r) -> l));
+ }
+
+ /**
+ * 将Collection转化为map(value类型与collection的泛型不同)
+ * {@code Collection -----> Map }
+ *
+ * @param collection 需要转化的集合
+ * @param key E类型转化为K类型的lambda方法
+ * @param value E类型转化为V类型的lambda方法
+ * @param collection中的泛型
+ * @param map中的key类型
+ * @param map中的value类型
+ * @return 转化后的map
+ */
+ public static Map toMap(Collection collection, Function key, Function value) {
+ if (CollUtil.isEmpty(collection)) {
+ return MapUtil.newHashMap();
+ }
+ return collection.stream().filter(Objects::nonNull).collect(Collectors.toMap(key, value, (l, r) -> l));
+ }
+
+ /**
+ * 将collection按照规则(比如有相同的班级id)分类成map
+ * {@code Collection -------> Map> }
+ *
+ * @param collection 需要分类的集合
+ * @param key 分类的规则
+ * @param collection中的泛型
+ * @param map中的key类型
+ * @return 分类后的map
+ */
+ public static Map> groupByKey(Collection collection, Function key) {
+ if (CollUtil.isEmpty(collection)) {
+ return MapUtil.newHashMap();
+ }
+ return collection
+ .stream().filter(Objects::nonNull)
+ .collect(Collectors.groupingBy(key, LinkedHashMap::new, Collectors.toList()));
+ }
+
+ /**
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map>> }
+ *
+ * @param collection 需要分类的集合
+ * @param key1 第一个分类的规则
+ * @param key2 第二个分类的规则
+ * @param 集合元素类型
+ * @param 第一个map中的key类型
+ * @param 第二个map中的key类型
+ * @return 分类后的map
+ */
+ public static Map>> groupBy2Key(Collection collection, Function key1, Function key2) {
+ if (CollUtil.isEmpty(collection)) {
+ return MapUtil.newHashMap();
+ }
+ return collection
+ .stream().filter(Objects::nonNull)
+ .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.groupingBy(key2, LinkedHashMap::new, Collectors.toList())));
+ }
+
+ /**
+ * 将collection按照两个规则(比如有相同的年级id,班级id)分类成双层map
+ * {@code Collection ---> Map> }
+ *
+ * @param collection 需要分类的集合
+ * @param key1 第一个分类的规则
+ * @param key2 第二个分类的规则
+ * @param 第一个map中的key类型
+ * @param 第二个map中的key类型
+ * @param collection中的泛型
+ * @return 分类后的map
+ */
+ public static Map> group2Map(Collection collection, Function key1, Function key2) {
+ if (CollUtil.isEmpty(collection) || key1 == null || key2 == null) {
+ return MapUtil.newHashMap();
+ }
+ return collection
+ .stream().filter(Objects::nonNull)
+ .collect(Collectors.groupingBy(key1, LinkedHashMap::new, Collectors.toMap(key2, Function.identity(), (l, r) -> l)));
+ }
+
+ /**
+ * 将collection转化为List集合,但是两者的泛型不同
+ * {@code Collection ------> List }
+ *
+ * @param collection 需要转化的集合
+ * @param function collection中的泛型转化为list泛型的lambda表达式
+ * @param collection中的泛型
+ * @param List中的泛型
+ * @return 转化后的list
+ */
+ public static List toList(Collection collection, Function function) {
+ if (CollUtil.isEmpty(collection)) {
+ return CollUtil.newArrayList();
+ }
+ return collection
+ .stream()
+ .map(function)
+ .filter(Objects::nonNull)
+ // 注意此处不要使用 .toList() 新语法 因为返回的是不可变List 会导致序列化问题
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * 将collection转化为Set集合,但是两者的泛型不同
+ * {@code Collection ------> Set }
+ *
+ * @param collection 需要转化的集合
+ * @param function collection中的泛型转化为set泛型的lambda表达式
+ * @param collection中的泛型
+ * @param Set中的泛型
+ * @return 转化后的Set
+ */
+ public static Set toSet(Collection collection, Function function) {
+ if (CollUtil.isEmpty(collection) || function == null) {
+ return CollUtil.newHashSet();
+ }
+ return collection
+ .stream()
+ .map(function)
+ .filter(Objects::nonNull)
+ .collect(Collectors.toSet());
+ }
+
+
+ /**
+ * 合并两个相同key类型的map
+ *
+ * @param map1 第一个需要合并的 map
+ * @param map2 第二个需要合并的 map
+ * @param merge 合并的lambda,将key value1 value2合并成最终的类型,注意value可能为空的情况
+ * @param map中的key类型
+ * @param 第一个 map的value类型
+ * @param 第二个 map的value类型
+ * @param 最终map的value类型
+ * @return 合并后的map
+ */
+ public static Map merge(Map map1, Map map2, BiFunction merge) {
+ if (MapUtil.isEmpty(map1) && MapUtil.isEmpty(map2)) {
+ return MapUtil.newHashMap();
+ } else if (MapUtil.isEmpty(map1)) {
+ map1 = MapUtil.newHashMap();
+ } else if (MapUtil.isEmpty(map2)) {
+ map2 = MapUtil.newHashMap();
+ }
+ Set key = new HashSet<>();
+ key.addAll(map1.keySet());
+ key.addAll(map2.keySet());
+ Map map = new HashMap<>();
+ for (K t : key) {
+ X x = map1.get(t);
+ Y y = map2.get(t);
+ V z = merge.apply(x, y);
+ if (z != null) {
+ map.put(t, z);
+ }
+ }
+ return map;
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
index 4a6a224..a4398e8 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/StringUtils.java
@@ -1,32 +1,37 @@
package com.ruoyi.common.core.utils;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Validator;
+import cn.hutool.core.util.StrUtil;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.core.core.text.StrFormatter;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
import org.springframework.util.AntPathMatcher;
import com.ruoyi.common.core.constant.Constants;
/**
* 字符串工具类
- *
+ *
* @author ruoyi
*/
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class StringUtils extends org.apache.commons.lang3.StringUtils
{
+ public static final String SEPARATOR = ",";
+
/** 空字符串 */
private static final String NULLSTR = "";
- /** 下划线 */
- private static final char SEPARATOR = '_';
-
/**
* 获取参数不为空值
- *
+ *
* @param value defaultValue 要判断的value
* @return value 返回值
*/
@@ -37,7 +42,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个Collection是否为空, 包含List,Set,Queue
- *
+ *
* @param coll 要判断的Collection
* @return true:为空 false:非空
*/
@@ -48,7 +53,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个Collection是否非空,包含List,Set,Queue
- *
+ *
* @param coll 要判断的Collection
* @return true:非空 false:空
*/
@@ -59,7 +64,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个对象数组是否为空
- *
+ *
* @param objects 要判断的对象数组
** @return true:为空 false:非空
*/
@@ -70,7 +75,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个对象数组是否非空
- *
+ *
* @param objects 要判断的对象数组
* @return true:非空 false:空
*/
@@ -81,7 +86,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个Map是否为空
- *
+ *
* @param map 要判断的Map
* @return true:为空 false:非空
*/
@@ -92,7 +97,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个Map是否为空
- *
+ *
* @param map 要判断的Map
* @return true:非空 false:空
*/
@@ -103,7 +108,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个字符串是否为空串
- *
+ *
* @param str String
* @return true:为空 false:非空
*/
@@ -114,7 +119,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个字符串是否为非空串
- *
+ *
* @param str String
* @return true:非空串 false:空串
*/
@@ -125,7 +130,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个对象是否为空
- *
+ *
* @param object Object
* @return true:为空 false:非空
*/
@@ -136,7 +141,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个对象是否非空
- *
+ *
* @param object Object
* @return true:非空 false:空
*/
@@ -147,7 +152,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* * 判断一个对象是否是数组类型(Java基本型别的数组)
- *
+ *
* @param object 对象
* @return true:是数组 false:不是数组
*/
@@ -166,7 +171,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 截取字符串
- *
+ *
* @param str 字符串
* @param start 开始
* @return 结果
@@ -197,7 +202,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 截取字符串
- *
+ *
* @param str 字符串
* @param start 开始
* @param end 结束
@@ -249,7 +254,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
* 通常使用:format("this is {} for {}", "a", "b") -> this is a for b
* 转义{}: format("this is \\{} for {}", "a", "b") -> this is \{} for a
* 转义\: format("this is \\\\{} for {}", "a", "b") -> this is \a for b
- *
+ *
* @param template 文本模板,被替换的部分用 {} 表示
* @param params 参数值
* @return 格式化后的文本
@@ -265,7 +270,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 是否为http(s)://开头
- *
+ *
* @param link 链接
* @return 结果
*/
@@ -276,7 +281,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 字符串转set
- *
+ *
* @param str 字符串
* @param sep 分隔符
* @return set集合
@@ -288,7 +293,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 字符串转list
- *
+ *
* @param str 字符串
* @param sep 分隔符
* @param filterBlank 过滤纯空白
@@ -425,7 +430,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 是否包含字符串
- *
+ *
* @param str 验证字符串
* @param strs 字符串组
* @return 包含返回true
@@ -447,81 +452,24 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_WORLD->HelloWorld
- *
+ *
* @param name 转换前的下划线大写方式命名的字符串
* @return 转换后的驼峰式命名的字符串
*/
- public static String convertToCamelCase(String name)
- {
- StringBuilder result = new StringBuilder();
- // 快速检查
- if (name == null || name.isEmpty())
- {
- // 没必要转换
- return "";
- }
- else if (!name.contains("_"))
- {
- // 不含下划线,仅将首字母大写
- return name.substring(0, 1).toUpperCase() + name.substring(1);
- }
- // 用下划线将原始字符串分割
- String[] camels = name.split("_");
- for (String camel : camels)
- {
- // 跳过原始字符串中开头、结尾的下换线或双重下划线
- if (camel.isEmpty())
- {
- continue;
- }
- // 首字母大写
- result.append(camel.substring(0, 1).toUpperCase());
- result.append(camel.substring(1).toLowerCase());
- }
- return result.toString();
+ public static String convertToCamelCase(String name) {
+ return StrUtil.upperFirst(StrUtil.toCamelCase(name));
}
/**
- * 驼峰式命名法
- * 例如:user_name->userName
+ * 驼峰式命名法 例如:user_name->userName
*/
- public static String toCamelCase(String s)
- {
- if (s == null)
- {
- return null;
- }
- if (s.indexOf(SEPARATOR) == -1)
- {
- return s;
- }
- s = s.toLowerCase();
- StringBuilder sb = new StringBuilder(s.length());
- boolean upperCase = false;
- for (int i = 0; i < s.length(); i++)
- {
- char c = s.charAt(i);
-
- if (c == SEPARATOR)
- {
- upperCase = true;
- }
- else if (upperCase)
- {
- sb.append(Character.toUpperCase(c));
- upperCase = false;
- }
- else
- {
- sb.append(c);
- }
- }
- return sb.toString();
+ public static String toCamelCase(String s) {
+ return StrUtil.toCamelCase(s);
}
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
- *
+ *
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
@@ -543,11 +491,11 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
/**
- * 判断url是否与规则配置:
- * ? 表示单个字符;
- * * 表示一层路径内的任意字符串,不可跨层级;
+ * 判断url是否与规则配置:
+ * ? 表示单个字符;
+ * * 表示一层路径内的任意字符串,不可跨层级;
* ** 表示任意层路径;
- *
+ *
* @param pattern 匹配规则
* @param url 需要匹配的url
* @return
@@ -566,7 +514,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
- *
+ *
* @param num 数字对象
* @param size 字符串指定长度
* @return 返回数字的字符串格式,该字符串为指定长度。
@@ -578,7 +526,7 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
/**
* 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
- *
+ *
* @param s 原始字符串
* @param size 字符串指定长度
* @param c 用于补齐的字符
@@ -612,4 +560,55 @@ public class StringUtils extends org.apache.commons.lang3.StringUtils
}
return sb.toString();
}
-}
\ No newline at end of file
+
+ /**
+ * 切分字符串(分隔符默认逗号)
+ *
+ * @param str 被切分的字符串
+ * @return 分割后的数据列表
+ */
+ public static List splitList(String str) {
+ return splitTo(str, Convert::toStr);
+ }
+
+ /**
+ * 切分字符串
+ *
+ * @param str 被切分的字符串
+ * @param separator 分隔符
+ * @return 分割后的数据列表
+ */
+ public static List splitList(String str, String separator) {
+ return splitTo(str, separator, Convert::toStr);
+ }
+
+ /**
+ * 切分字符串自定义转换(分隔符默认逗号)
+ *
+ * @param str 被切分的字符串
+ * @param mapper 自定义转换
+ * @return 分割后的数据列表
+ */
+ public static List splitTo(String str, Function super Object, T> mapper) {
+ return splitTo(str, SEPARATOR, mapper);
+ }
+
+ /**
+ * 切分字符串自定义转换
+ *
+ * @param str 被切分的字符串
+ * @param separator 分隔符
+ * @param mapper 自定义转换
+ * @return 分割后的数据列表
+ */
+ public static List splitTo(String str, String separator, Function super Object, T> mapper) {
+ if (isBlank(str)) {
+ return new ArrayList<>(0);
+ }
+ return StrUtil.split(str, separator)
+ .stream()
+ .filter(Objects::nonNull)
+ .map(mapper)
+ .collect(Collectors.toList());
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java
index 088ae0b..8812a08 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/Threads.java
@@ -5,6 +5,9 @@ import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,10 +16,10 @@ import org.slf4j.LoggerFactory;
*
* @author ruoyi
*/
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Threads
{
- private static final Logger logger = LoggerFactory.getLogger(Threads.class);
-
+ private static final Logger log = LoggerFactory.getLogger(Threads.class);
/**
* sleep等待,单位为毫秒
*/
@@ -51,7 +54,7 @@ public class Threads
pool.shutdownNow();
if (!pool.awaitTermination(120, TimeUnit.SECONDS))
{
- logger.info("Pool did not terminate");
+ log.info("Pool did not terminate");
}
}
}
@@ -93,7 +96,7 @@ public class Threads
}
if (t != null)
{
- logger.error(t.getMessage(), t);
+ log.error(t.getMessage(), t);
}
}
}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java
new file mode 100644
index 0000000..7b331f0
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/ValidatorUtils.java
@@ -0,0 +1,28 @@
+package com.ruoyi.common.core.utils;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.validation.Validator;
+import java.util.Set;
+
+/**
+ * Validator 校验框架工具
+ *
+ * @author Lion Li
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class ValidatorUtils {
+
+ private static final Validator VALID = SpringUtils.getBean(Validator.class);
+
+ public static void validate(T object, Class>... groups) {
+ Set> validate = VALID.validate(object, groups);
+ if (!validate.isEmpty()) {
+ throw new ConstraintViolationException("参数校验异常", validate);
+ }
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java
index afe8115..2e4a79c 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/file/FileUtils.java
@@ -20,12 +20,17 @@ import org.apache.commons.lang3.ArrayUtils;
import com.ruoyi.common.core.config.RuoYiConfig;
import org.apache.commons.io.FilenameUtils;
+import cn.hutool.core.io.FileUtil;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+
/**
* 文件处理工具类
*
* @author ruoyi
*/
-public class FileUtils
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class FileUtils extends FileUtil
{
public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
@@ -74,7 +79,7 @@ public class FileUtils
*/
public static String writeImportBytes(byte[] data) throws IOException
{
- return writeBytes(data, RuoYiConfig.getImportPath());
+ return writeByte(data, RuoYiConfig.getImportPath());
}
/**
@@ -85,7 +90,7 @@ public class FileUtils
* @return 目标文件
* @throws IOException IO异常
*/
- public static String writeBytes(byte[] data, String uploadDir) throws IOException
+ public static String writeByte(byte[] data, String uploadDir) throws IOException
{
FileOutputStream fos = null;
String pathName = "";
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java
index 1b8345c..93aacdb 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/poi/ExcelUtil.java
@@ -78,7 +78,6 @@ import org.slf4j.LoggerFactory;
import com.ruoyi.common.core.config.RuoYiConfig;
import com.ruoyi.common.core.exception.UtilException;
import com.ruoyi.common.core.utils.DateUtils;
-import com.ruoyi.common.core.utils.DictUtils;
import com.ruoyi.common.core.utils.file.FileTypeUtils;
import com.ruoyi.common.core.utils.file.FileUtils;
import com.ruoyi.common.core.utils.file.ImageUtils;
@@ -86,7 +85,7 @@ import com.ruoyi.common.core.utils.reflect.ReflectUtils;
/**
* Excel相关处理
- *
+ *
* @author ruoyi
*/
public class ExcelUtil
@@ -283,7 +282,7 @@ public class ExcelUtil
/**
* 对excel表单默认第一个索引名转换成list
- *
+ *
* @param is 输入流
* @return 转换后集合
*/
@@ -294,7 +293,7 @@ public class ExcelUtil
/**
* 对excel表单默认第一个索引名转换成list
- *
+ *
* @param is 输入流
* @param titleNum 标题占用行数
* @return 转换后集合
@@ -306,7 +305,7 @@ public class ExcelUtil
/**
* 对excel表单指定表格索引名转换成list
- *
+ *
* @param sheetName 表格索引名
* @param titleNum 标题占用行数
* @param is 输入流
@@ -486,7 +485,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @return 结果
@@ -498,7 +497,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param list 导出数据集合
* @param sheetName 工作表的名称
* @param title 标题
@@ -512,7 +511,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param response 返回数据
* @param list 导出数据集合
* @param sheetName 工作表的名称
@@ -525,7 +524,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param response 返回数据
* @param list 导出数据集合
* @param sheetName 工作表的名称
@@ -542,7 +541,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param sheetName 工作表的名称
* @return 结果
*/
@@ -553,7 +552,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param sheetName 工作表的名称
* @param title 标题
* @return 结果
@@ -566,7 +565,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param sheetName 工作表的名称
* @return 结果
*/
@@ -577,7 +576,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @param sheetName 工作表的名称
* @param title 标题
* @return 结果
@@ -592,7 +591,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @return 结果
*/
public void exportExcel(HttpServletResponse response)
@@ -614,7 +613,7 @@ public class ExcelUtil
/**
* 对list数据源将其里面的数据导入到excel表单
- *
+ *
* @return 结果
*/
public AjaxResult exportExcel()
@@ -682,7 +681,7 @@ public class ExcelUtil
/**
* 填充excel数据
- *
+ *
* @param index 序号
* @param row 单元格行
*/
@@ -753,7 +752,7 @@ public class ExcelUtil
/**
* 创建表格样式
- *
+ *
* @param wb 工作薄对象
* @return 样式列表
*/
@@ -806,7 +805,7 @@ public class ExcelUtil
/**
* 根据Excel注解创建表格头样式
- *
+ *
* @param wb 工作薄对象
* @return 自定义样式列表
*/
@@ -839,7 +838,7 @@ public class ExcelUtil
/**
* 根据Excel注解创建表格列样式
- *
+ *
* @param wb 工作薄对象
* @return 自定义样式列表
*/
@@ -901,7 +900,7 @@ public class ExcelUtil
/**
* 设置单元格信息
- *
+ *
* @param value 单元格值
* @param attr 注解相关
* @param cell 单元格信息
@@ -1070,7 +1069,7 @@ public class ExcelUtil
/**
* 设置 POI XSSFSheet 单元格提示或选择框
- *
+ *
* @param sheet 表单
* @param textlist 下拉框显示的内容
* @param promptContent 提示内容
@@ -1107,7 +1106,7 @@ public class ExcelUtil
/**
* 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框).
- *
+ *
* @param sheet 要设置的sheet.
* @param textlist 下拉框显示的内容
* @param promptContent 提示内容
@@ -1159,7 +1158,7 @@ public class ExcelUtil
/**
* 解析导出值 0=男,1=女,2=未知
- *
+ *
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
@@ -1196,7 +1195,7 @@ public class ExcelUtil
/**
* 反向解析值 男=0,女=1,未知=2
- *
+ *
* @param propertyValue 参数值
* @param converterExp 翻译注解
* @param separator 分隔符
@@ -1233,7 +1232,7 @@ public class ExcelUtil
/**
* 解析字典值
- *
+ *
* @param dictValue 字典值
* @param dictType 字典类型
* @param separator 分隔符
@@ -1241,12 +1240,13 @@ public class ExcelUtil
*/
public static String convertDictByExp(String dictValue, String dictType, String separator)
{
- return DictUtils.getDictLabel(dictType, dictValue, separator);
+ //return DictUtils.getDictLabel(dictType, dictValue, separator);
+ return "";
}
/**
* 反向解析值字典值
- *
+ *
* @param dictLabel 字典标签
* @param dictType 字典类型
* @param separator 分隔符
@@ -1254,12 +1254,13 @@ public class ExcelUtil
*/
public static String reverseDictByExp(String dictLabel, String dictType, String separator)
{
- return DictUtils.getDictValue(dictType, dictLabel, separator);
+ //return DictUtils.getDictValue(dictType, dictLabel, separator);
+ return "";
}
/**
* 数据处理器
- *
+ *
* @param value 数据值
* @param excel 数据注解
* @return
@@ -1336,7 +1337,7 @@ public class ExcelUtil
/**
* 获取下载路径
- *
+ *
* @param filename 文件名称
*/
public String getAbsoluteFile(String filename)
@@ -1352,7 +1353,7 @@ public class ExcelUtil
/**
* 获取bean中的属性值
- *
+ *
* @param vo 实体对象
* @param field 字段
* @param excel 注解
@@ -1383,7 +1384,7 @@ public class ExcelUtil
/**
* 以类的属性的get方法方法形式获取值
- *
+ *
* @param o
* @param name
* @return value
@@ -1489,7 +1490,7 @@ public class ExcelUtil
/**
* 创建工作表
- *
+ *
* @param sheetNo sheet数量
* @param index 序号
*/
@@ -1506,7 +1507,7 @@ public class ExcelUtil
/**
* 获取单元格值
- *
+ *
* @param row 获取的行
* @param column 获取单元格列号
* @return 单元格值
@@ -1566,7 +1567,7 @@ public class ExcelUtil
/**
* 判断是否是空行
- *
+ *
* @param row 判断的行
* @return
*/
@@ -1654,7 +1655,7 @@ public class ExcelUtil
/**
* 格式化不同类型的日期对象
- *
+ *
* @param dateFormat 日期格式
* @param val 被格式化的日期对象
* @return 格式化后的日期字符
@@ -1720,7 +1721,7 @@ public class ExcelUtil
/**
* 获取对象的子列表方法
- *
+ *
* @param name 名称
* @param pojoClass 类对象
* @return 子列表方法
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java
index d2e0bf1..8909ada 100644
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/reflect/ReflectUtils.java
@@ -1,5 +1,6 @@
package com.ruoyi.common.core.utils.reflect;
+import cn.hutool.core.util.ReflectUtil;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -18,11 +19,11 @@ import org.slf4j.LoggerFactory;
/**
* 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
- *
+ *
* @author ruoyi
*/
@SuppressWarnings("rawtypes")
-public class ReflectUtils
+public class ReflectUtils extends ReflectUtil
{
private static final String SETTER_PREFIX = "set";
@@ -71,51 +72,51 @@ public class ReflectUtils
}
}
- /**
- * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
- */
- @SuppressWarnings("unchecked")
- public static E getFieldValue(final Object obj, final String fieldName)
- {
- Field field = getAccessibleField(obj, fieldName);
- if (field == null)
- {
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- return null;
- }
- E result = null;
- try
- {
- result = (E) field.get(obj);
- }
- catch (IllegalAccessException e)
- {
- logger.error("不可能抛出的异常{}", e.getMessage());
- }
- return result;
- }
-
- /**
- * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
- */
- public static void setFieldValue(final Object obj, final String fieldName, final E value)
- {
- Field field = getAccessibleField(obj, fieldName);
- if (field == null)
- {
- // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
- return;
- }
- try
- {
- field.set(obj, value);
- }
- catch (IllegalAccessException e)
- {
- logger.error("不可能抛出的异常: {}", e.getMessage());
- }
- }
+// /**
+// * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+// */
+// @SuppressWarnings("unchecked")
+// public static E getFieldValue(final Object obj, final String fieldName)
+// {
+// Field field = getAccessibleField(obj, fieldName);
+// if (field == null)
+// {
+// logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+// return null;
+// }
+// E result = null;
+// try
+// {
+// result = (E) field.get(obj);
+// }
+// catch (IllegalAccessException e)
+// {
+// logger.error("不可能抛出的异常{}", e.getMessage());
+// }
+// return result;
+// }
+//
+// /**
+// * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+// */
+// public static void setFieldValue(final Object obj, final String fieldName, final E value)
+// {
+// Field field = getAccessibleField(obj, fieldName);
+// if (field == null)
+// {
+// // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+// logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+// return;
+// }
+// try
+// {
+// field.set(obj, value);
+// }
+// catch (IllegalAccessException e)
+// {
+// logger.error("不可能抛出的异常: {}", e.getMessage());
+// }
+// }
/**
* 直接调用对象方法, 无视private/protected修饰符.
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java
deleted file mode 100644
index 23ec675..0000000
--- a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/utils/spring/SpringUtils.java
+++ /dev/null
@@ -1,158 +0,0 @@
-package com.ruoyi.common.core.utils.spring;
-
-import com.ruoyi.common.core.utils.StringUtils;
-import org.springframework.aop.framework.AopContext;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.NoSuchBeanDefinitionException;
-import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
-import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-
-/**
- * spring工具类 方便在非spring管理环境中获取bean
- *
- * @author ruoyi
- */
-@Component
-public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware
-{
- /** Spring应用上下文环境 */
- private static ConfigurableListableBeanFactory beanFactory;
-
- private static ApplicationContext applicationContext;
-
- @Override
- public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
- {
- SpringUtils.beanFactory = beanFactory;
- }
-
- @Override
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
- {
- SpringUtils.applicationContext = applicationContext;
- }
-
- /**
- * 获取对象
- *
- * @param name
- * @return Object 一个以所给名字注册的bean的实例
- * @throws org.springframework.beans.BeansException
- *
- */
- @SuppressWarnings("unchecked")
- public static T getBean(String name) throws BeansException
- {
- return (T) beanFactory.getBean(name);
- }
-
- /**
- * 获取类型为requiredType的对象
- *
- * @param clz
- * @return
- * @throws org.springframework.beans.BeansException
- *
- */
- public static T getBean(Class clz) throws BeansException
- {
- T result = (T) beanFactory.getBean(clz);
- return result;
- }
-
- /**
- * 如果BeanFactory包含一个与所给名称匹配的bean定义,则返回true
- *
- * @param name
- * @return boolean
- */
- public static boolean containsBean(String name)
- {
- return beanFactory.containsBean(name);
- }
-
- /**
- * 判断以给定名字注册的bean定义是一个singleton还是一个prototype。 如果与给定名字相应的bean定义没有被找到,将会抛出一个异常(NoSuchBeanDefinitionException)
- *
- * @param name
- * @return boolean
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.isSingleton(name);
- }
-
- /**
- * @param name
- * @return Class 注册对象的类型
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static Class> getType(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.getType(name);
- }
-
- /**
- * 如果给定的bean名字在bean定义中有别名,则返回这些别名
- *
- * @param name
- * @return
- * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
- *
- */
- public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
- {
- return beanFactory.getAliases(name);
- }
-
- /**
- * 获取aop代理对象
- *
- * @param invoker
- * @return
- */
- @SuppressWarnings("unchecked")
- public static T getAopProxy(T invoker)
- {
- return (T) AopContext.currentProxy();
- }
-
- /**
- * 获取当前的环境配置,无配置返回null
- *
- * @return 当前的环境配置
- */
- public static String[] getActiveProfiles()
- {
- return applicationContext.getEnvironment().getActiveProfiles();
- }
-
- /**
- * 获取当前的环境配置,当有多个环境配置时,只获取第一个
- *
- * @return 当前的环境配置
- */
- public static String getActiveProfile()
- {
- final String[] activeProfiles = getActiveProfiles();
- return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
- }
-
- /**
- * 获取配置文件中的值
- *
- * @param key 配置文件的key
- * @return 当前的配置文件的值
- *
- */
- public static String getRequiredProperty(String key)
- {
- return applicationContext.getEnvironment().getRequiredProperty(key);
- }
-}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java
new file mode 100644
index 0000000..e1934e1
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/AddGroup.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.validate;
+
+/**
+ * 校验分组 add
+ *
+ * @author Lion Li
+ */
+public interface AddGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java
new file mode 100644
index 0000000..3c6ca7f
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/EditGroup.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.validate;
+
+/**
+ * 校验分组 edit
+ *
+ * @author Lion Li
+ */
+public interface EditGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java
new file mode 100644
index 0000000..bbbfe03
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/QueryGroup.java
@@ -0,0 +1,9 @@
+package com.ruoyi.common.core.validate;
+
+/**
+ * 校验分组 query
+ *
+ * @author Lion Li
+ */
+public interface QueryGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java
new file mode 100644
index 0000000..536a85b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/EmailGroup.java
@@ -0,0 +1,7 @@
+package com.ruoyi.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface EmailGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java
new file mode 100644
index 0000000..2dba18e
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/PasswordGroup.java
@@ -0,0 +1,7 @@
+package com.ruoyi.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface PasswordGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java
new file mode 100644
index 0000000..660609f
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SmsGroup.java
@@ -0,0 +1,7 @@
+package com.ruoyi.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface SmsGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java
new file mode 100644
index 0000000..5a6a59a
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/SocialGroup.java
@@ -0,0 +1,4 @@
+package com.ruoyi.common.core.validate.auth;
+
+public interface SocialGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java
new file mode 100644
index 0000000..3f792f8
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/java/com/ruoyi/common/core/validate/auth/WechatGroup.java
@@ -0,0 +1,7 @@
+package com.ruoyi.common.core.validate.auth;
+
+/**
+ * @Author Michelle.Chung
+ */
+public interface WechatGroup {
+}
diff --git a/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
new file mode 100644
index 0000000..11c007c
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-core/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports
@@ -0,0 +1,5 @@
+com.ruoyi.common.core.config.ApplicationConfig
+com.ruoyi.common.core.config.AsyncConfig
+com.ruoyi.common.core.config.RuoYiConfig
+com.ruoyi.common.core.config.ThreadPoolConfig
+com.ruoyi.common.core.config.ValidatorConfig
diff --git a/ruoyi-common/ruoyi-common-excel/pom.xml b/ruoyi-common/ruoyi-common-excel/pom.xml
new file mode 100644
index 0000000..1b91b7b
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/pom.xml
@@ -0,0 +1,30 @@
+
+
+
+ com.ruoyi
+ ruoyi-common
+ ${revision}
+
+ 4.0.0
+
+ ruoyi-common-excel
+
+
+ ruoyi-common-excel excel表格模块
+
+
+
+
+ com.ruoyi
+ ruoyi-common-json
+
+
+
+ com.alibaba
+ easyexcel
+
+
+
+
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java
new file mode 100644
index 0000000..5c0f552
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/CellMerge.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.excel.annotation;
+
+import com.ruoyi.common.excel.core.CellMergeStrategy;
+
+import java.lang.annotation.*;
+
+/**
+ * excel 列单元格合并(合并列相同项)
+ *
+ * 需搭配 {@link CellMergeStrategy} 策略使用
+ *
+ * @author Lion Li
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface CellMerge {
+
+ /**
+ * col index
+ */
+ int index() default -1;
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java
new file mode 100644
index 0000000..162dc79
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelDictFormat.java
@@ -0,0 +1,32 @@
+package com.ruoyi.common.excel.annotation;
+
+import com.ruoyi.common.core.utils.StringUtils;
+
+import java.lang.annotation.*;
+
+/**
+ * 字典格式化
+ *
+ * @author Lion Li
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelDictFormat {
+
+ /**
+ * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+ */
+ String dictType() default "";
+
+ /**
+ * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+ */
+ String readConverterExp() default "";
+
+ /**
+ * 分隔符,读取字符串组内容
+ */
+ String separator() default StringUtils.SEPARATOR;
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java
new file mode 100644
index 0000000..d5fda7c
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/annotation/ExcelEnumFormat.java
@@ -0,0 +1,30 @@
+package com.ruoyi.common.excel.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 枚举格式化
+ *
+ * @author Liang
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface ExcelEnumFormat {
+
+ /**
+ * 字典枚举类型
+ */
+ Class extends Enum>> enumClass();
+
+ /**
+ * 字典枚举类中对应的code属性名称,默认为code
+ */
+ String codeField() default "code";
+
+ /**
+ * 字典枚举类中对应的text属性名称,默认为text
+ */
+ String textField() default "text";
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java
new file mode 100644
index 0000000..1e10334
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelBigNumberConvert.java
@@ -0,0 +1,52 @@
+package com.ruoyi.common.excel.convert;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import lombok.extern.slf4j.Slf4j;
+
+import java.math.BigDecimal;
+
+/**
+ * 大数值转换
+ * Excel 数值长度位15位 大于15位的数值转换位字符串
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class ExcelBigNumberConvert implements Converter {
+
+ @Override
+ public Class supportJavaTypeKey() {
+ return Long.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return CellDataTypeEnum.STRING;
+ }
+
+ @Override
+ public Long convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ return Convert.toLong(cellData.getData());
+ }
+
+ @Override
+ public WriteCellData convertToExcelData(Long object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ if (ObjectUtil.isNotNull(object)) {
+ String str = Convert.toStr(object);
+ if (str.length() > 15) {
+ return new WriteCellData<>(str);
+ }
+ }
+ WriteCellData cellData = new WriteCellData<>(new BigDecimal(object));
+ cellData.setType(CellDataTypeEnum.NUMBER);
+ return cellData;
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java
new file mode 100644
index 0000000..5d69355
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelDictConvert.java
@@ -0,0 +1,73 @@
+package com.ruoyi.common.excel.convert;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.ruoyi.common.excel.annotation.ExcelDictFormat;
+import com.ruoyi.common.excel.utils.ExcelUtil;
+import com.ruoyi.common.core.service.DictService;
+import com.ruoyi.common.core.utils.SpringUtils;
+import com.ruoyi.common.core.utils.StringUtils;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+
+/**
+ * 字典格式化转换处理
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class ExcelDictConvert implements Converter {
+
+ @Override
+ public Class supportJavaTypeKey() {
+ return Object.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return null;
+ }
+
+ @Override
+ public Object convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+ String type = anno.dictType();
+ String label = cellData.getStringValue();
+ String value;
+ if (StringUtils.isBlank(type)) {
+ value = ExcelUtil.reverseByExp(label, anno.readConverterExp(), anno.separator());
+ } else {
+ value = SpringUtils.getBean(DictService.class).getDictValue(type, label, anno.separator());
+ }
+ return Convert.convert(contentProperty.getField().getType(), value);
+ }
+
+ @Override
+ public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ if (ObjectUtil.isNull(object)) {
+ return new WriteCellData<>("");
+ }
+ ExcelDictFormat anno = getAnnotation(contentProperty.getField());
+ String type = anno.dictType();
+ String value = Convert.toStr(object);
+ String label;
+ if (StringUtils.isBlank(type)) {
+ label = ExcelUtil.convertByExp(value, anno.readConverterExp(), anno.separator());
+ } else {
+ label = SpringUtils.getBean(DictService.class).getDictLabel(type, value, anno.separator());
+ }
+ return new WriteCellData<>(label);
+ }
+
+ private ExcelDictFormat getAnnotation(Field field) {
+ return AnnotationUtil.getAnnotation(field, ExcelDictFormat.class);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java
new file mode 100644
index 0000000..2fb1d32
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/convert/ExcelEnumConvert.java
@@ -0,0 +1,87 @@
+package com.ruoyi.common.excel.convert;
+
+import cn.hutool.core.annotation.AnnotationUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.alibaba.excel.converters.Converter;
+import com.alibaba.excel.enums.CellDataTypeEnum;
+import com.alibaba.excel.metadata.GlobalConfiguration;
+import com.alibaba.excel.metadata.data.ReadCellData;
+import com.alibaba.excel.metadata.data.WriteCellData;
+import com.alibaba.excel.metadata.property.ExcelContentProperty;
+import com.ruoyi.common.core.utils.reflect.ReflectUtils;
+import com.ruoyi.common.excel.annotation.ExcelEnumFormat;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 枚举格式化转换处理
+ *
+ * @author Liang
+ */
+@Slf4j
+public class ExcelEnumConvert implements Converter {
+
+ @Override
+ public Class supportJavaTypeKey() {
+ return Object.class;
+ }
+
+ @Override
+ public CellDataTypeEnum supportExcelTypeKey() {
+ return null;
+ }
+
+ @Override
+ public Object convertToJavaData(ReadCellData> cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ cellData.checkEmpty();
+ // Excel中填入的是枚举中指定的描述
+ Object textValue = switch (cellData.getType()) {
+ case STRING, DIRECT_STRING, RICH_TEXT_STRING -> cellData.getStringValue();
+ case NUMBER -> cellData.getNumberValue();
+ case BOOLEAN -> cellData.getBooleanValue();
+ default -> throw new IllegalArgumentException("单元格类型异常!");
+ };
+ // 如果是空值
+ if (ObjectUtil.isNull(textValue)) {
+ return null;
+ }
+ Map enumCodeToTextMap = beforeConvert(contentProperty);
+ // 从Java输出至Excel是code转text
+ // 因此从Excel转Java应该将text与code对调
+ Map enumTextToCodeMap = new HashMap<>();
+ enumCodeToTextMap.forEach((key, value) -> enumTextToCodeMap.put(value, key));
+ // 应该从text -> code中查找
+ Object codeValue = enumTextToCodeMap.get(textValue);
+ return Convert.convert(contentProperty.getField().getType(), codeValue);
+ }
+
+ @Override
+ public WriteCellData convertToExcelData(Object object, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) {
+ if (ObjectUtil.isNull(object)) {
+ return new WriteCellData<>("");
+ }
+ Map enumValueMap = beforeConvert(contentProperty);
+ String value = Convert.toStr(enumValueMap.get(object), "");
+ return new WriteCellData<>(value);
+ }
+
+ private Map beforeConvert(ExcelContentProperty contentProperty) {
+ ExcelEnumFormat anno = getAnnotation(contentProperty.getField());
+ Map enumValueMap = new HashMap<>();
+ Enum>[] enumConstants = anno.enumClass().getEnumConstants();
+ for (Enum> enumConstant : enumConstants) {
+ Object codeValue = ReflectUtils.invokeGetter(enumConstant, anno.codeField());
+ String textValue = ReflectUtils.invokeGetter(enumConstant, anno.textField());
+ enumValueMap.put(codeValue, textValue);
+ }
+ return enumValueMap;
+ }
+
+ private ExcelEnumFormat getAnnotation(Field field) {
+ return AnnotationUtil.getAnnotation(field, ExcelEnumFormat.class);
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java
new file mode 100644
index 0000000..2e7e4d9
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/CellMergeStrategy.java
@@ -0,0 +1,121 @@
+package com.ruoyi.common.excel.core;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.excel.annotation.ExcelProperty;
+import com.alibaba.excel.metadata.Head;
+import com.alibaba.excel.write.merge.AbstractMergeStrategy;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.util.CellRangeAddress;
+import com.ruoyi.common.core.utils.reflect.ReflectUtils;
+import com.ruoyi.common.excel.annotation.CellMerge;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 列值重复合并策略
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class CellMergeStrategy extends AbstractMergeStrategy {
+
+ private final List cellList;
+ private final boolean hasTitle;
+ private int rowIndex;
+
+ public CellMergeStrategy(List> list, boolean hasTitle) {
+ this.hasTitle = hasTitle;
+ // 行合并开始下标
+ this.rowIndex = hasTitle ? 1 : 0;
+ this.cellList = handle(list, hasTitle);
+ }
+
+ @Override
+ protected void merge(Sheet sheet, Cell cell, Head head, Integer relativeRowIndex) {
+ // judge the list is not null
+ if (CollUtil.isNotEmpty(cellList)) {
+ // the judge is necessary
+ if (cell.getRowIndex() == rowIndex && cell.getColumnIndex() == 0) {
+ for (CellRangeAddress item : cellList) {
+ sheet.addMergedRegion(item);
+ }
+ }
+ }
+ }
+
+ @SneakyThrows
+ private List handle(List> list, boolean hasTitle) {
+ List cellList = new ArrayList<>();
+ if (CollUtil.isEmpty(list)) {
+ return cellList;
+ }
+ Field[] fields = ReflectUtils.getFields(list.get(0).getClass(), field -> !"serialVersionUID".equals(field.getName()));
+
+ // 有注解的字段
+ List mergeFields = new ArrayList<>();
+ List mergeFieldsIndex = new ArrayList<>();
+ for (int i = 0; i < fields.length; i++) {
+ Field field = fields[i];
+ if (field.isAnnotationPresent(CellMerge.class)) {
+ CellMerge cm = field.getAnnotation(CellMerge.class);
+ mergeFields.add(field);
+ mergeFieldsIndex.add(cm.index() == -1 ? i : cm.index());
+ if (hasTitle) {
+ ExcelProperty property = field.getAnnotation(ExcelProperty.class);
+ rowIndex = Math.max(rowIndex, property.value().length);
+ }
+ }
+ }
+
+ Map map = new HashMap<>();
+ // 生成两两合并单元格
+ for (int i = 0; i < list.size(); i++) {
+ for (int j = 0; j < mergeFields.size(); j++) {
+ Field field = mergeFields.get(j);
+ Object val = ReflectUtils.invokeGetter(list.get(i), field.getName());
+
+ int colNum = mergeFieldsIndex.get(j);
+ if (!map.containsKey(field)) {
+ map.put(field, new RepeatCell(val, i));
+ } else {
+ RepeatCell repeatCell = map.get(field);
+ Object cellValue = repeatCell.getValue();
+ if (cellValue == null || "".equals(cellValue)) {
+ // 空值跳过不合并
+ continue;
+ }
+ if (!cellValue.equals(val)) {
+ if (i - repeatCell.getCurrent() > 1) {
+ cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex - 1, colNum, colNum));
+ }
+ map.put(field, new RepeatCell(val, i));
+ } else if (i == list.size() - 1) {
+ if (i > repeatCell.getCurrent()) {
+ cellList.add(new CellRangeAddress(repeatCell.getCurrent() + rowIndex, i + rowIndex, colNum, colNum));
+ }
+ }
+ }
+ }
+ }
+ return cellList;
+ }
+
+ @Data
+ @AllArgsConstructor
+ static class RepeatCell {
+
+ private Object value;
+
+ private int current;
+
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java
new file mode 100644
index 0000000..1cf6426
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelListener.java
@@ -0,0 +1,104 @@
+package com.ruoyi.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import com.alibaba.excel.exception.ExcelAnalysisException;
+import com.alibaba.excel.exception.ExcelDataConvertException;
+import com.ruoyi.common.core.utils.StreamUtils;
+import com.ruoyi.common.core.utils.ValidatorUtils;
+import com.ruoyi.common.json.utils.JsonUtils;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import lombok.NoArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Excel 导入监听
+ *
+ * @author Yjoioooo
+ * @author Lion Li
+ */
+@Slf4j
+@NoArgsConstructor
+public class DefaultExcelListener extends AnalysisEventListener implements ExcelListener {
+
+ /**
+ * 是否Validator检验,默认为是
+ */
+ private Boolean isValidate = Boolean.TRUE;
+
+ /**
+ * excel 表头数据
+ */
+ private Map headMap;
+
+ /**
+ * 导入回执
+ */
+ private ExcelResult excelResult;
+
+ public DefaultExcelListener(boolean isValidate) {
+ this.excelResult = new DefaultExcelResult<>();
+ this.isValidate = isValidate;
+ }
+
+ /**
+ * 处理异常
+ *
+ * @param exception ExcelDataConvertException
+ * @param context Excel 上下文
+ */
+ @Override
+ public void onException(Exception exception, AnalysisContext context) throws Exception {
+ String errMsg = null;
+ if (exception instanceof ExcelDataConvertException excelDataConvertException) {
+ // 如果是某一个单元格的转换异常 能获取到具体行号
+ Integer rowIndex = excelDataConvertException.getRowIndex();
+ Integer columnIndex = excelDataConvertException.getColumnIndex();
+ errMsg = StrUtil.format("第{}行-第{}列-表头{}: 解析异常
",
+ rowIndex + 1, columnIndex + 1, headMap.get(columnIndex));
+ if (log.isDebugEnabled()) {
+ log.error(errMsg);
+ }
+ }
+ if (exception instanceof ConstraintViolationException constraintViolationException) {
+ Set> constraintViolations = constraintViolationException.getConstraintViolations();
+ String constraintViolationsMsg = StreamUtils.join(constraintViolations, ConstraintViolation::getMessage, ", ");
+ errMsg = StrUtil.format("第{}行数据校验异常: {}", context.readRowHolder().getRowIndex() + 1, constraintViolationsMsg);
+ if (log.isDebugEnabled()) {
+ log.error(errMsg);
+ }
+ }
+ excelResult.getErrorList().add(errMsg);
+ throw new ExcelAnalysisException(errMsg);
+ }
+
+ @Override
+ public void invokeHeadMap(Map headMap, AnalysisContext context) {
+ this.headMap = headMap;
+ log.debug("解析到一条表头数据: {}", JsonUtils.toJsonString(headMap));
+ }
+
+ @Override
+ public void invoke(T data, AnalysisContext context) {
+ if (isValidate) {
+ ValidatorUtils.validate(data);
+ }
+ excelResult.getList().add(data);
+ }
+
+ @Override
+ public void doAfterAllAnalysed(AnalysisContext context) {
+ log.debug("所有数据解析完成!");
+ }
+
+ @Override
+ public ExcelResult getExcelResult() {
+ return excelResult;
+ }
+
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java
new file mode 100644
index 0000000..e57b2a5
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DefaultExcelResult.java
@@ -0,0 +1,73 @@
+package com.ruoyi.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 默认excel返回对象
+ *
+ * @author Yjoioooo
+ * @author Lion Li
+ */
+public class DefaultExcelResult implements ExcelResult {
+
+ /**
+ * 数据对象list
+ */
+ @Setter
+ private List list;
+
+ /**
+ * 错误信息列表
+ */
+ @Setter
+ private List errorList;
+
+ public DefaultExcelResult() {
+ this.list = new ArrayList<>();
+ this.errorList = new ArrayList<>();
+ }
+
+ public DefaultExcelResult(List list, List errorList) {
+ this.list = list;
+ this.errorList = errorList;
+ }
+
+ public DefaultExcelResult(ExcelResult excelResult) {
+ this.list = excelResult.getList();
+ this.errorList = excelResult.getErrorList();
+ }
+
+ @Override
+ public List getList() {
+ return list;
+ }
+
+ @Override
+ public List getErrorList() {
+ return errorList;
+ }
+
+ /**
+ * 获取导入回执
+ *
+ * @return 导入回执
+ */
+ @Override
+ public String getAnalysis() {
+ int successCount = list.size();
+ int errorCount = errorList.size();
+ if (successCount == 0) {
+ return "读取失败,未解析到数据";
+ } else {
+ if (errorCount == 0) {
+ return StrUtil.format("恭喜您,全部读取成功!共{}条", successCount);
+ } else {
+ return "";
+ }
+ }
+ }
+}
diff --git a/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java
new file mode 100644
index 0000000..1caf9bb
--- /dev/null
+++ b/ruoyi-common/ruoyi-common-excel/src/main/java/com/ruoyi/common/excel/core/DropDownOptions.java
@@ -0,0 +1,149 @@
+package com.ruoyi.common.excel.core;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import com.ruoyi.common.core.exception.ServiceException;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+/**
+ * Excel下拉可选项
+ * 注意:为确保下拉框解析正确,传值务必使用createOptionValue()做为值的拼接
+ *
+ * @author Emil.Zhang
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@SuppressWarnings("unused")
+public class DropDownOptions {
+ /**
+ * 一级下拉所在列index,从0开始算
+ */
+ private int index = 0;
+ /**
+ * 二级下拉所在的index,从0开始算,不能与一级相同
+ */
+ private int nextIndex = 0;
+ /**
+ * 一级下拉所包含的数据
+ */
+ private List options = new ArrayList<>();
+ /**
+ * 二级下拉所包含的数据Map
+ * 以每一个一级选项值为Key,每个一级选项对应的二级数据为Value
+ */
+ private Map> nextOptions = new HashMap<>();
+ /**
+ * 分隔符
+ */
+ private static final String DELIMITER = "_";
+
+ /**
+ * 创建只有一级的下拉选
+ */
+ public DropDownOptions(int index, List options) {
+ this.index = index;
+ this.options = options;
+ }
+
+ /**
+ * 创建每个选项可选值
+ * 注意:不能以数字,特殊符号开头,选项中不可以包含任何运算符号
+ *
+ * @param vars 可选值内包含的参数
+ * @return 合规的可选值
+ */
+ public static String createOptionValue(Object... vars) {
+ StringBuilder stringBuffer = new StringBuilder();
+ String regex = "^[\\S\\d\\u4e00-\\u9fa5]+$";
+ for (int i = 0; i < vars.length; i++) {
+ String var = StrUtil.trimToEmpty(String.valueOf(vars[i]));
+ if (!var.matches(regex)) {
+ throw new ServiceException("选项数据不符合规则,仅允许使用中英文字符以及数字");
+ }
+ stringBuffer.append(var);
+ if (i < vars.length - 1) {
+ // 直至最后一个前,都以_作为切割线
+ stringBuffer.append(DELIMITER);
+ }
+ }
+ if (stringBuffer.toString().matches("^\\d_*$")) {
+ throw new ServiceException("禁止以数字开头");
+ }
+ return stringBuffer.toString();
+ }
+
+ /**
+ * 将处理后合理的可选值解析为原始的参数
+ *
+ * @param option 经过处理后的合理的可选项
+ * @return 原始的参数
+ */
+ public static List analyzeOptionValue(String option) {
+ return StrUtil.split(option, DELIMITER, true, true);
+ }
+
+ /**
+ * 创建级联下拉选项
+ *
+ * @param parentList 父实体可选项原始数据
+ * @param parentIndex 父下拉选位置
+ * @param sonList 子实体可选项原始数据
+ * @param sonIndex 子下拉选位置
+ * @param parentHowToGetIdFunction 父类如何获取唯一标识
+ * @param sonHowToGetParentIdFunction 子类如何获取父类的唯一标识
+ * @param howToBuildEveryOption 如何生成下拉选内容
+ * @return 级联下拉选项
+ */
+ public static