xlsea
2024-12-16 4d566071db7853c66805a1ffac2fd9c93a6aac8a
Merge remote-tracking branch 'origin/dev' into dev
已添加6个文件
已修改27个文件
904 ■■■■ 文件已修改
pom.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java 146 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java 250 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
pom.xml
@@ -36,7 +36,7 @@
        <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
        <lombok.version>1.18.34</lombok.version>
        <bouncycastle.version>1.76</bouncycastle.version>
        <justauth.version>1.16.6</justauth.version>
        <justauth.version>1.16.7</justauth.version>
        <!-- ç¦»çº¿IP地址定位库 -->
        <ip2region.version>2.7.0</ip2region.version>
ruoyi-admin/src/main/java/org/dromara/web/service/SysLoginService.java
@@ -14,6 +14,7 @@
import org.dromara.common.core.constant.Constants;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.dto.PostDTO;
import org.dromara.common.core.domain.dto.RoleDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.LoginType;
@@ -60,6 +61,7 @@
    private final ISysSocialService sysSocialService;
    private final ISysRoleService roleService;
    private final ISysDeptService deptService;
    private final ISysPostService postService;
    private final SysUserMapper userMapper;
@@ -148,21 +150,24 @@
     */
    public LoginUser buildLoginUser(SysUserVo user) {
        LoginUser loginUser = new LoginUser();
        Long userId = user.getUserId();
        loginUser.setTenantId(user.getTenantId());
        loginUser.setUserId(user.getUserId());
        loginUser.setUserId(userId);
        loginUser.setDeptId(user.getDeptId());
        loginUser.setUsername(user.getUserName());
        loginUser.setNickname(user.getNickName());
        loginUser.setUserType(user.getUserType());
        loginUser.setMenuPermission(permissionService.getMenuPermission(user.getUserId()));
        loginUser.setRolePermission(permissionService.getRolePermission(user.getUserId()));
        loginUser.setMenuPermission(permissionService.getMenuPermission(userId));
        loginUser.setRolePermission(permissionService.getRolePermission(userId));
        if (ObjectUtil.isNotNull(user.getDeptId())) {
            Opt<SysDeptVo> deptOpt = Opt.of(user.getDeptId()).map(deptService::selectDeptById);
            loginUser.setDeptName(deptOpt.map(SysDeptVo::getDeptName).orElse(StringUtils.EMPTY));
            loginUser.setDeptCategory(deptOpt.map(SysDeptVo::getDeptCategory).orElse(StringUtils.EMPTY));
        }
        List<SysRoleVo> roles = roleService.selectRolesByUserId(user.getUserId());
        List<SysRoleVo> roles = roleService.selectRolesByUserId(userId);
        List<SysPostVo> posts = postService.selectPostsByUserId(userId);
        loginUser.setRoles(BeanUtil.copyToList(roles, RoleDTO.class));
        loginUser.setPosts(BeanUtil.copyToList(posts, PostDTO.class));
        return loginUser;
    }
ruoyi-admin/src/main/java/org/dromara/web/service/impl/XcxAuthStrategy.java
@@ -5,9 +5,17 @@
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.model.AuthCallback;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.request.AuthWechatMiniProgramRequest;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.model.XcxLoginBody;
import org.dromara.common.core.domain.model.XcxLoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.ValidatorUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.satoken.utils.LoginHelper;
@@ -39,12 +47,24 @@
        // å¤šä¸ªå°ç¨‹åºè¯†åˆ«ä½¿ç”¨
        String appid = loginBody.getAppid();
        // todo ä»¥ä¸‹è‡ªè¡Œå®žçް
        // æ ¡éªŒ appid + appsrcret + xcxCode è°ƒç”¨ç™»å½•凭证校验接口 èŽ·å– session_key ä¸Ž openid
        String openid = "";
        AuthRequest authRequest = new AuthWechatMiniProgramRequest(AuthConfig.builder()
            .clientId(appid).clientSecret("自行填写密钥 å¯æ ¹æ®ä¸åŒappid填入不同密钥")
            .ignoreCheckRedirectUri(true).ignoreCheckState(true).build());
        AuthCallback authCallback = new AuthCallback();
        authCallback.setCode(xcxCode);
        AuthResponse<AuthUser> resp = authRequest.login(authCallback);
        String openid, unionId;
        if (resp.ok()) {
            AuthToken token = resp.getData().getToken();
            openid = token.getOpenId();
            // å¾®ä¿¡å°ç¨‹åºåªæœ‰å…³è”到微信开放平台下之后才能获取到 unionId,因此unionId不一定能返回。
            unionId = token.getUnionId();
        } else {
            throw new ServiceException(resp.getMsg());
        }
        // æ¡†æž¶ç™»å½•不限制从什么表查询 åªè¦æœ€ç»ˆæž„建出 LoginUser å³å¯
        SysUserVo user = loadUserByOpenid(openid);
        // æ­¤å¤„可根据登录用户的数据不同 è‡ªè¡Œåˆ›å»º loginUser å±žæ€§ä¸å¤Ÿç”¨ç»§æ‰¿æ‰©å±•就行了
        XcxLoginUser loginUser = new XcxLoginUser();
        loginUser.setTenantId(user.getTenantId());
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/DeptDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
 * éƒ¨é—¨
 *
 * @author AprilWind
 */
@Data
@NoArgsConstructor
public class DeptDTO implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * éƒ¨é—¨ID
     */
    private Long deptId;
    /**
     * çˆ¶éƒ¨é—¨ID
     */
    private Long parentId;
    /**
     * éƒ¨é—¨åç§°
     */
    private String deptName;
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/dto/PostDTO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,46 @@
package org.dromara.common.core.domain.dto;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
/**
 * å²—位
 *
 * @author AprilWind
 */
