From ecfee76c8d799aca0f437a3b0377a1e813591493 Mon Sep 17 00:00:00 2001 From: zt Date: Wed, 7 May 2025 11:13:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../web/controller/common/SseController.java | 5 ++ .../web/controller/wgz/WgzAppController.java | 1 + .../com/ruoyi/common/constant/Constants.java | 14 ++++++ .../framework/config/SecurityConfig.java | 4 +- .../handle/AuthenticationEntryPointImpl.java | 4 +- .../handle/LogoutSuccessHandlerImpl.java | 3 +- .../framework/web/service/TokenService.java | 36 +++++++++++++-- .../web/service/UserDetailsServiceImpl.java | 3 +- .../BgtProjectRecruitApplyServiceImpl.java | 46 +++++++++++-------- .../java/com/ruoyi/common/util/SseUtil.java | 32 +++++++++++-- .../impl/WgzPayCalculationServiceImpl.java | 1 - 11 files changed, 115 insertions(+), 34 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SseController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SseController.java index 69eafbf..7a60908 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SseController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SseController.java @@ -1,6 +1,8 @@ package com.ruoyi.web.controller.common; +import cn.hutool.core.util.StrUtil; import com.ruoyi.common.util.SseUtil; +import com.ruoyi.common.utils.SecurityUtils; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; @@ -17,6 +19,9 @@ public class SseController { */ @GetMapping(path = "/subscribe", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public SseEmitter subscribe(String userId,String prefix) { + if(StrUtil.isBlank(userId)){ + userId = SecurityUtils.getAppUserId().toString(); + } return SseUtil.subscribe(userId,prefix); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wgz/WgzAppController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wgz/WgzAppController.java index f84471b..82d03ec 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wgz/WgzAppController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/wgz/WgzAppController.java @@ -400,6 +400,7 @@ */ @ApiOperation("【首页】【招工列表】【项目详情】 项目详情·申请报名)") //@PreAuthorize("@ss.hasPermi('wgzApp:user:userApplyForRegistration')") + @RepeatSubmit @GetMapping("/WgzAppUserApplyForRegistration/{id}") public AjaxResult userApplyForRegistration(@NotNull(message = "主键不能为空") @PathVariable("id") Long id) { return AjaxResult.success(iBgtProjectRecruitApplyService.userApplyForRegistration(id)); diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java index d2f1330..681eab2 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java @@ -86,6 +86,20 @@ public class Constants * 令牌前缀 */ public static final String LOGIN_USER_KEY = "login_user_key"; + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_TYPE = "login_user_type"; + + /** + * 令牌前缀 + */ + public static final String LOGIN_USER_ID = "login_user_id"; + + /** + * 令牌前缀 + */ + public static final String LOGIN_TYEO_SYS = "sys"; /** * 用户ID diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java index 98ee3e9..2a6fd90 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java @@ -101,8 +101,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter // 过滤请求 .authorizeRequests() // 对于登录login 验证码captchaImage 允许匿名访问 - .antMatchers("/login", "/app/login", "/captchaImage","/demo/tress/all").anonymous() - .antMatchers("/app/login","/wgz/app/wgzRegister", + .antMatchers("/login", "/captchaImage","/demo/tress/all").anonymous() + .antMatchers("/app/login","/wgz/app/wgzRegister","/sse/subscribe", "/app/bgt/recruit/htmlList","/app/bgt/apply/htmlList","/common/annex/getHtmlWgzAnnex" ,"/download-folders","/upload-zip").permitAll() .antMatchers( diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java index 1cd8d60..fa50c40 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java @@ -28,8 +28,10 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException { + int code = HttpStatus.HTTP_UNAUTHORIZED; - String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); +// String msg = StrUtil.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI()); + String msg = StrUtil.format("登录过期或其他设备登录"); ServletUtils.renderString(response, JsonUtils.toJsonString(AjaxResult.error(code, msg))); } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java index 2a12126..24ab927 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java @@ -43,7 +43,8 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { if (Validator.isNotNull(loginUser)) { String userName = loginUser.getUsername(); // 删除用户缓存记录 - tokenService.delLoginUser(loginUser.getToken()); +// tokenService.delLoginUser(loginUser.getToken()); + tokenService.delLoginUser(loginUser.getUserType(),loginUser.getUser().getUserId().toString()); // 记录用户退出日志 asyncService.recordLogininfor(userName, Constants.LOGOUT, "退出成功", request); } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java index f834570..45b93c3 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java @@ -7,12 +7,15 @@ import cn.hutool.http.useragent.UserAgentUtil; import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.core.redis.RedisCache; +import com.ruoyi.common.exception.BaseException; import com.ruoyi.common.utils.ServletUtils; import com.ruoyi.common.utils.ip.AddressUtils; import com.ruoyi.framework.config.properties.TokenProperties; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -29,6 +32,8 @@ import java.util.concurrent.TimeUnit; @Component public class TokenService { + private static final Logger log = LoggerFactory.getLogger(TokenService.class); + protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; @@ -48,13 +53,23 @@ public class TokenService { */ public LoginUser getLoginUser(HttpServletRequest request) { // 获取请求携带的令牌 + + String token = getToken(request); +// log.info("用户当前token:{}", token); if (Validator.isNotEmpty(token)) { Claims claims = parseToken(token); // 解析对应的权限以及用户信息 String uuid = (String) claims.get(Constants.LOGIN_USER_KEY); - String userKey = getTokenKey(uuid); - LoginUser user = redisCache.getCacheObject(userKey); + //String userKey = getTokenKey(uuid); + String type = (String) claims.get(Constants.LOGIN_USER_TYPE); + String userId = (String) claims.get(Constants.LOGIN_USER_ID); + String userKey = getTokenKey(type, userId); + LoginUser user = redisCache.getCacheObject(userKey); +// log.info("用户当前类型:{}", claims); + if(!uuid.equals(user.getToken())){ + throw new BaseException("999","您的账号在其他设备登录"); + } return user; } return null; @@ -79,6 +94,13 @@ public class TokenService { } } + public void delLoginUser(String userType,String userId) { + if (Validator.isNotEmpty(userType) && Validator.isNotEmpty(userId)) { + String userKey = getTokenKey(userType,userId); + redisCache.deleteObject(userKey); + } + } + /** * 创建令牌 * @@ -93,6 +115,8 @@ public class TokenService { Map claims = new HashMap<>(); claims.put(Constants.LOGIN_USER_KEY, token); + claims.put(Constants.LOGIN_USER_TYPE, loginUser.getUserType()); + claims.put(Constants.LOGIN_USER_ID, loginUser.getUser().getUserId().toString()); return createToken(claims); } @@ -119,7 +143,9 @@ public class TokenService { loginUser.setLoginTime(System.currentTimeMillis()); loginUser.setExpireTime(loginUser.getLoginTime() + tokenProperties.getExpireTime() * MILLIS_MINUTE); // 根据uuid将loginUser缓存 - String userKey = getTokenKey(loginUser.getToken()); +// String userKey = getTokenKey(loginUser.getToken()); + String userType = loginUser.getUserType(); + String userKey = getTokenKey(userType,loginUser.getUser().getUserId().toString()); redisCache.setCacheObject(userKey, loginUser, tokenProperties.getExpireTime(), TimeUnit.MINUTES); } @@ -191,4 +217,8 @@ public class TokenService { private String getTokenKey(String uuid) { return Constants.LOGIN_TOKEN_KEY + uuid; } + + private String getTokenKey(String userType,String userId) { + return Constants.LOGIN_TOKEN_KEY + userType+"-"+userId; + } } diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java index 46b96ba..a76445a 100644 --- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java +++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java @@ -1,6 +1,7 @@ package com.ruoyi.framework.web.service; import cn.hutool.core.lang.Validator; +import com.ruoyi.common.constant.Constants; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.domain.model.LoginUser; import com.ruoyi.common.enums.UserStatus; @@ -55,6 +56,6 @@ public class UserDetailsServiceImpl implements UserDetailsService public UserDetails createLoginUser(SysUser user) { - return new LoginUser(user, permissionService.getMenuPermission(user)); + return new LoginUser(user, permissionService.getMenuPermission(user)).setUserType(Constants.LOGIN_TYEO_SYS); } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/bgt/service/impl/BgtProjectRecruitApplyServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/bgt/service/impl/BgtProjectRecruitApplyServiceImpl.java index 374552c..f79ae1f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/bgt/service/impl/BgtProjectRecruitApplyServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/bgt/service/impl/BgtProjectRecruitApplyServiceImpl.java @@ -662,18 +662,21 @@ public class BgtProjectRecruitApplyServiceImpl extends ServicePlusImpl 0) { + Long appUserId = SecurityUtils.getAppUserId(); + BgtProjectRecruitApply by = baseMapper.selectById(recruitApplyId); + BgtProjectRecruit appById = iBgtProjectRecruitService.getAppById(by.getRecruitId()); + //状态取消成功需要把对应消息的状态变更为【不需要操作】 iBgtMessageService.operation( USERTYPE_WGZ, recruitApply.getUserId(), USERTYPE_BGT, - SecurityUtils.getAppUserId(), + appById.getUserId(), recruitApply.getId(), SqlHelper.table(BgtProjectRecruitApply.class).getTableName() ); - Long appUserId = SecurityUtils.getAppUserId(); - BgtProjectRecruitApply by = baseMapper.selectById(recruitApplyId); - BgtProjectRecruit appById = iBgtProjectRecruitService.getAppById(by.getRecruitId()); + + Map mp = new HashMap<>(); mp.put("projectName", appById.getRecruitName()); //发送取消报名的系统消息 @@ -713,25 +716,28 @@ public class BgtProjectRecruitApplyServiceImpl extends ServicePlusImpl judMp = iWgzMessageService.JudgingRecruitment(recruit.getId(), recruit.getRecruitStaffNum(), recruit.getRecruitEndTime()); - String status = judMp.get("status").toString(); - switch (status) { - case "1": + if (req.getStatus().equals("3")) { + Map judMp = iWgzMessageService.JudgingRecruitment(recruit.getId(), recruit.getRecruitStaffNum(), recruit.getRecruitEndTime()); + String status = judMp.get("status").toString(); + switch (status) { + case "1": // //异步修改状态为已招满 // iAsyncService.updateRecruitStatus(recruit); - throw new RuntimeException("已招满!"); - case "2": - throw new RuntimeException("已失效!"); - } - int count = ((Number) judMp.get("count")).intValue() + 1; - if (count == recruit.getRecruitStaffNum()){ - iAsyncService.updateRecruitStatus(recruit); - } - //数据库行级锁(是否进入其他工地) - Integer i = iWgzService.QueryWhetherTheCurrentUserHasAnOngoingProject(byUserId.getUserId()); - if (i>0) { - throw new RuntimeException("您已在其他工地!"); + throw new RuntimeException("已招满!"); + case "2": + throw new RuntimeException("已失效!"); + } + int count = ((Number) judMp.get("count")).intValue() + 1; + if (count == recruit.getRecruitStaffNum()){ + iAsyncService.updateRecruitStatus(recruit); + } + //数据库行级锁(是否进入其他工地) + Integer i = iWgzService.QueryWhetherTheCurrentUserHasAnOngoingProject(byUserId.getUserId()); + if (i>0) { + throw new RuntimeException("您已在其他工地!"); + } } + //3、更新报名状态、及更新消息的操作状态(用户同意更新进场时间、状态;用户拒绝更新状态) BgtProjectRecruitApply apply = new BgtProjectRecruitApply(); apply.setId(req.getRecruitApplyId()); diff --git a/ruoyi-system/src/main/java/com/ruoyi/common/util/SseUtil.java b/ruoyi-system/src/main/java/com/ruoyi/common/util/SseUtil.java index bda1c30..471ea8e 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/common/util/SseUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/common/util/SseUtil.java @@ -1,5 +1,6 @@ package com.ruoyi.common.util; +import cn.hutool.core.date.LocalDateTimeUtil; import cn.hutool.json.JSONUtil; import com.ruoyi.common.core.redis.RedisCache; import com.ruoyi.common.utils.spring.SpringUtils; @@ -8,6 +9,8 @@ import org.slf4j.LoggerFactory; import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; import java.io.IOException; +import java.time.LocalDateTime; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; @@ -22,11 +25,27 @@ public class SseUtil { public static final String FBS_PREFIX = "fbs-"; public static final String ZBF_PREFIX = "zbf-"; public static SseEmitter subscribe(String userId,String prefix) { - // Spring Boot 2.4.7中SseEmitter构造函数支持超时时间(单位:毫秒) - SseEmitter emitter = new SseEmitter(1 * 60 * 1000L); // 30分钟超时 + // Spring Boot 2.4.7中SseEmitter构造函数支持超时时间(单位:毫秒) 30 * 60 + SseEmitter emitter = new SseEmitter(30 * 60 * 1000L); // 30分钟超时 // 存储emitter并设置回调(2.4.7中回调机制与主流版本一致) String key = prefix + "-" +userId; + SseEmitter sseEmitter = emitterMap.get(key); + if(sseEmitter!=null){ + try { + HashMap map = new HashMap<>(); + map.put("code",401); + map.put("msg","您已在其他地方登录,请重新登录"); + sseEmitter.send(SseEmitter.event() +// .id("init") +// .name(name) + .data(JSONUtil.toJsonStr(map)) + ); + } catch (IOException e) { + sseEmitter.completeWithError(e); + } + } + emitterMap.put(key, emitter); // 利用闭包特性捕获userId和prefix @@ -34,10 +53,13 @@ public class SseUtil { emitter.onTimeout(() -> { emitter.complete(); emitterMap.remove(key); - log.info("用户{}连接已超时", key); + log.info("时间:{},用户{}连接已超时", LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"),key); + }); + emitter.onError(e -> { + emitter.completeWithError(e); + emitterMap.remove(key); + log.warn("用户{}连接异常: {}", key, e.getMessage()); }); - emitter.onError(e -> emitterMap.remove(key)); - String redisKey = "messageCount:"+prefix+":"+userId; Object cacheObj = SpringUtils.getBean(RedisCache.class).getCacheObject(redisKey); diff --git a/ruoyi-system/src/main/java/com/ruoyi/wgz/service/impl/WgzPayCalculationServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/wgz/service/impl/WgzPayCalculationServiceImpl.java index 5d68ed4..0ca0d15 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/wgz/service/impl/WgzPayCalculationServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/wgz/service/impl/WgzPayCalculationServiceImpl.java @@ -713,7 +713,6 @@ public class WgzPayCalculationServiceImpl extends ServicePlusImpl