Sfoglia il codice sorgente

update 日志修复

ct 1 settimana fa
parent
commit
ffbce1fab2

+ 97 - 0
fs-admin-saas/src/main/java/com/fs/company/CompanyOperLogController.java

@@ -0,0 +1,97 @@
+package com.fs.company;
+
+import com.fs.common.annotation.Log;
+import com.fs.common.core.controller.BaseController;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.core.page.TableDataInfo;
+import com.fs.common.enums.BusinessType;
+import com.fs.common.utils.poi.ExcelUtil;
+import com.fs.company.domain.CompanyOperLog;
+import com.fs.company.service.ICompanyOperLogService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 操作日志记录Controller
+ *
+ * @author fs
+ * @date 2021-10-04
+ */
+@RestController
+@RequestMapping("/company/companyOperLog")
+public class CompanyOperLogController extends BaseController
+{
+    @Autowired
+    private ICompanyOperLogService companyOperLogService;
+
+    /**
+     * 查询操作日志记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(CompanyOperLog companyOperLog)
+    {
+        startPage();
+        List<CompanyOperLog> list = companyOperLogService.selectCompanyOperLogList(companyOperLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出操作日志记录列表
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:export')")
+    @Log(title = "操作日志记录", businessType = BusinessType.EXPORT)
+    @GetMapping("/export")
+    public AjaxResult export(CompanyOperLog companyOperLog)
+    {
+        List<CompanyOperLog> list = companyOperLogService.selectCompanyOperLogList(companyOperLog);
+        ExcelUtil<CompanyOperLog> util = new ExcelUtil<CompanyOperLog>(CompanyOperLog.class);
+        return util.exportExcel(list, "companyOperLog");
+    }
+
+    /**
+     * 获取操作日志记录详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:query')")
+    @GetMapping(value = "/{operId}")
+    public AjaxResult getInfo(@PathVariable("operId") Long operId)
+    {
+        return AjaxResult.success(companyOperLogService.selectCompanyOperLogById(operId));
+    }
+
+    /**
+     * 新增操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:add')")
+    @Log(title = "操作日志记录", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody CompanyOperLog companyOperLog)
+    {
+        return toAjax(companyOperLogService.insertCompanyOperLog(companyOperLog));
+    }
+
+    /**
+     * 修改操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:edit')")
+    @Log(title = "操作日志记录", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody CompanyOperLog companyOperLog)
+    {
+        return toAjax(companyOperLogService.updateCompanyOperLog(companyOperLog));
+    }
+
+    /**
+     * 删除操作日志记录
+     */
+    @PreAuthorize("@ss.hasPermi('company:companyOperLog:remove')")
+    @Log(title = "操作日志记录", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(companyOperLogService.deleteCompanyOperLogByIds(operIds));
+    }
+}

+ 3 - 2
fs-admin-saas/src/main/java/com/fs/qw/controller/QwUserController.java

@@ -434,14 +434,15 @@ public class QwUserController extends BaseController {
         }
         catch (Exception e)
         {
+            Long tenantId = com.fs.common.utils.SecurityUtils.getTenantId();
             if (e instanceof BadCredentialsException)
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(param.getCompanyAdmin(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, param.getCompanyAdmin(), Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                 throw new UserPasswordNotMatchException();
             }
             else
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(param.getCompanyAdmin(), Constants.LOGIN_FAIL, e.getMessage()));
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, param.getCompanyAdmin(), Constants.LOGIN_FAIL, e.getMessage()));
                 throw new ServiceException(e.getMessage());
             }
         }

+ 2 - 1
fs-framework/src/main/java/com/fs/framework/aspectj/LogAspect.java

@@ -129,7 +129,8 @@ public class LogAspect
             // 处理设置注解上的参数
             getControllerMethodDescription(joinPoint, controllerLog, operLog);
             // 保存数据库