@Data
@NoArgsConstructor
public class PostDTO implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    /**
     * å²—位ID
     */
    private Long postId;
    /**
     * éƒ¨é—¨id
     */
    private Long deptId;
    /**
     * å²—位编码
     */
    private String postCode;
    /**
     * å²—位名称
     */
    private String postName;
    /**
     * å²—位类别编码
     */
    private String postCategory;
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/domain/model/LoginUser.java
@@ -1,8 +1,9 @@
package org.dromara.common.core.domain.model;
import org.dromara.common.core.domain.dto.RoleDTO;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.dromara.common.core.domain.dto.PostDTO;
import org.dromara.common.core.domain.dto.RoleDTO;
import java.io.Serial;
import java.io.Serializable;
@@ -112,6 +113,11 @@
    private List<RoleDTO> roles;
    /**
     * å²—位对象
     */
    private List<PostDTO> posts;
    /**
     * æ•°æ®æƒé™ å½“前角色ID
     */
    private Long roleId;
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/enums/FormatsType.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,146 @@
package org.dromara.common.core.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.dromara.common.core.utils.StringUtils;
/*
 * æ—¥æœŸæ ¼å¼
 * "yyyy":4位数的年份,例如:2023年表示为"2023"。
 * "yy":2位数的年份,例如:2023年表示为"23"。
 * "MM":2位数的月份,取值范围为01到12,例如:7月表示为"07"。
 * "M":不带前导零的月份,取值范围为1到12,例如:7月表示为"7"。
 * "dd":2位数的日期,取值范围为01到31,例如:22日表示为"22"。
 * "d":不带前导零的日期,取值范围为1到31,例如:22日表示为"22"。
 * "EEEE":星期的全名,例如:星期三表示为"Wednesday"。
 * "E":星期的缩写,例如:星期三表示为"Wed"。
 * "DDD" æˆ– "D":一年中的第几天,取值范围为001到366,例如:第200天表示为"200"。
 * æ—¶é—´æ ¼å¼
 * "HH":24小时制的小时数,取值范围为00到23,例如:下午5点表示为"17"。
 * "hh":12小时制的小时数,取值范围为01到12,例如:下午5点表示为"05"。
 * "mm":分钟数,取值范围为00到59,例如:30分钟表示为"30"。
 * "ss":秒数,取值范围为00到59,例如:45秒表示为"45"。
 * "SSS":毫秒数,取值范围为000到999,例如:123毫秒表示为"123"。
 */
/**
 * æ—¥æœŸæ ¼å¼ä¸Žæ—¶é—´æ ¼å¼æžšä¸¾
 */
