From a3d0d7423c4aa1f65d4bbb2a17f89dccc52fd8d9 Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 13 Jan 2026 00:32:17 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=B0=81=E7=A6=81?= =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=99=A8=EF=BC=8C=E7=99=BB=E5=BD=95=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dating/controller/AdminController.java | 4 +++ .../dating/interceptor/TokenInterceptor.java | 18 +++++++++-- .../dating/interceptor/WsAuthInterceptor.java | 8 +++++ .../com/bao/dating/pojo/entity/UserBan.java | 30 +++++++++++++++++++ .../dating/service/impl/UserServiceImpl.java | 8 ++++- 5 files changed, 64 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/bao/dating/controller/AdminController.java create mode 100644 src/main/java/com/bao/dating/pojo/entity/UserBan.java diff --git a/src/main/java/com/bao/dating/controller/AdminController.java b/src/main/java/com/bao/dating/controller/AdminController.java new file mode 100644 index 0000000..d449500 --- /dev/null +++ b/src/main/java/com/bao/dating/controller/AdminController.java @@ -0,0 +1,4 @@ +package com.bao.dating.controller; + +public class AdminController { +} diff --git a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java index 3203fc9..e2357f9 100644 --- a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java +++ b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java @@ -44,10 +44,10 @@ public class TokenInterceptor implements HandlerInterceptor { } // 从 header 获取 token String token = request.getHeader("token"); - + try { log.info("jwt校验: {}", token); - + // 验证 token 是否有效(包括是否过期) if (!JwtUtil.validateToken(token)) { log.error("Token无效或已过期"); @@ -66,10 +66,22 @@ public class TokenInterceptor implements HandlerInterceptor { response.getWriter().write("登录已失效, 请重新登录"); return false; } - + // 解析 token Long userId = Long.valueOf(JwtUtil.getSubjectFromToken(token)); + // 检查用户是否被封禁 + String banKey = "user:ban:" + userId; + if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { + String reason = String.valueOf(redisTemplate.opsForValue().get(banKey)); + log.error("用户 {} 已被封禁:{}", userId, reason); + + response.setStatus(403); + response.setContentType("application/json;charset=UTF-8"); + response.getWriter().write("账号已被封禁:" + reason); + return false; + } + // 从Redis获取存储的token进行比对 Object redisTokenObj = redisTemplate.opsForValue().get("login:token:" + userId); String redisToken = redisTokenObj != null ? redisTokenObj.toString() : null; diff --git a/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java index a01153c..1e0e99a 100644 --- a/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java +++ b/src/main/java/com/bao/dating/interceptor/WsAuthInterceptor.java @@ -73,6 +73,14 @@ public class WsAuthInterceptor implements HandshakeInterceptor { Long userId = Long.valueOf(userIdStr); + // 检查用户是否被封禁 + String banKey = "user:ban:" + userId; + if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { + String reason = String.valueOf(redisTemplate.opsForValue().get(banKey)); + log.error("WebSocket拒绝:用户 {} 被封禁,原因:{}", userId, reason); + return false; + } + // 从Redis获取存储的token进行比对 String redisTokenKey = "login:token:" + userId; Object redisTokenObj = redisTemplate.opsForValue().get(redisTokenKey); diff --git a/src/main/java/com/bao/dating/pojo/entity/UserBan.java b/src/main/java/com/bao/dating/pojo/entity/UserBan.java new file mode 100644 index 0000000..53bec33 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/entity/UserBan.java @@ -0,0 +1,30 @@ +package com.bao.dating.pojo.entity; + +import lombok.Data; + +import java.time.LocalDateTime; + +/** + * 用户封禁记录 + * @author KilLze + */ +@Data +public class UserBan { + + private Long id; + + private Long userId; + + private String reason; + + private LocalDateTime banStartTime; + + private LocalDateTime banEndTime; + + /** + * 1:封禁中 0:已解封 + */ + private Integer status; + + private LocalDateTime createTime; +} diff --git a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java index e3210ed..733e8ab 100644 --- a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java @@ -20,6 +20,7 @@ import com.bao.dating.util.CodeUtil; import com.bao.dating.util.FileUtil; import com.bao.dating.util.JwtUtil; import com.bao.dating.util.MD5Util; +import com.bao.dating.util.UserBanUtil; import io.jsonwebtoken.Claims; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -66,6 +67,9 @@ public class UserServiceImpl implements UserService { @Autowired private VerificationCodeService verificationCodeService; + @Autowired + private UserBanUtil userBanValidator; + /** * 用户登录 * @@ -92,6 +96,8 @@ public class UserServiceImpl implements UserService { if (!match) { throw new RuntimeException("密码错误"); } + // 用户封禁验证 + userBanValidator.validateUserNotBanned(user.getUserId()); // 生成token String token = JwtUtil.generateToken(String.valueOf(user.getUserId())); @@ -485,4 +491,4 @@ public class UserServiceImpl implements UserService { } return result; } -} +} \ No newline at end of file From 088c94e723e93095a8bb0b6256ae927e2c699b40 Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 13 Jan 2026 00:32:30 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E7=94=A8=E6=88=B7=E5=B0=81=E7=A6=81?= =?UTF-8?q?=E6=8B=A6=E6=88=AA=E5=99=A8=EF=BC=8C=E7=99=BB=E5=BD=95=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E5=AE=8C=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bao/dating/util/UserBanUtil.java | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/main/java/com/bao/dating/util/UserBanUtil.java diff --git a/src/main/java/com/bao/dating/util/UserBanUtil.java b/src/main/java/com/bao/dating/util/UserBanUtil.java new file mode 100644 index 0000000..13a0745 --- /dev/null +++ b/src/main/java/com/bao/dating/util/UserBanUtil.java @@ -0,0 +1,43 @@ +package com.bao.dating.util; + +import com.bao.dating.context.UserContext; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Component; + +/** + * 用户封禁验证工具类 + * 提供统一的用户封禁状态检查功能 + * + * @author KilLze + */ +@Component +public class UserBanUtil { + + @Autowired + private RedisTemplate redisTemplate; + + /** + * 验证指定用户是否被封禁 + * + * @param userId 用户ID + * @throws RuntimeException 如果用户被封禁则抛出异常 + */ + public void validateUserNotBanned(Long userId) { + String banKey = "user:ban:" + userId; + if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { + String reason = (String) redisTemplate.opsForValue().get(banKey); + throw new RuntimeException("账号已被封禁:" + reason); + } + } + + /** + * 验证当前登录用户是否被封禁 + * + * @throws RuntimeException 如果用户被封禁则抛出异常 + */ + public void validateCurrentUserNotBanned() { + Long userId = UserContext.getUserId(); + validateUserNotBanned(userId); + } +} \ No newline at end of file From 1c2a4edae9190bd37221a7edc971292f2efeef0e Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 13 Jan 2026 01:29:34 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=B0=81=E7=A6=81=EF=BC=8C=E8=A7=A3=E5=B0=81=EF=BC=8C=E5=B0=81?= =?UTF-8?q?=E7=A6=81=E6=9F=A5=E8=AF=A2=EF=BC=88=E7=94=B1=E4=BA=8E=E6=B2=A1?= =?UTF-8?q?=E6=9C=89=E7=AE=A1=E7=90=86=E5=91=98=EF=BC=8C=E6=89=80=E4=BB=A5?= =?UTF-8?q?=E7=8E=B0=E5=9C=A8=E5=85=88=E7=94=A8=E6=99=AE=E9=80=9A=E7=94=A8?= =?UTF-8?q?=E6=88=B7=E6=B5=8B=E8=AF=95=E5=B0=81=E7=A6=81=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../dating/controller/AdminController.java | 47 ++++++++++++ .../dating/interceptor/TokenInterceptor.java | 2 +- .../com/bao/dating/mapper/UserBanMapper.java | 43 +++++++++++ .../com/bao/dating/pojo/dto/UserBanDTO.java | 13 ++++ .../bao/dating/service/UserBanService.java | 31 ++++++++ .../service/impl/UserBanServiceImpl.java | 74 +++++++++++++++++++ .../java/com/bao/dating/util/UserBanUtil.java | 24 +++++- .../com/bao/dating/mapper/UserBanMapper.xml | 50 +++++++++++++ 8 files changed, 282 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/bao/dating/mapper/UserBanMapper.java create mode 100644 src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java create mode 100644 src/main/java/com/bao/dating/service/UserBanService.java create mode 100644 src/main/java/com/bao/dating/service/impl/UserBanServiceImpl.java create mode 100644 src/main/resources/com/bao/dating/mapper/UserBanMapper.xml diff --git a/src/main/java/com/bao/dating/controller/AdminController.java b/src/main/java/com/bao/dating/controller/AdminController.java index d449500..e7cf97f 100644 --- a/src/main/java/com/bao/dating/controller/AdminController.java +++ b/src/main/java/com/bao/dating/controller/AdminController.java @@ -1,4 +1,51 @@ package com.bao.dating.controller; +import com.bao.dating.common.Result; +import com.bao.dating.common.ResultCode; +import com.bao.dating.pojo.dto.UserBanDTO; +import com.bao.dating.pojo.entity.UserBan; +import com.bao.dating.service.UserBanService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * 管理员控制器 + * @author lenovo + */ +@RestController +@RequestMapping("/admin") public class AdminController { + @Autowired + private UserBanService userBanService; + + /** + * 封禁用户 + */ + @PostMapping("/{userId}/ban") + public Result banUser(@PathVariable Long userId, + @RequestBody UserBanDTO userBanDTO) { + userBanDTO.setUserId(userId); + userBanService.banUser(userBanDTO); + return Result.success(ResultCode.SUCCESS, "封禁成功"); + } + + /** + * 解封用户 + */ + @PostMapping("/{userId}/unban") + public Result unbanUser(@PathVariable Long userId) { + + userBanService.unbanUser(userId); + return Result.success(ResultCode.SUCCESS, "解封成功"); + } + + /** + * 查询封禁状态 + */ + @GetMapping("/{userId}/banInfo") + public Result banInfo(@PathVariable Long userId) { + + UserBan ban = userBanService.getActiveBan(userId); + return Result.success(ResultCode.SUCCESS, "查询成功", ban); + } } diff --git a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java index e2357f9..2d976ec 100644 --- a/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java +++ b/src/main/java/com/bao/dating/interceptor/TokenInterceptor.java @@ -74,7 +74,7 @@ public class TokenInterceptor implements HandlerInterceptor { String banKey = "user:ban:" + userId; if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { String reason = String.valueOf(redisTemplate.opsForValue().get(banKey)); - log.error("用户 {} 已被封禁:{}", userId, reason); + log.error("用户 {} 已被封禁,原因:{}", userId, reason); response.setStatus(403); response.setContentType("application/json;charset=UTF-8"); diff --git a/src/main/java/com/bao/dating/mapper/UserBanMapper.java b/src/main/java/com/bao/dating/mapper/UserBanMapper.java new file mode 100644 index 0000000..a7d586c --- /dev/null +++ b/src/main/java/com/bao/dating/mapper/UserBanMapper.java @@ -0,0 +1,43 @@ +package com.bao.dating.mapper; + +import com.bao.dating.pojo.entity.UserBan; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface UserBanMapper { + + /** + * 新增封禁记录 + * @param userBan 封禁记录 + * @return 影响行数 + */ + int insertBan(UserBan userBan); + + /** + * 查询是否存在生效中的封禁 + * @param userId 用户ID + * @return 存在返回1,不存在返回0 + */ + int existsActiveBan(@Param("userId") Long userId); + + /** + * 查询生效中的封禁记录 + * @param userId 用户ID + * @return 封禁记录 + */ + UserBan selectActiveBan(@Param("userId") Long userId); + + /** + * 解封用户 + * @param userId 用户ID + * @return 影响行数 + */ + int unbanUser(@Param("userId") Long userId); + + /** + * 定时任务:过期自动解封 + * @return 影响行数 + */ + int updateExpiredBans(); +} diff --git a/src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java b/src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java new file mode 100644 index 0000000..0f54079 --- /dev/null +++ b/src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java @@ -0,0 +1,13 @@ +package com.bao.dating.pojo.dto; +import lombok.Data; + +/** + * 用户封禁数据传输对象 + * @author KilLze + */ +@Data +public class UserBanDTO { + private Long userId; + private String reason; + private Integer banDays; +} diff --git a/src/main/java/com/bao/dating/service/UserBanService.java b/src/main/java/com/bao/dating/service/UserBanService.java new file mode 100644 index 0000000..37a38de --- /dev/null +++ b/src/main/java/com/bao/dating/service/UserBanService.java @@ -0,0 +1,31 @@ +package com.bao.dating.service; + +import com.bao.dating.pojo.dto.UserBanDTO; +import com.bao.dating.pojo.entity.UserBan; + +/** + * 用户封禁服务接口 + * @author KilLze + */ +public interface UserBanService { + + /** + * 封禁用户 + * @param userBanDTO 用户封禁信息 + * + */ + void banUser(UserBanDTO userBanDTO); + + /** + * 解封用户 + * @param userId 用户ID + */ + void unbanUser(Long userId); + + /** + * 查询封禁信息 + * @param userId 用户ID + * @return 封禁信息 + */ + UserBan getActiveBan(Long userId); +} diff --git a/src/main/java/com/bao/dating/service/impl/UserBanServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserBanServiceImpl.java new file mode 100644 index 0000000..917e4dc --- /dev/null +++ b/src/main/java/com/bao/dating/service/impl/UserBanServiceImpl.java @@ -0,0 +1,74 @@ +package com.bao.dating.service.impl; + +import com.bao.dating.mapper.UserBanMapper; +import com.bao.dating.pojo.dto.UserBanDTO; +import com.bao.dating.pojo.entity.UserBan; +import com.bao.dating.service.UserBanService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.util.concurrent.TimeUnit; + +@Service +public class UserBanServiceImpl implements UserBanService { + + @Autowired + private UserBanMapper userBanMapper; + + @Autowired + private RedisTemplate redisTemplate; + + @Override + public void banUser(UserBanDTO userBanDTO) { + + // 已被封禁,直接拒绝 + if (userBanMapper.existsActiveBan(userBanDTO.getUserId()) > 0) { + throw new RuntimeException("用户已处于封禁状态"); + } + + LocalDateTime now = LocalDateTime.now(); + LocalDateTime endTime = userBanDTO.getBanDays() == null ? null : now.plusDays(userBanDTO.getBanDays()); + + // 1. 写数据库 + UserBan ban = new UserBan(); + ban.setUserId(userBanDTO.getUserId()); + ban.setReason(userBanDTO.getReason()); + ban.setBanStartTime(now); + ban.setBanEndTime(endTime); + ban.setStatus(1); + userBanMapper.insertBan(ban); + + // 2. 写 Redis + String key = "user:ban:" + userBanDTO.getUserId(); + if (userBanDTO.getBanDays() == null) { + redisTemplate.opsForValue().set(key, userBanDTO.getReason()); + } else { + redisTemplate.opsForValue().set(key, userBanDTO.getReason(), userBanDTO.getBanDays(), TimeUnit.DAYS); + } + + // 3. 踢下线 + redisTemplate.delete("login:token:" + userBanDTO.getUserId()); + } + + /** + * 解封用户 + */ + @Override + public void unbanUser(Long userId) { + // 更新数据库 + userBanMapper.unbanUser(userId); + + // 删除 Redis + redisTemplate.delete("user:ban:" + userId); + } + + /** + * 获取用户封禁信息 + */ + @Override + public UserBan getActiveBan(Long userId) { + return userBanMapper.selectActiveBan(userId); + } +} diff --git a/src/main/java/com/bao/dating/util/UserBanUtil.java b/src/main/java/com/bao/dating/util/UserBanUtil.java index 13a0745..b53236a 100644 --- a/src/main/java/com/bao/dating/util/UserBanUtil.java +++ b/src/main/java/com/bao/dating/util/UserBanUtil.java @@ -5,6 +5,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; +import java.util.concurrent.TimeUnit; + /** * 用户封禁验证工具类 * 提供统一的用户封禁状态检查功能 @@ -27,7 +29,27 @@ public class UserBanUtil { String banKey = "user:ban:" + userId; if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { String reason = (String) redisTemplate.opsForValue().get(banKey); - throw new RuntimeException("账号已被封禁:" + reason); + + // 获取剩余过期时间(秒) + Long ttlSeconds = redisTemplate.getExpire(banKey, TimeUnit.SECONDS); + String remainingTime = ""; + if (ttlSeconds != null && ttlSeconds > 0) { + long days = ttlSeconds / (24 * 3600); + long hours = (ttlSeconds % (24 * 3600)) / 3600; + long minutes = (ttlSeconds % 3600) / 60; + + if (days > 0) { + remainingTime = ",剩余时间:" + days + "天" + hours + "小时"; + } else if (hours > 0) { + remainingTime = ",剩余时间:" + hours + "小时" + minutes + "分钟"; + } else { + remainingTime = ",剩余时间:" + minutes + "分钟"; + } + } else { + remainingTime = ",永久封禁"; + } + + throw new RuntimeException("账号已被封禁,原因:" + reason + remainingTime); } } diff --git a/src/main/resources/com/bao/dating/mapper/UserBanMapper.xml b/src/main/resources/com/bao/dating/mapper/UserBanMapper.xml new file mode 100644 index 0000000..915d251 --- /dev/null +++ b/src/main/resources/com/bao/dating/mapper/UserBanMapper.xml @@ -0,0 +1,50 @@ + + + + + + + + INSERT INTO user_ban + (user_id, reason, ban_start_time, ban_end_time, status) + VALUES + (#{userId}, #{reason}, #{banStartTime}, #{banEndTime}, #{status}) + + + + + + + + + + + UPDATE user_ban + SET status = 0 + WHERE user_id = #{userId} + AND status = 1 + + + + + UPDATE user_ban + SET status = 0 + WHERE status = 1 + AND ban_end_time IS NOT NULL + AND ban_end_time < NOW() + + + \ No newline at end of file From 6d95b8d3915342274fd8286676097f5bcc5a3cbe Mon Sep 17 00:00:00 2001 From: KilLze Date: Tue, 13 Jan 2026 01:34:05 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=BA=93=E5=AE=9A=E6=97=B6=E8=A7=A3=E5=B0=81=E4=BD=8E=E9=A2=91?= =?UTF-8?q?=E5=90=8C=E6=AD=A5=EF=BC=88=E5=87=8C=E6=99=A83=E7=82=B9?= =?UTF-8?q?=EF=BC=89=EF=BC=8C=E4=B8=BB=E8=A6=81=E8=BF=98=E6=98=AF=E4=BE=9D?= =?UTF-8?q?=E8=B5=96redis=E5=AE=9E=E6=97=B6=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/task/UserBanScheduleTask.java | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 src/main/java/com/bao/dating/task/UserBanScheduleTask.java diff --git a/src/main/java/com/bao/dating/task/UserBanScheduleTask.java b/src/main/java/com/bao/dating/task/UserBanScheduleTask.java new file mode 100644 index 0000000..3344e48 --- /dev/null +++ b/src/main/java/com/bao/dating/task/UserBanScheduleTask.java @@ -0,0 +1,26 @@ +package com.bao.dating.task; + +import com.bao.dating.mapper.UserBanMapper; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@EnableScheduling +public class UserBanScheduleTask { + + @Autowired + private UserBanMapper userBanMapper; + + /** + * 每天凌晨 3 点同步过期封禁 + */ + @Scheduled(cron = "0 0 3 * * ?") + public void syncExpiredUserBan() { + int rows = userBanMapper.updateExpiredBans(); + log.info("封禁同步任务执行完成,解封 {} 个用户", rows); + } +} From e17001601933d0cc7a72f7537341090a53e136ea Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 14 Jan 2026 11:21:06 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E7=8A=B6=E6=80=81=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../bao/dating/controller/UserController.java | 11 +++++++++++ .../com/bao/dating/service/UserService.java | 7 +++++++ .../dating/service/impl/UserServiceImpl.java | 19 +++++++++++++++++++ 3 files changed, 37 insertions(+) diff --git a/src/main/java/com/bao/dating/controller/UserController.java b/src/main/java/com/bao/dating/controller/UserController.java index 13b709a..a85a762 100644 --- a/src/main/java/com/bao/dating/controller/UserController.java +++ b/src/main/java/com/bao/dating/controller/UserController.java @@ -203,4 +203,15 @@ public class UserController { return Result.success(ResultCode.SUCCESS,"用户登录成功",userLoginVO); } + /** + * 判断用户是否在线 + * @param userId 用户ID + * @return 用户是否在线 + */ + @GetMapping("/{userId}/online") + public Result isUserOnline(@PathVariable Long userId) { + + boolean online = userService.isUserOnline(userId); + return Result.success(ResultCode.SUCCESS, "查询成功", online); + } } diff --git a/src/main/java/com/bao/dating/service/UserService.java b/src/main/java/com/bao/dating/service/UserService.java index 3e3fed1..ab23da1 100644 --- a/src/main/java/com/bao/dating/service/UserService.java +++ b/src/main/java/com/bao/dating/service/UserService.java @@ -92,4 +92,11 @@ public interface UserService { * @return 用户列表 */ List findNearbyUsers(double lat,double lng,double radiusKm); + + /** + * 判断用户是否在线 + * @param userId 用户ID + * @return 是否在线 + */ + boolean isUserOnline(Long userId); } diff --git a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java index 733e8ab..d17c298 100644 --- a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java @@ -491,4 +491,23 @@ public class UserServiceImpl implements UserService { } return result; } + + @Override + public boolean isUserOnline(Long userId) { + if (userId == null) { + return false; + } + + // 1. 是否被封禁 + String banKey = "user:ban:" + userId; + if (Boolean.TRUE.equals(redisTemplate.hasKey(banKey))) { + return false; + } + + // 2. 是否存在登录 token + String tokenKey = "login:token:" + userId; + Boolean online = redisTemplate.hasKey(tokenKey); + + return Boolean.TRUE.equals(online); + } } \ No newline at end of file From ea5c95584dc0bec3514816fddd993208a849f29e Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 14 Jan 2026 11:31:10 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BC=9A=E8=AF=9D?= =?UTF-8?q?=E5=88=97=E8=A1=A8=EF=BC=8C=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=9C=A8=E7=BA=BF=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java | 2 ++ src/main/java/com/bao/dating/pojo/vo/UserInfoVO.java | 1 + src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java | 1 + 3 files changed, 4 insertions(+) diff --git a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java index 3e28e5b..1be8926 100644 --- a/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java +++ b/src/main/java/com/bao/dating/pojo/vo/ChatSessionsVO.java @@ -29,4 +29,6 @@ public class ChatSessionsVO { private Integer topStatus; /** 免打扰状态 */ private Integer muteStatus; + /** 会话状态 */ + private Boolean online; } diff --git a/src/main/java/com/bao/dating/pojo/vo/UserInfoVO.java b/src/main/java/com/bao/dating/pojo/vo/UserInfoVO.java index 35c5c90..ec6ffa6 100644 --- a/src/main/java/com/bao/dating/pojo/vo/UserInfoVO.java +++ b/src/main/java/com/bao/dating/pojo/vo/UserInfoVO.java @@ -26,4 +26,5 @@ public class UserInfoVO implements Serializable { private LocalDateTime createdAt; private Double latitude; private Double longitude; + private Boolean online; } diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index 517eb9c..c255336 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -236,6 +236,7 @@ public class ChatServiceImpl implements ChatService { vo.setSessionName("用户" + session.getTargetUserId()); vo.setAvatarUrl(null); } + vo.setOnline(userService.isUserOnline(currentUserId)); return vo; }).collect(Collectors.toList()); } From 39af4e65961a99cd1a1a1f1acb08efe0f3597b62 Mon Sep 17 00:00:00 2001 From: KilLze Date: Wed, 14 Jan 2026 11:44:36 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E4=BF=AE=E8=AF=A5=E6=AD=BB=E7=9A=84bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/bao/dating/service/impl/ChatServiceImpl.java | 2 +- .../java/com/bao/dating/service/impl/UserServiceImpl.java | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java index c255336..ca27edf 100644 --- a/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/ChatServiceImpl.java @@ -236,7 +236,7 @@ public class ChatServiceImpl implements ChatService { vo.setSessionName("用户" + session.getTargetUserId()); vo.setAvatarUrl(null); } - vo.setOnline(userService.isUserOnline(currentUserId)); + vo.setOnline(userService.isUserOnline(vo.getTargetUserId())); return vo; }).collect(Collectors.toList()); } diff --git a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java index d17c298..3f3b9ec 100644 --- a/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java +++ b/src/main/java/com/bao/dating/service/impl/UserServiceImpl.java @@ -124,6 +124,9 @@ public class UserServiceImpl implements UserService { @Override public void logout(String token) { Claims claims = JwtUtil.getClaimsFromToken(token); + // 获取token信息 + String subject = claims.getSubject(); + // 获取token的过期时间 Date expiration = claims.getExpiration(); // 判断 token 是否已过期 long ttl = expiration.getTime() - System.currentTimeMillis(); @@ -132,6 +135,10 @@ public class UserServiceImpl implements UserService { return; } + // 从Redis中删除登录token记录 + String loginTokenKey = "login:token:" + subject; + redisTemplate.delete(loginTokenKey); + String logoutKey = "jwt:blacklist:" + token; redisTemplate.opsForValue().set( logoutKey,