-            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
+            Long tenantId = loginUser != null ? loginUser.getTenantId() : null;
+            AsyncManager.me().execute(AsyncFactory.recordOper(tenantId, operLog));
             if(controllerLog.isStoreLog() ){
                 SysOperLogScrm operLogScrm = new SysOperLogScrm();
                 //插入operId

+ 69 - 55
fs-framework/src/main/java/com/fs/framework/manager/factory/AsyncFactory.java

@@ -1,5 +1,6 @@
 package com.fs.framework.manager.factory;
 
+import java.util.Date;
 import java.util.TimerTask;
 
 import com.fs.hisStore.domain.SysOperLogScrm;
@@ -7,12 +8,15 @@ import com.fs.hisStore.service.ISysOperLogScrmService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import com.fs.common.constant.Constants;
+import com.fs.common.enums.DataSourceType;
 import com.fs.common.utils.LogUtils;
 import com.fs.common.utils.ServletUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.common.utils.ip.AddressUtils;
 import com.fs.common.utils.ip.IpUtils;
 import com.fs.common.utils.spring.SpringUtils;
+import com.fs.framework.datasource.DynamicDataSourceContextHolder;
+import com.fs.framework.datasource.TenantDataSourceManager;
 import com.fs.system.domain.SysLogininfor;
 import com.fs.system.domain.SysOperLog;
 import com.fs.system.service.ISysLogininforService;
@@ -21,24 +25,22 @@ import eu.bitwalker.useragentutils.UserAgent;
 
 /**
  * 异步工厂(产生任务用)
- *
-
  */
 public class AsyncFactory
 {
     private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
 
-    /**
-     * 记录登录信息
-     *
-     * @param username 用户名
-     * @param status 状态
-     * @param message 消息
-     * @param args 列表
-     * @return 任务task
-     */
     public static TimerTask recordLogininfor(final String username, final String status, final String message,
             final Object... args)
+    {
+        return recordLogininfor(null, username, status, message, args);
+    }
+
+    /**
+     * 记录登录信息(多租户场景需传 tenantId,异步任务内切租户库写 sys_logininfor)
+     */
+    public static TimerTask recordLogininfor(final Long tenantId, final String username, final String status,
+            final String message, final Object... args)
     {
         final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
         final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
@@ -54,61 +56,56 @@ public class AsyncFactory
                 s.append(LogUtils.getBlock(username));
                 s.append(LogUtils.getBlock(status));
                 s.append(LogUtils.getBlock(message));
-                // 打印信息到日志
                 sys_user_logger.info(s.toString(), args);
-                // 获取客户端操作系统
-                String os = userAgent.getOperatingSystem().getName();
-                // 获取客户端浏览器
-                String browser = userAgent.getBrowser().getName();
-                // 封装对象
-                SysLogininfor logininfor = new SysLogininfor();
-                logininfor.setUserName(username);
-                logininfor.setIpaddr(ip);
-                logininfor.setLoginLocation(address);
-                logininfor.setBrowser(browser);
-                logininfor.setOs(os);
-                logininfor.setMsg(message);
-                // 日志状态
-                if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
-                {
-                    logininfor.setStatus(Constants.SUCCESS);
-                }
-                else if (Constants.LOGIN_FAIL.equals(status))
-                {
-                    logininfor.setStatus(Constants.FAIL);
-                }
-                // 插入数据
-                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
+
+                executeWithTenantDatasource(tenantId, () -> {
+                    String os = userAgent.getOperatingSystem().getName();
+                    String browser = userAgent.getBrowser().getName();
+                    SysLogininfor logininfor = new SysLogininfor();
+                    logininfor.setUserName(username);
+                    logininfor.setIpaddr(ip);
+                    logininfor.setLoginLocation(address);
+                    logininfor.setBrowser(browser);
+                    logininfor.setOs(os);
+                    logininfor.setMsg(message);
+                    logininfor.setLoginTime(new Date());
+                    if (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
+                    {
+                        logininfor.setStatus(Constants.SUCCESS);
+                    }
+                    else if (Constants.LOGIN_FAIL.equals(status))
+                    {
+                        logininfor.setStatus(Constants.FAIL);
+                    }
+                    SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
+                });
             }
         };
     }
 
+    public static TimerTask recordOper(final SysOperLog operLog)
+    {
+        return recordOper(null, operLog);
+    }
+
     /**
-     * 操作日志记录
-     *
-     * @param operLog 操作日志信息
-     * @return 任务task
+     * 操作日志记录(多租户场景需传 tenantId)
      */
-    public static TimerTask recordOper(final SysOperLog operLog)
+    public static TimerTask recordOper(final Long tenantId, final SysOperLog operLog)
     {
         return new TimerTask()
         {
             @Override
             public void run()
             {
-                // 远程查询操作地点
-                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
-                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
+                executeWithTenantDatasource(tenantId, () -> {
+                    operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
+                    SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
+                });
             }
         };
     }
 
-    /**
-     * 操作日志记录
-     *
-     * @param operLog 操作日志信息
-     * @return 任务task
-     */
     public static TimerTask recordOperScrm(final SysOperLogScrm operLog)
     {
         return new TimerTask()
@@ -116,16 +113,33 @@ public class AsyncFactory
             @Override
             public void run()
             {
-                // 远程查询操作地点
                 operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
                 SpringUtils.getBean(ISysOperLogScrmService.class).updateOperLog(operLog);
             }
         };
     }
 
-    /**
-     * 生成日志记录
-     * */
-
-
+    private static void executeWithTenantDatasource(Long tenantId, Runnable action)
+    {
+        if (tenantId == null)
+        {
+            action.run();
+            return;
+        }
+        TenantDataSourceManager tenantDataSourceManager = SpringUtils.getBean(TenantDataSourceManager.class);
+        try
+        {
+            tenantDataSourceManager.ensureSwitchByTenantId(tenantId);
+            action.run();
+        }
+        catch (Exception ex)
+        {
+            sys_user_logger.warn("租户异步写库失败 tenantId={}: {}", tenantId, ex.getMessage());
+        }
+        finally
+        {
+            tenantDataSourceManager.clear();
+            DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        }
+    }
 }

+ 1 - 1
fs-framework/src/main/java/com/fs/framework/security/handle/LogoutSuccessHandlerImpl.java