@Getter
@AllArgsConstructor
public enum FormatsType {
    /**
     * ä¾‹å¦‚:2023年表示为"23"
     */
    YY("yy"),
    /**
     * ä¾‹å¦‚:2023年表示为"2023"
     */
    YYYY("yyyy"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023-07"
     */
    YYYY_MM("yyyy-MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023-07-22"
     */
    YYYY_MM_DD("yyyy-MM-dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分",则可以表示为 "2023-07-22 15:30"
     */
    YYYY_MM_DD_HH_MM("yyyy-MM-dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023-07-22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS("yyyy-MM-dd HH:mm:ss"),
    /**
     * ä¾‹å¦‚:下午3点30分45秒,表示为 "15:30:45"
     */
    HH_MM_SS("HH:mm:ss"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023/07"
     */
    YYYY_MM_SLASH("yyyy/MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023/07/22"
     */
    YYYY_MM_DD_SLASH("yyyy/MM/dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SLASH("yyyy/MM/dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023/07/22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS_SLASH("yyyy/MM/dd HH:mm:ss"),
    /**
     * ä¾‹ä¾‹å¦‚,2023å¹´7月可以表示为 "2023.07"
     */
    YYYY_MM_DOT("yyyy.MM"),
    /**
     * ä¾‹å¦‚,日期 "2023å¹´7月22日" å¯ä»¥è¡¨ç¤ºä¸º "2023.07.22"
     */
    YYYY_MM_DD_DOT("yyyy.MM.dd"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分",则可以表示为 "2023.07.22 15:30"
     */
    YYYY_MM_DD_HH_MM_DOT("yyyy.MM.dd HH:mm"),
    /**
     * ä¾‹å¦‚,当前时间如果是 "2023å¹´7月22日下午3点30分45秒",则可以表示为 "2023.07.22 15:30:45"
     */
    YYYY_MM_DD_HH_MM_SS_DOT("yyyy.MM.dd HH:mm:ss"),
    /**
     * ä¾‹å¦‚,2023å¹´7月可以表示为 "202307"
     */
    YYYYMM("yyyyMM"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日可以表示为 "20230722"
     */
    YYYYMMDD("yyyyMMdd"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点可以表示为 "2023072215"
     */
    YYYYMMDDHH("yyyyMMddHH"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点30分可以表示为 "202307221530"
     */
    YYYYMMDDHHMM("yyyyMMddHHmm"),
    /**
     * ä¾‹å¦‚,2023å¹´7月22日下午3点30分45秒可以表示为 "20230722153045"
     */
    YYYYMMDDHHMMSS("yyyyMMddHHmmss");
    /**
     * æ—¶é—´æ ¼å¼
     */
    private final String timeFormat;
    public static FormatsType getFormatsType(String str) {
        for (FormatsType value : values()) {
            if (StringUtils.contains(str, value.getTimeFormat())) {
                return value;
            }
        }
        throw new RuntimeException("'FormatsType' not found By " + str);
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/DeptService.java
@@ -1,5 +1,9 @@
package org.dromara.common.core.service;
import org.dromara.common.core.domain.dto.DeptDTO;
import java.util.List;
/**
 * é€šç”¨ éƒ¨é—¨æœåŠ¡
 *
@@ -15,4 +19,19 @@
     */
    String selectDeptNameByIds(String deptIds);
    /**
     * æ ¹æ®éƒ¨é—¨ID查询部门负责人
     *
     * @param deptId éƒ¨é—¨ID,用于指定需要查询的部门
     * @return è¿”回该部门的负责人ID
     */
    Long selectDeptLeaderById(Long deptId);
    /**
     * æŸ¥è¯¢éƒ¨é—¨
     *
     * @return éƒ¨é—¨åˆ—表
     */
    List<DeptDTO> selectDeptsByList();
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/PostService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
package org.dromara.common.core.service;
/**
 * é€šç”¨ å²—位服务
 *
 * @author AprilWind
 */
public interface PostService {
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/RoleService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,10 @@
package org.dromara.common.core.service;
/**
 * é€šç”¨ è§’色服务
 *
 * @author AprilWind
 */
public interface RoleService {
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/service/UserService.java
@@ -82,4 +82,13 @@
     * @return ç”¨æˆ·
     */
    List<UserDTO> selectUsersByDeptIds(List<Long> deptIds);
    /**
     * é€šè¿‡å²—位ID查询用户
     *
     * @param postIds å²—位ids
     * @return ç”¨æˆ·
     */
    List<UserDTO> selectUsersByPostIds(List<Long> postIds);
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/DateUtils.java
@@ -3,16 +3,15 @@
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.dromara.common.core.enums.FormatsType;
import org.dromara.common.core.exception.ServiceException;
import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
 * æ—¶é—´å·¥å…·ç±»
@@ -21,86 +20,137 @@
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DateUtils extends org.apache.commons.lang3.time.DateUtils {
    public static final String YYYY = "yyyy";
    public static final String YYYY_MM = "yyyy-MM";
    public static final String YYYY_MM_DD = "yyyy-MM-dd";
    public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
    public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
    private static final String[] PARSE_PATTERNS = {
        "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
        "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
        "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
    /**
     * èŽ·å–å½“å‰Date型日期
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´
     *
     * @return Date() å½“前日期
     * @return å½“前日期和时间的 Date å¯¹è±¡è¡¨ç¤º
     */
    public static Date getNowDate() {
        return new Date();
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸ, é»˜è®¤æ ¼å¼ä¸ºyyyy-MM-dd
     * èŽ·å–å½“å‰æ—¥æœŸçš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYY-MM-DD
     *
     * @return String
     * @return å½“前日期的字符串表示
     */
    public static String getDate() {
        return dateTimeNow(YYYY_MM_DD);
        return dateTimeNow(FormatsType.YYYY_MM_DD);
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸçš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºyyyyMMdd
     *
     * @return å½“前日期的字符串表示
     */
    public static String getCurrentDate() {
        return DateFormatUtils.format(new Date(), FormatsType.YYYYMMDD.getTimeFormat());
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸçš„è·¯å¾„æ ¼å¼å­—ç¬¦ä¸²ï¼Œæ ¼å¼ä¸º"yyyy/MM/dd"
     *
     * @return å½“前日期的路径格式字符串
     */
    public static String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, FormatsType.YYYY_MM_DD_SLASH.getTimeFormat());
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYY-MM-DD HH:MM:SS
     *
     * @return å½“前时间的字符串表示
     */
    public static String getTime() {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
        return dateTimeNow(FormatsType.YYYY_MM_DD_HH_MM_SS);
    }
    /**
     * èŽ·å–å½“å‰æ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸º "HH:MM:SS"
     *
     * @return å½“前时间的字符串表示,格式为 "HH:MM:SS"
     */
    public static String getTimeWithHourMinuteSecond() {
        return dateTimeNow(FormatsType.HH_MM_SS);
    }
    /**
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´çš„å­—ç¬¦ä¸²è¡¨ç¤ºï¼Œæ ¼å¼ä¸ºYYYYMMDDHHMMSS
     *
     * @return å½“前日期和时间的字符串表示
     */
    public static String dateTimeNow() {
        return dateTimeNow(YYYYMMDDHHMMSS);
        return dateTimeNow(FormatsType.YYYYMMDDHHMMSS);
    }
    public static String dateTimeNow(final String format) {
    /**
     * èŽ·å–å½“å‰æ—¥æœŸå’Œæ—¶é—´çš„æŒ‡å®šæ ¼å¼çš„å­—ç¬¦ä¸²è¡¨ç¤º
     *
     * @param format æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @return å½“前日期和时间的字符串表示
     */
    public static String dateTimeNow(final FormatsType format) {
        return parseDateToStr(format, new Date());
    }
    public static String dateTime(final Date date) {
        return parseDateToStr(YYYY_MM_DD, date);
    /**
     * å°†æŒ‡å®šæ—¥æœŸæ ¼å¼åŒ–为 YYYY-MM-DD æ ¼å¼çš„字符串
     *
     * @param date è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期字符串
     */
    public static String formatDate(final Date date) {
        return parseDateToStr(FormatsType.YYYY_MM_DD, date);
    }
    public static String parseDateToStr(final String format, final Date date) {
        return new SimpleDateFormat(format).format(date);
    /**
     * å°†æŒ‡å®šæ—¥æœŸæ ¼å¼åŒ–为 YYYY-MM-DD HH:MM:SS æ ¼å¼çš„字符串
     *
     * @param date è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期时间字符串
     */
    public static String formatDateTime(final Date date) {
        return parseDateToStr(FormatsType.YYYY_MM_DD_HH_MM_SS, date);
    }
    public static Date dateTime(final String format, final String ts) {
    /**
     * å°†æŒ‡å®šæ—¥æœŸæŒ‰ç…§æŒ‡å®šæ ¼å¼è¿›è¡Œæ ¼å¼åŒ–
     *
     * @param format è¦ä½¿ç”¨çš„æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @param date   è¦æ ¼å¼åŒ–的日期对象
     * @return æ ¼å¼åŒ–后的日期时间字符串
     */
    public static String parseDateToStr(final FormatsType format, final Date date) {
        return new SimpleDateFormat(format.getTimeFormat()).format(date);
    }
    /**
     * å°†æŒ‡å®šæ ¼å¼çš„æ—¥æœŸæ—¶é—´å­—符串转换为 Date å¯¹è±¡
     *
     * @param format è¦è§£æžçš„æ—¥æœŸæ—¶é—´æ ¼å¼ï¼Œä¾‹å¦‚"YYYY-MM-DD HH:MM:SS"
     * @param ts     è¦è§£æžçš„æ—¥æœŸæ—¶é—´å­—符串
     * @return è§£æžåŽçš„ Date å¯¹è±¡
     * @throws RuntimeException å¦‚果解析过程中发生异常
     */
    public static Date parseDateTime(final FormatsType format, final String ts) {
        try {
            return new SimpleDateFormat(format).parse(ts);
            return new SimpleDateFormat(format.getTimeFormat()).parse(ts);
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * æ—¥æœŸè·¯å¾„ å³å¹´/月/日 å¦‚2018/08/08
     */
    public static String datePath() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }
    /**
     * æ—¥æœŸè·¯å¾„ å³å¹´/月/日 å¦‚20180808
     */
    public static String dateTime() {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }
    /**
     * æ—¥æœŸåž‹å­—符串转化为日期 æ ¼å¼
     * å°†å¯¹è±¡è½¬æ¢ä¸ºæ—¥æœŸå¯¹è±¡
     *
     * @param str è¦è½¬æ¢çš„对象,通常是字符串
     * @return è½¬æ¢åŽçš„æ—¥æœŸå¯¹è±¡ï¼Œå¦‚果转换失败或输入为null,则返回null
     */
    public static Date parseDate(Object str) {
        if (str == null) {
@@ -115,6 +165,8 @@
    /**
     * èŽ·å–æœåŠ¡å™¨å¯åŠ¨æ—¶é—´
     *
     * @return æœåŠ¡å™¨å¯åŠ¨æ—¶é—´çš„ Date å¯¹è±¡è¡¨ç¤º
     */
    public static Date getServerStartDate() {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
@@ -122,35 +174,66 @@
    }
    /**
     * è®¡ç®—相差天数
     * è®¡ç®—两个日期之间的天数差(以毫秒为单位)
     *
     * @param date1 ç¬¬ä¸€ä¸ªæ—¥æœŸ
     * @param date2 ç¬¬äºŒä¸ªæ—¥æœŸ
     * @return ä¸¤ä¸ªæ—¥æœŸä¹‹é—´çš„天数差的绝对值
     */
    public static int differentDaysByMillisecond(Date date1, Date date2) {
        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
    }
    /**
     * è®¡ç®—两个时间差
     * è®¡ç®—两个日期之间的时间差,并以天、小时和分钟的格式返回
     *
     * @param endDate ç»“束日期
     * @param nowDate å½“前日期
     * @return è¡¨ç¤ºæ—¶é—´å·®çš„字符串,格式为"天 å°æ—¶ åˆ†é’Ÿ"
     */
    public static String getDatePoor(Date endDate, Date nowDate) {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // èŽ·å¾—ä¸¤ä¸ªæ—¶é—´çš„æ¯«ç§’æ—¶é—´å·®å¼‚
        long diff = endDate.getTime() - nowDate.getTime();
        // è®¡ç®—差多少天
        long day = diff / nd;
        // è®¡ç®—差多少小时
        long hour = diff % nd / nh;
        // è®¡ç®—差多少分钟
        long min = diff % nd % nh / nm;
        // è®¡ç®—差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
        long diffInMillis = endDate.getTime() - nowDate.getTime();
        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
        return String.format("%d天 %d小时 %d分钟", day, hour, min);
    }
    /**
     * å¢žåŠ  LocalDateTime ==> Date
     * è®¡ç®—两个时间点的差值(天、小时、分钟、秒),当值为0时不显示该单位
     *
     * @param endDate ç»“束时间
     * @param nowDate å½“前时间
     * @return æ—¶é—´å·®å­—符串,格式为 "x天 x小时 x分钟 x秒",若为 0 åˆ™ä¸æ˜¾ç¤º
     */
    public static String getTimeDifference(Date endDate, Date nowDate) {
        long diffInMillis = endDate.getTime() - nowDate.getTime();
        long day = TimeUnit.MILLISECONDS.toDays(diffInMillis);
        long hour = TimeUnit.MILLISECONDS.toHours(diffInMillis) % 24;
        long min = TimeUnit.MILLISECONDS.toMinutes(diffInMillis) % 60;
        long sec = TimeUnit.MILLISECONDS.toSeconds(diffInMillis) % 60;
        // æž„建时间差字符串,条件是值不为0才显示
        StringBuilder result = new StringBuilder();
        if (day > 0) {
            result.append(String.format("%d天 ", day));
        }
        if (hour > 0) {
            result.append(String.format("%d小时 ", hour));
        }
        if (min > 0) {
            result.append(String.format("%d分钟 ", min));
        }
        if (sec > 0) {
            result.append(String.format("%d秒", sec));
        }
        return result.length() > 0 ? result.toString().trim() : "0秒";
    }
    /**
     * å°† LocalDateTime å¯¹è±¡è½¬æ¢ä¸º Date å¯¹è±¡
     *
     * @param temporalAccessor è¦è½¬æ¢çš„ LocalDateTime å¯¹è±¡
     * @return è½¬æ¢åŽçš„ Date å¯¹è±¡
     */
    public static Date toDate(LocalDateTime temporalAccessor) {
        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
@@ -158,11 +241,46 @@
    }
    /**
     * å¢žåŠ  LocalDate ==> Date
     * å°† LocalDate å¯¹è±¡è½¬æ¢ä¸º Date å¯¹è±¡
     *
     * @param temporalAccessor è¦è½¬æ¢çš„ LocalDate å¯¹è±¡
     * @return è½¬æ¢åŽçš„ Date å¯¹è±¡
     */
    public static Date toDate(LocalDate temporalAccessor) {
        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
        return Date.from(zdt.toInstant());
    }
    /**
     * æ ¡éªŒæ—¥æœŸèŒƒå›´
     *
     * @param startDate å¼€å§‹æ—¥æœŸ
     * @param endDate   ç»“束日期
     * @param maxValue  æœ€å¤§æ—¶é—´è·¨åº¦çš„限制值
     * @param unit      æ—¶é—´è·¨åº¦çš„单位,可选择 "DAYS"、"HOURS" æˆ– "MINUTES"
     */
    public static void validateDateRange(Date startDate, Date endDate, int maxValue, TimeUnit unit) {
        // æ ¡éªŒç»“束日期不能早于开始日期
        if (endDate.before(startDate)) {
            throw new ServiceException("结束日期不能早于开始日期");
        }
        // è®¡ç®—时间跨度
        long diffInMillis = endDate.getTime() - startDate.getTime();
        // æ ¹æ®å•位转换时间跨度
        long diff = switch (unit) {
            case DAYS -> TimeUnit.MILLISECONDS.toDays(diffInMillis);
            case HOURS -> TimeUnit.MILLISECONDS.toHours(diffInMillis);
            case MINUTES -> TimeUnit.MILLISECONDS.toMinutes(diffInMillis);
            default -> throw new IllegalArgumentException("不支持的时间单位");
        };
        // æ ¡éªŒæ—¶é—´è·¨åº¦ä¸è¶…过最大限制
        if (diff > maxValue) {
            throw new ServiceException("最大时间跨度为 " + maxValue + " " + unit.toString().toLowerCase());
        }
    }
}
ruoyi-common/ruoyi-common-core/src/main/java/org/dromara/common/core/utils/Threads.java
@@ -14,18 +14,6 @@
@Slf4j
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class Threads {
    /**
     * sleep等待,单位为毫秒
     */
    public static void sleep(long milliseconds) {
        try {
            Thread.sleep(milliseconds);
        } catch (InterruptedException e) {
            return;
        }
    }
    /**
     * åœæ­¢çº¿ç¨‹æ± 
     * å…ˆä½¿ç”¨shutdown, åœæ­¢æŽ¥æ”¶æ–°ä»»åŠ¡å¹¶å°è¯•å®Œæˆæ‰€æœ‰å·²å­˜åœ¨ä»»åŠ¡.
ruoyi-common/ruoyi-common-mail/src/main/java/org/dromara/common/mail/config/properties/MailProperties.java
@@ -43,7 +43,13 @@
    private String pass;
    /**
     * å‘送方,遵循RFC-822标准
     * å‘送方,遵循RFC-822标准<br>
     * å‘件人可以是以下形式:
     *
     * <pre>
     * 1. user@xxx.xx
     * 2.  name &lt;user@xxx.xx&gt;
     * </pre>
     */
    private String from;
ruoyi-common/ruoyi-common-mybatis/src/main/java/org/dromara/common/mybatis/core/page/PageQuery.java
@@ -119,4 +119,9 @@
        return (pageNum - 1) * pageSize;
    }
    public PageQuery(Integer pageSize, Integer pageNum) {
        this.pageSize = pageSize;
        this.pageNum = pageNum;
    }
}
ruoyi-common/ruoyi-common-redis/src/main/java/org/dromara/common/redis/utils/SequenceUtils.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,165 @@
package org.dromara.common.redis.utils;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.core.utils.StringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.redisson.api.RIdGenerator;
import org.redisson.api.RedissonClient;
import java.time.Duration;
/**
 * å‘号器工具类
 *
 * @author ç§‹è¾žæœªå¯’
 * @date 2024-12-10
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class SequenceUtils {
    /**
     * é»˜è®¤åˆå§‹å€¼
     */
    public static final Long DEFAULT_INIT_VALUE = 1L;
    /**
     * é»˜è®¤æ­¥é•¿
     */
    public static final Long DEFAULT_STEP_VALUE = 1L;
    /**
     * é»˜è®¤è¿‡æœŸæ—¶é—´-天
     */
    public static final Duration DEFAULT_EXPIRE_TIME_DAY = Duration.ofDays(1);
    /**
     * é»˜è®¤è¿‡æœŸæ—¶é—´-分钟
     */
    public static final Duration DEFAULT_EXPIRE_TIME_MINUTE = Duration.ofMinutes(1);
    /**
     * èŽ·å–Redisson客户端实例
     */
    private static final RedissonClient REDISSON_CLIENT = SpringUtils.getBean(RedissonClient.class);
    /**
     * èŽ·å–ID生成器
     *
     * @param key        ä¸šåŠ¡key
     * @param expireTime è¿‡æœŸæ—¶é—´
     * @param initValue  ID初始值
     * @param stepValue  ID步长
     * @return ID生成器
     */
    private static RIdGenerator getIdGenerator(String key, Duration expireTime, Long initValue, Long stepValue) {
        if (initValue == null || initValue <= 0) {
            initValue = DEFAULT_INIT_VALUE;
        }
        if (stepValue == null || stepValue <= 0) {
            stepValue = DEFAULT_STEP_VALUE;
        }
        RIdGenerator idGenerator = REDISSON_CLIENT.getIdGenerator(key);
        // è®¾ç½®è¿‡æœŸæ—¶é—´
        idGenerator.expire(expireTime);
        // è®¾ç½®åˆå§‹å€¼å’Œæ­¥é•¿
        idGenerator.tryInit(initValue, stepValue);
        return idGenerator;
    }
    /**
     * èŽ·å–æŒ‡å®šä¸šåŠ¡key的唯一id
     *
     * @param key        ä¸šåŠ¡key
     * @param expireTime è¿‡æœŸæ—¶é—´
     * @param initValue  ID初始值
     * @param stepValue  ID步长
     * @return å”¯ä¸€id
     */
    public static long nextId(String key, Duration expireTime, Long initValue, Long stepValue) {
        return getIdGenerator(key, expireTime, initValue, stepValue).nextId();
    }
    /**
     * èŽ·å–æŒ‡å®šä¸šåŠ¡key的唯一id字符串
     *
     * @param key        ä¸šåŠ¡key
     * @param expireTime è¿‡æœŸæ—¶é—´
     * @param initValue  ID初始值
     * @param stepValue  ID步长
     * @return å”¯ä¸€id
     */
    public static String nextIdStr(String key, Duration expireTime, Long initValue, Long stepValue) {
        return String.valueOf(nextId(key, expireTime, initValue, stepValue));
    }
    /**
     * èŽ·å–æŒ‡å®šä¸šåŠ¡key的唯一id (ID初始值=1,ID步长=1)
     *
     * @param key        ä¸šåŠ¡key
     * @param expireTime è¿‡æœŸæ—¶é—´
     * @return å”¯ä¸€id
     */
    public static long nextId(String key, Duration expireTime) {
        return getIdGenerator(key, expireTime, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
    }
    /**
     * èŽ·å–æŒ‡å®šä¸šåŠ¡key的唯一id字符串 (ID初始值=1,ID步长=1)
     *
     * @param key        ä¸šåŠ¡key
     * @param expireTime è¿‡æœŸæ—¶é—´
     * @return å”¯ä¸€id
     */
    public static String nextIdStr(String key, Duration expireTime) {
        return String.valueOf(nextId(key, expireTime));
    }
    /**
     * èŽ·å– yyyyMMdd å¼€å¤´çš„唯一id
     *
     * @return å”¯ä¸€id
     */
    public static String nextIdDate() {
        return nextIdDate("");
    }
    /**
     * èŽ·å– prefix + yyyyMMdd å¼€å¤´çš„唯一id
     *
     * @param prefix ä¸šåŠ¡å‰ç¼€
     * @return å”¯ä¸€id
     */
    public static String nextIdDate(String prefix) {
        // å‰ç¼€+日期 æž„建 prefixKey
        String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATE_FORMATTER));
        // èŽ·å–ä¸‹ä¸€ä¸ªid
        long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_DAY, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
        // è¿”回完整id
        return StringUtils.format("{}{}", prefixKey, nextId);
    }
    /**
     * èŽ·å– yyyyMMddHHmmss å¼€å¤´çš„唯一id
     *
     * @return å”¯ä¸€id
     */
    public static String nextIdDateTime() {
        return nextIdDateTime("");
    }
    /**
     * èŽ·å– prefix + yyyyMMddHHmmss å¼€å¤´çš„唯一id
     *
     * @param prefix ä¸šåŠ¡å‰ç¼€
     * @return å”¯ä¸€id
     */
    public static String nextIdDateTime(String prefix) {
        // å‰ç¼€+日期时间 æž„建 prefixKey
        String prefixKey = StringUtils.format("{}{}", StringUtils.blankToDefault(prefix, ""), DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_FORMATTER));
        // èŽ·å–ä¸‹ä¸€ä¸ªid
        long nextId = getIdGenerator(prefixKey, DEFAULT_EXPIRE_TIME_MINUTE, DEFAULT_INIT_VALUE, DEFAULT_STEP_VALUE).nextId();
        // è¿”回完整id
        return StringUtils.format("{}{}", prefixKey, nextId);
    }
}
ruoyi-common/ruoyi-common-satoken/src/main/java/org/dromara/common/satoken/utils/LoginHelper.java
@@ -89,6 +89,13 @@
    }
    /**
     * èŽ·å–ç”¨æˆ·id
     */
    public static String getUserIdStr() {
        return Convert.toStr(getExtra(USER_KEY));
    }
    /**
     * èŽ·å–ç”¨æˆ·è´¦æˆ·
     */
    public static String getUsername() {
ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/maxkey/AuthMaxKeyRequest.java
@@ -30,7 +30,7 @@
    }
    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
    public AuthToken getAccessToken(AuthCallback authCallback) {
        String body = doPostAuthorizationCode(authCallback.getCode());
        Dict object = JsonUtils.parseMap(body);
        // oauth/token éªŒè¯å¼‚常
@@ -51,7 +51,7 @@
    }
    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
    public AuthUser getUserInfo(AuthToken authToken) {
        String body = doGetUserInfo(authToken);
        Dict object = JsonUtils.parseMap(body);
        // oauth/token éªŒè¯å¼‚常
ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/topiam/AuthTopIamRequest.java
@@ -44,7 +44,7 @@
    }
    @Override
    protected AuthToken getAccessToken(AuthCallback authCallback) {
    public AuthToken getAccessToken(AuthCallback authCallback) {
        String body = doPostAuthorizationCode(authCallback.getCode());
        Dict object = JsonUtils.parseMap(body);
        checkResponse(object);
@@ -58,7 +58,7 @@
    }
    @Override
    protected AuthUser getUserInfo(AuthToken authToken) {
    public AuthUser getUserInfo(AuthToken authToken) {
        String body = doGetUserInfo(authToken);
        Dict object = JsonUtils.parseMap(body);
        checkResponse(object);
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisCacheController.java
@@ -1,5 +1,6 @@
package org.dromara.demo.controller;
import cn.hutool.core.thread.ThreadUtil;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.domain.R;
import org.dromara.common.redis.utils.RedisUtils;
@@ -83,11 +84,7 @@
        RedisUtils.setCacheObject(key, value);
        boolean flag = RedisUtils.expire(key, Duration.ofSeconds(10));
        System.out.println("***********" + flag);
        try {
            Thread.sleep(11 * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        ThreadUtil.sleep(11 * 1000);
        Object obj = RedisUtils.getCacheObject(key);
        return R.ok(value.equals(obj));
    }
ruoyi-modules/ruoyi-demo/src/main/java/org/dromara/demo/controller/RedisLockController.java
@@ -1,5 +1,6 @@
package org.dromara.demo.controller;
import cn.hutool.core.thread.ThreadUtil;
import com.baomidou.lock.LockInfo;
import com.baomidou.lock.LockTemplate;
import com.baomidou.lock.annotation.Lock4j;
@@ -33,13 +34,9 @@
    @Lock4j(keys = {"#key"})
    @GetMapping("/testLock4j")
    public R<String> testLock4j(String key, String value) {
        System.out.println("start:" + key + ",time:" + LocalTime.now().toString());
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end :" + key + ",time:" + LocalTime.now().toString());
        System.out.println("start:" + key + ",time:" + LocalTime.now());
        ThreadUtil.sleep(10000);
        System.out.println("end :" + key + ",time:" + LocalTime.now());
        return R.ok("操作成功", value);
    }
@@ -54,11 +51,7 @@
        }
        // èŽ·å–é”æˆåŠŸï¼Œå¤„ç†ä¸šåŠ¡
        try {
            try {
                Thread.sleep(8000);
            } catch (InterruptedException e) {
                //
            }
            ThreadUtil.sleep(8000);
            System.out.println("执行简单方法1 , å½“前线程:" + Thread.currentThread().getName());
        } finally {
            //释放锁
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
@@ -97,7 +97,7 @@
    @Log(title = "客户端管理", businessType = BusinessType.UPDATE)
    @PutMapping("/changeStatus")
    public R<Void> changeStatus(@RequestBody SysClientBo bo) {
        return toAjax(sysClientService.updateUserStatus(bo.getClientId(), bo.getStatus()));
        return toAjax(sysClientService.updateClientStatus(bo.getClientId(), bo.getStatus()));
    }
    /**
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
@@ -218,7 +218,7 @@
    @GetMapping("/optionselect")
    public R<List<SysUserVo>> optionselect(@RequestParam(required = false) Long[] userIds,
                                           @RequestParam(required = false) Long deptId) {
        return R.ok(userService.selectUserByIds(userIds == null ? null : List.of(userIds), deptId));
        return R.ok(userService.selectUserByIds(ArrayUtil.isEmpty(userIds) ? null : List.of(userIds), deptId));
    }
    /**
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
@@ -50,7 +50,7 @@
    /**
     * ä¿®æ”¹çŠ¶æ€
     */
    int updateUserStatus(String clientId, String status);
    int updateClientStatus(String clientId, String status);
    /**
     * æ ¡éªŒå¹¶æ‰¹é‡åˆ é™¤å®¢æˆ·ç«¯ç®¡ç†ä¿¡æ¯
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -26,6 +26,14 @@
    List<SysPostVo> selectPostList(SysPostBo post);
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žå²—位组
     *
     * @param userId ç”¨æˆ·ID
     * @return å²—位ID
     */
    List<SysPostVo> selectPostsByUserId(Long userId);
    /**
     * æŸ¥è¯¢æ‰€æœ‰å²—位
     *
     * @return å²—位列表
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
@@ -123,7 +123,7 @@
     */
    @CacheEvict(cacheNames = CacheNames.SYS_CLIENT, key = "#clientId")
    @Override
    public int updateUserStatus(String clientId, String status) {
    public int updateClientStatus(String clientId, String status) {
        return baseMapper.update(null,
            new LambdaUpdateWrapper<SysClient>()
                .set(SysClient::getStatus, status)
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDataScopeServiceImpl.java
@@ -38,7 +38,7 @@
     * @param roleId è§’色Id
     * @return éƒ¨é—¨Id组
     */
    @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId")
    @Cacheable(cacheNames = CacheNames.SYS_ROLE_CUSTOM, key = "#roleId", condition = "#roleId != null")
    @Override
    public String getRoleCustom(Long roleId) {
        if (ObjectUtil.isNull(roleId)) {
@@ -60,7 +60,7 @@
     * @param deptId éƒ¨é—¨Id
     * @return éƒ¨é—¨Id组
     */
    @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId")
    @Cacheable(cacheNames = CacheNames.SYS_DEPT_AND_CHILD, key = "#deptId", condition = "#deptId != null")
    @Override
    public String getDeptAndChild(Long deptId) {
        if (ObjectUtil.isNull(deptId)) {
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
@@ -1,5 +1,6 @@
package org.dromara.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.tree.Tree;
@@ -10,6 +11,7 @@
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.CacheNames;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.domain.dto.DeptDTO;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.DeptService;
import org.dromara.common.core.utils.*;
@@ -110,7 +112,7 @@
                        .setName(dept.getDeptName())
                        .setWeight(dept.getOrderNum())
                        .putExtra("disabled", SystemConstants.DISABLE.equals(dept.getStatus())));
                Tree<Long> tree = trees.stream().filter(it -> it.getId().longValue() == d.getDeptId()).findFirst().get();
                Tree<Long> tree = StreamUtils.findFirst(trees, it -> it.getId().longValue() == d.getDeptId());
                treeList.add(tree);
            }
        }
@@ -175,6 +177,31 @@
    }
    /**
     * æ ¹æ®éƒ¨é—¨ID查询部门负责人
     *
     * @param deptId éƒ¨é—¨ID,用于指定需要查询的部门
     * @return è¿”回该部门的负责人ID
     */
    @Override
    public Long selectDeptLeaderById(Long deptId) {
        SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(deptId);
        return vo.getLeader();
    }
    /**
     * æŸ¥è¯¢éƒ¨é—¨
     *
     * @return éƒ¨é—¨åˆ—表
     */
    @Override
    public List<DeptDTO> selectDeptsByList() {
        List<SysDeptVo> list = baseMapper.selectDeptList(new LambdaQueryWrapper<SysDept>()
            .select(SysDept::getDeptId, SysDept::getDeptName, SysDept::getParentId)
            .eq(SysDept::getStatus, SystemConstants.NORMAL));
        return BeanUtil.copyToList(list, DeptDTO.class);
    }
    /**
     * æ ¹æ®ID查询所有子部门数(正常状态)
     *
     * @param deptId éƒ¨é—¨ID
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
@@ -118,8 +118,7 @@
            .between(params.get("beginTime") != null && params.get("endTime") != null,
                SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"));
        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
            pageQuery.setOrderByColumn("info_id");
            pageQuery.setIsAsc("desc");
            lqw.orderByDesc(SysLogininfor::getInfoId);
        }
        Page<SysLogininforVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
@@ -53,8 +53,7 @@
    public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) {
        LambdaQueryWrapper<SysOperLog> lqw = buildQueryWrapper(operLog);
        if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
            pageQuery.setOrderByColumn("oper_id");
            pageQuery.setIsAsc("desc");
            lqw.orderByDesc(SysOperLog::getOperId);
        }
        Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -8,6 +8,7 @@
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.constant.SystemConstants;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.PostService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -34,7 +35,7 @@
 */
@RequiredArgsConstructor
@Service
public class SysPostServiceImpl implements ISysPostService {
public class SysPostServiceImpl implements ISysPostService, PostService {
    private final SysPostMapper baseMapper;
    private final SysDeptMapper deptMapper;
@@ -58,6 +59,17 @@
    }
    /**
     * æŸ¥è¯¢ç”¨æˆ·æ‰€å±žå²—位组
     *
     * @param userId ç”¨æˆ·ID
     * @return å²—位ID
     */
    @Override
    public List<SysPostVo> selectPostsByUserId(Long userId) {
        return baseMapper.selectPostsByUserId(userId);
    }
    /**
     * æ ¹æ®æŸ¥è¯¢æ¡ä»¶æž„建查询包装器
     *
     * @param bo æŸ¥è¯¢æ¡ä»¶å¯¹è±¡
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -17,6 +17,7 @@
import org.dromara.common.core.constant.TenantConstants;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.service.RoleService;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StreamUtils;
import org.dromara.common.core.utils.StringUtils;
@@ -47,7 +48,7 @@
 */
@RequiredArgsConstructor
@Service
public class SysRoleServiceImpl implements ISysRoleService {
public class SysRoleServiceImpl implements ISysRoleService, RoleService {
    private final SysRoleMapper baseMapper;
    private final SysRoleMenuMapper roleMenuMapper;
@@ -351,7 +352,7 @@
    private int insertRoleMenu(SysRoleBo role) {
        int rows = 1;
        // æ–°å¢žç”¨æˆ·ä¸Žè§’色管理
        List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
        List<SysRoleMenu> list = new ArrayList<>();
        for (Long menuId : role.getMenuIds()) {
            SysRoleMenu rm = new SysRoleMenu();
            rm.setRoleId(role.getRoleId());
@@ -372,7 +373,7 @@
    private int insertRoleDept(SysRoleBo role) {
        int rows = 1;
        // æ–°å¢žè§’色与部门(数据权限)管理
        List<SysRoleDept> list = new ArrayList<SysRoleDept>();
        List<SysRoleDept> list = new ArrayList<>();
        for (Long deptId : role.getDeptIds()) {
            SysRoleDept rd = new SysRoleDept();
            rd.setRoleId(role.getRoleId());
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -696,4 +696,27 @@
            .in(SysUser::getDeptId, deptIds));
        return BeanUtil.copyToList(list, UserDTO.class);
    }
    /**
     * é€šè¿‡å²—位ID查询用户
     *
     * @param postIds å²—位ids
     * @return ç”¨æˆ·
     */
    @Override
    public List<UserDTO> selectUsersByPostIds(List<Long> postIds) {
        if (CollUtil.isEmpty(postIds)) {
            return List.of();
        }
        // é€šè¿‡å²—位ID获取用户岗位信息
        List<SysUserPost> userPosts = userPostMapper.selectList(
            new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getPostId, postIds));
        // èŽ·å–ç”¨æˆ·ID列表
        Set<Long> userIds = StreamUtils.toSet(userPosts, SysUserPost::getUserId);
        return selectListByIds(new ArrayList<>(userIds));
    }
}