Procházet zdrojové kódy

Merge branch 'system-zjy' of uskycloud/usky-cloud into system-165

hanzhengyi před 5 měsíci
rodič
revize
3ed3588869

+ 82 - 50
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/controller/web/SysUserOnlineController.java

@@ -1,12 +1,9 @@
 package com.usky.system.controller.web;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-
+import java.util.*;
 import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.constants.CacheConstants;
+import com.usky.common.core.utils.StringUtils;
 import com.usky.common.log.annotation.Log;
 import com.usky.common.log.enums.BusinessType;
 import com.usky.common.redis.core.RedisService;
@@ -15,13 +12,10 @@ import com.usky.system.controller.web.page.TableDataInfo;
 import com.usky.system.domain.SysUserOnline;
 import com.usky.system.model.LoginUser;
 import com.usky.system.service.ISysUserOnlineService;
-import org.apache.commons.lang3.StringUtils;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
-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 org.springframework.web.bind.annotation.*;
+import org.slf4j.Logger;
 
 /**
  * 在线用户监控
@@ -29,63 +23,101 @@ import org.springframework.web.bind.annotation.RestController;
  */
 @RestController
 @RequestMapping("/online")
-public class SysUserOnlineController extends BaseController
-{
+public class SysUserOnlineController {
+    private final Logger logger = LoggerFactory.getLogger(SysUserOnlineController.class);
+
     @Autowired
     private ISysUserOnlineService userOnlineService;
 
     @Autowired
     private RedisService redisService;
 
-    @RequiresPermissions("monitor:online:list")
+    private TableDataInfo getDataTable(List<SysUserOnline> userOnlineList, int pageNum, int pageSize, long total) {
+        TableDataInfo dataInfo = new TableDataInfo();
+        dataInfo.setRows(userOnlineList);
+        dataInfo.setTotal(total);
+        dataInfo.setPageNum(pageNum);
+        dataInfo.setPageSize(pageSize);
+        dataInfo.setPages((int) Math.ceil((double) total / pageSize));
+        return dataInfo;
+    }
+
     @GetMapping("/list")
-    public ApiResult<TableDataInfo> list(String ipaddr, String userName)
-    {
-        Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
-        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
-        for (String key : keys)
-        {
-            LoginUser user = redisService.getCacheObject(key);
-            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
-            {
-                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
-                }
-            }
-            else if (StringUtils.isNotEmpty(ipaddr))
-            {
-                if (StringUtils.equals(ipaddr, user.getIpaddr()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
-                }
+    public ApiResult<TableDataInfo> list(@RequestParam(required = false, defaultValue = "1") Integer page,
+                                         @RequestParam(required = false, defaultValue = "10") Integer size) {
+        try {
+            Collection<String> keys = redisService.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+            if (keys == null || keys.isEmpty()) {
+                logger.error("Redis keys is null or empty");
+                return ApiResult.error("SYS-0000", "Redis keys is null or empty");
             }
-            else if (StringUtils.isNotEmpty(userName))
-            {
-                if (StringUtils.equals(userName, user.getUsername()))
-                {
-                    userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+            Map<String, List<SysUserOnline>> userOnlineMap = new HashMap<>();
+
+            for (String key : keys) {
+                // 检查键是否存在并且未过期
+                if (redisService.hasKey(key)) {
+                    LoginUser user = redisService.getCacheObject(key);
+                    if (user != null) {
+                        SysUserOnline online = userOnlineService.loginUserToUserOnline(user);
+                        if (online != null) {
+                            List<SysUserOnline> list = userOnlineMap.computeIfAbsent(user.getUsername(), k -> new ArrayList<>());
+                            list.add(online);
+                        }
+                    }
                 }
             }
-            else
-            {
-                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+
+            List<SysUserOnline> userOnlineList = new ArrayList<>();
+            for (Map.Entry<String, List<SysUserOnline>> entry : userOnlineMap.entrySet()) {
+                List<SysUserOnline> sortedList = entry.getValue();
+                sortedList.sort(Comparator.comparing(SysUserOnline::getLoginTime).reversed());
+                int loginCount = sortedList.size(); // 计算登录次数
+                SysUserOnline lastOnline = sortedList.get(0); // 取最后登录时间的记录
+                lastOnline.setLoginCount(loginCount); // 设置登录记录的数量
+                lastOnline.setPreviousOnlines(sortedList.subList(1, sortedList.size())); // 设置其他登录记录
+                userOnlineList.add(lastOnline);
             }
+
+            // 按照登录时间降序排序
+            userOnlineList.sort(Comparator.comparing(SysUserOnline::getLoginTime).reversed());
+
+            long total = userOnlineList.size();
+            int start = (page - 1) * size;
+            int end = Math.min(start + size, (int) total);
+            List<SysUserOnline> pageList = userOnlineList.subList(start, end);
+
+            return ApiResult.success(getDataTable(pageList, page, size, total));
+        } catch (Exception ex) {
+            logger.error("Error processing /online/list", ex);
+            return ApiResult.error("SYS-0001", "Internal system error", ex.getMessage());
         }
-        Collections.reverse(userOnlineList);
-        userOnlineList.removeAll(Collections.singleton(null));
-        return ApiResult.success(getDataTable(userOnlineList));
     }
 
     /**
      * 强退用户
      */
-    @RequiresPermissions("monitor:online:forceLogout")
+//    @RequiresPermissions("monitor:online:forceLogout")
     @Log(title = "在线用户", businessType = BusinessType.FORCE)
     @DeleteMapping("/{tokenId}")
-    public ApiResult forceLogout(@PathVariable String tokenId)
-    {
-        redisService.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
-        return ApiResult.success();
+    public ApiResult forceLogout(@PathVariable String tokenId) {
+        try {
+            if (StringUtils.isBlank(tokenId)) {
+                logger.error("Token ID is blank for force logout");
+                return ApiResult.error("SYS-0004", "Token ID is required for force logout");
+            }
+
+            String key = CacheConstants.LOGIN_TOKEN_KEY + tokenId;
+            boolean deleted = redisService.deleteObject(key);
+            if (deleted) {
+                logger.info("User with tokenId {} has been forcibly logged out.", tokenId);
+                return ApiResult.success();
+            } else {
+                logger.warn("Failed to find and delete user session with tokenId {}", tokenId);
+                return ApiResult.error("SYS-0002", "Session not found or already deleted");
+            }
+        } catch (Exception ex) {
+            logger.error("Error processing forceLogout for tokenId {}", tokenId, ex);
+            return ApiResult.error("SYS-0003", "Internal system error during force logout", ex.getMessage());
+        }
     }
 }

+ 39 - 0
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/controller/web/page/TableDataInfo.java

@@ -29,6 +29,21 @@ public class TableDataInfo implements Serializable {
      */
     private String msg;
 
+    /**
+     * 当前页码
+     */
+    private int pageNum;
+
+    /**
+     * 每页记录数
+     */
+    private int pageSize;
+
+    /**
+     * 总页数
+     */
+    private int pages;
+
     /**
      * 表格数据对象
      */
@@ -77,4 +92,28 @@ public class TableDataInfo implements Serializable {
     public void setMsg(String msg) {
         this.msg = msg;
     }
+
+    public int getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(int pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public int getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(int pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public int getPages() {
+        return pages;
+    }
+
+    public void setPages(int pages) {
+        this.pages = pages;
+    }
 }

+ 78 - 29
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/domain/SysUserOnline.java

@@ -1,15 +1,20 @@
 package com.usky.system.domain;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * 当前在线会话
  * 
  * @author yq
  */
-public class SysUserOnline
-{
+public class SysUserOnline {
     /** 会话编号 */
     private String tokenId;
 
+    /** 用户ID */
+    private Long userid;
+
     /** 部门名称 */
     private String deptName;
 
@@ -31,68 +36,79 @@ public class SysUserOnline
     /** 登录时间 */
     private Long loginTime;
 
-    public String getTokenId()
-    {
+    /** 最后访问时间 */
+    private Long expireTime;
+
+    /** 登录记录的数量 */
+    private int loginCount;
+
+
+    private SysUserOnline lastOnline;
+    private List<SysUserOnline> previousOnlines;
+
+    public SysUserOnline() {
+        // 初始化默认值
+        this.lastOnline = null;
+        this.previousOnlines = new ArrayList<>();
+    }
+
+    public String getTokenId() {
         return tokenId;
     }
 
-    public void setTokenId(String tokenId)
-    {
+    public void setTokenId(String tokenId) {
         this.tokenId = tokenId;
     }
 
-    public String getDeptName()
-    {
+    public Long getUserid() {
+        return userid;
+    }
+
+    public void setUserid(Long userid) {
+        this.userid = userid;
+    }
+
+    public String getDeptName() {
         return deptName;
     }
 
-    public void setDeptName(String deptName)
-    {
+    public void setDeptName(String deptName) {
         this.deptName = deptName;
     }
 
-    public String getUserName()
-    {
+    public String getUserName() {
         return userName;
     }
 
-    public void setUserName(String userName)
-    {
+    public void setUserName(String userName) {
         this.userName = userName;
     }
 
-    public String getIpaddr()
-    {
+    public String getIpaddr() {
         return ipaddr;
     }
 
-    public void setIpaddr(String ipaddr)
-    {
+    public void setIpaddr(String ipaddr) {
         this.ipaddr = ipaddr;
     }
 
-    public String getLoginLocation()
-    {
+    public String getLoginLocation() {
         return loginLocation;
     }
 
-    public void setLoginLocation(String loginLocation)
-    {
+    public void setLoginLocation(String loginLocation) {
         this.loginLocation = loginLocation;
     }
 
-    public String getBrowser()
-    {
+    public String getBrowser() {
         return browser;
     }
 
-    public void setBrowser(String browser)
-    {
+    public void setBrowser(String browser) {
         this.browser = browser;
     }
 
-    public String getOs()
-    {
+    public String getOs() {
         return os;
     }
 
@@ -110,4 +126,37 @@ public class SysUserOnline
     {
         this.loginTime = loginTime;
     }
-}
+
+    public Long getExpireTime() {
+        return expireTime;
+    }
+
+    public void setExpireTime(Long expireTime) {
+        this.expireTime = expireTime;
+    }
+
+
+    public SysUserOnline getLastOnline() {
+        return lastOnline;
+    }
+
+    public void setLastOnline(SysUserOnline lastOnline) {
+        this.lastOnline = lastOnline;
+    }
+
+    public List<SysUserOnline> getPreviousOnlines() {
+        return previousOnlines;
+    }
+
+    public void setPreviousOnlines(List<SysUserOnline> previousOnlines) {
+        this.previousOnlines = previousOnlines;
+    }
+
+    public int getLoginCount() {
+        return loginCount;
+    }
+
+    public void setLoginCount(int loginCount) {
+        this.loginCount = loginCount;
+    }
+}

+ 2 - 0
base-modules/service-system/service-system-biz/src/main/java/com/usky/system/service/impl/SysUserOnlineServiceImpl.java

@@ -85,9 +85,11 @@ public class SysUserOnlineServiceImpl implements ISysUserOnlineService
         }
         SysUserOnline sysUserOnline = new SysUserOnline();
         sysUserOnline.setTokenId(user.getToken());
+        sysUserOnline.setUserid(user.getUserid());
         sysUserOnline.setUserName(user.getUsername());
         sysUserOnline.setIpaddr(user.getIpaddr());
         sysUserOnline.setLoginTime(user.getLoginTime());
+        sysUserOnline.setExpireTime(user.getExpireTime());
         return sysUserOnline;
     }
 }

+ 4 - 0
usky-common/usky-common-core/src/main/java/com/usky/common/core/bean/ApiResult.java

@@ -62,6 +62,10 @@ public class ApiResult<T> implements Serializable {
         return new ApiResult<>(null);
     }
 
+    public static <T> ApiResult<T> error(String message) {
+        return new ApiResult<>("9999", message);
+    }
+
     public static <T> ApiResult<T> error(String code, String message) {
         return new ApiResult<>(code, message);
     }

+ 5 - 4
usky-common/usky-common-log/src/main/java/com/usky/common/log/aspect/LogAspect.java

@@ -7,7 +7,6 @@ import java.util.Objects;
 import java.util.concurrent.TimeUnit;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import javax.xml.crypto.Data;
 
 import com.alibaba.fastjson.JSON;
 import com.usky.common.core.util.IpUtils;
@@ -42,11 +41,13 @@ public class LogAspect {
     @Autowired
     private AsyncLogService asyncLogService;
 
-    @Pointcut("@annotation(controllerLog)")
-    public void logPointcut(Log controllerLog) {
+    // 定义切入点,使用@annotation指示器
+    @Pointcut("@annotation(com.usky.common.log.annotation.Log)")
+    public void logPointcut() {
     }
 
-    @Around("logPointcut(controllerLog)")
+    // 环绕通知,引用切入点并传递注解实例
+    @Around("logPointcut() && @annotation(controllerLog)")
     public Object aroundLog(ProceedingJoinPoint joinPoint, Log controllerLog) throws Throwable {
         Date startTime = new Date();
         Object result = null;

+ 1 - 1
usky-common/usky-common-log/src/main/java/com/usky/common/log/service/AsyncLogService.java

@@ -15,7 +15,7 @@ import org.springframework.stereotype.Service;
 @Service
 public class AsyncLogService
 {
-    @Qualifier("sysLogControllerApi")
+    @Qualifier("com.usky.system.RemoteLogService")
     @Autowired
     private RemoteLogService remoteLogService;
 

+ 17 - 4
usky-common/usky-common-security/src/main/java/com/usky/common/security/auth/AuthLogic.java

@@ -1,5 +1,6 @@
 package com.usky.common.security.auth;
 
+import com.usky.common.core.bean.ApiResult;
 import com.usky.common.core.util.SpringContextUtils;
 import com.usky.common.security.annotation.Logical;
 import com.usky.common.security.annotation.RequiresLogin;
@@ -13,9 +14,11 @@ import com.usky.common.security.utils.SecurityUtils;
 import com.usky.system.model.LoginUser;
 import org.springframework.util.PatternMatchUtils;
 import org.springframework.util.StringUtils;
+import org.springframework.web.bind.annotation.ExceptionHandler;
 
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 /**
@@ -109,14 +112,20 @@ public class AuthLogic
      * @param permission 权限字符串
      * @return 用户是否具备某权限
      */
-    public boolean hasPermi(String permission)
-    {
-        return hasPermi(getPermiList(), permission);
+    public boolean hasPermi(List<String> permissions, String permission) {
+        if (permissions == null || permission == null) {
+            return false;
+        }
+        return permissions.stream().anyMatch(p -> p.equals(permission));
+    }
+    @ExceptionHandler(NotPermissionException.class)
+    public ApiResult<Void> handleNotPermissionException(NotPermissionException ex) {
+        return ApiResult.error("您没有权限执行这个操作");
     }
 
     /**
      * 验证用户是否具备某权限, 如果验证未通过,则抛出异常: NotPermissionException
-     * 
+     *
      * @param permission 权限字符串
      * @return 用户是否具备某权限
      */
@@ -369,4 +378,8 @@ public class AuthLogic
         return roles.stream().filter(StringUtils::hasText)
                 .anyMatch(x -> SUPER_ADMIN.contains(x) || PatternMatchUtils.simpleMatch(x, role));
     }
+
+    public boolean hasPermi(String permission) {
+        return hasPermi(getPermiList(), permission);
+    }
 }