@@ -46,7 +46,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
             // 删除用户缓存记录
             tokenService.delLoginUser(loginUser.getToken());
             // 记录用户退出日志
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "退出成功"));
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(loginUser.getTenantId(), userName, Constants.LOGOUT, "退出成功"));
         }
         ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "退出成功")));
     }

+ 27 - 23
fs-framework/src/main/java/com/fs/framework/web/service/SysLoginService.java

@@ -86,11 +86,11 @@ public class SysLoginService
      */
     public String login(String username, String password, String code, String uuid, String tenantCode)
     {
+        Long tenantId = resolveTenantIdQuiet(tenantCode);
         boolean captchaOnOff = configService.selectCaptchaOnOff();
-        // 验证码开关
         if (captchaOnOff)
         {
-            validateCaptcha(username, code, uuid);
+            validateCaptcha(username, code, uuid, tenantId);
         }
 
         TenantInfo tenantInfo = null;
@@ -101,7 +101,6 @@ public class SysLoginService
         // ===== 只有传了 tenantCode 才查询租户并切库 =====
         if (StringUtils.isNotBlank(tenantCode))
         {
-            // 查询租户(主库)
             tenantInfo = userService.getTenantInfo(tenantCode);
             if (BeanUtil.isEmpty(tenantInfo)) {
                 throw new ServiceException("企业不存在");
@@ -111,27 +110,25 @@ public class SysLoginService
                 throw new ServiceException("企业已禁用");
             }
 
-            // 切租户库
+            tenantId = tenantInfo.getId();
             tenantDataSourceManager.switchTenant(tenantInfo);
         }
 
         try {
-            // 用户验证
             Authentication authentication = null;
             try {
-                // 该方法会去调用 UserDetailsServiceImpl.loadUserByUsername
                 authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
             } catch (Exception e) {
                 if (e instanceof BadCredentialsException) {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                     throw new UserPasswordNotMatchException();
                 } else {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, e.getMessage()));
                     throw new ServiceException(e.getMessage());
                 }
             }
 
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
 
             LoginUser loginUser = (LoginUser) authentication.getPrincipal();
 
@@ -165,19 +162,19 @@ public class SysLoginService
      * @param uuid 唯一标识
      * @return 结果
      */
-    public void validateCaptcha(String username, String code, String uuid)
+    public void validateCaptcha(String username, String code, String uuid, Long tenantId)
     {
         String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
         String captcha = redisCache.getCacheObject(verifyKey);
         redisCache.deleteObject(verifyKey);
         if (captcha == null)
         {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
             throw new CaptchaExpireException();
         }
         if (!code.equalsIgnoreCase(captcha))
         {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
             throw new CaptchaException();
         }
     }
@@ -207,7 +204,7 @@ public class SysLoginService
 
     public boolean checkIsNeedCheck(String username, String password, String code, String uuid, String tenantCode)
     {
-        // 验证码开关
+        Long tenantId = resolveTenantIdQuiet(tenantCode);
         boolean captchaOnOff = configService.selectCaptchaOnOff();
         if (captchaOnOff)
         {
@@ -217,23 +214,21 @@ public class SysLoginService
 
             if (captcha == null)
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
                 throw new CaptchaExpireException();
             }
 
             if (!code.equalsIgnoreCase(captcha))
             {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
                 throw new CaptchaException();
             }
         }
 
         TenantInfo tenantInfo = null;
 
-        // 默认使用主库
         DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
-        
-        // 查询租户(主库)
+
         tenantInfo = userService.getTenantInfo(tenantCode);
         if (BeanUtil.isEmpty(tenantInfo))
         {
@@ -244,23 +239,21 @@ public class SysLoginService
             throw new ServiceException("企业已禁用");
         }
 
-        // 切到租户库
+        tenantId = tenantInfo.getId();
         tenantDataSourceManager.switchTenant(tenantInfo);
 
-
         try
         {
-            // 用户验证
             Authentication authentication = null;
             try {
                 authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(username, password));
             } catch (Exception e)
             {
                 if (e instanceof BadCredentialsException) {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
                     throw new UserPasswordNotMatchException();
                 } else {
-                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                    AsyncManager.me().execute(AsyncFactory.recordLogininfor(tenantId, username, Constants.LOGIN_FAIL, e.getMessage()));
                     throw new ServiceException(e.getMessage());
                 }
             }
@@ -415,4 +408,15 @@ public class SysLoginService
 
         redisCache.setCacheObject("wechat:scan:" + ticket, "ok", 30, TimeUnit.SECONDS);
     }
+
+    private Long resolveTenantIdQuiet(String tenantCode)
+    {
+        if (StringUtils.isBlank(tenantCode))
+        {
+            return null;
+        }
+        DynamicDataSourceContextHolder.setDataSourceType(DataSourceType.MASTER.name());
+        TenantInfo tenantInfo = userService.getTenantInfo(tenantCode);
+        return BeanUtil.isEmpty(tenantInfo) ? null : tenantInfo.getId();
+    }
 }