1 Commits

Author SHA1 Message Date
34392f137f 完成用户对用户登录和发布动态的数据分析 2026-01-12 19:35:52 +08:00
21 changed files with 209 additions and 463 deletions

View File

@@ -1,51 +0,0 @@
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<UserBan> banInfo(@PathVariable Long userId) {
UserBan ban = userBanService.getActiveBan(userId);
return Result.success(ResultCode.SUCCESS, "查询成功", ban);
}
}

View File

@@ -0,0 +1,66 @@
package com.bao.dating.controller;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.pojo.vo.DataAnalysisVO;
import com.bao.dating.util.DataAnalysisRedisService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
@RestController
@RequestMapping("/dataAnalysis")
public class DataAnalysisController {
@Resource
private DataAnalysisRedisService dataAnalysisRedisService;
/**
* 统计动态
* @param days 统计时常
* @return result
*/
@GetMapping("/postTotal")
public Result<DataAnalysisVO> postDataAnalysis(@RequestParam Integer days){
if (checkParam(days)){
return Result.error(ResultCode.PARAM_ERROR);
}
Long count = dataAnalysisRedisService.countPostTotalByDays(days);
String timePeriod = dataAnalysisRedisService.calculateTimeRanges(LocalDateTime.now(), days);
DataAnalysisVO dataAnalysisVO = new DataAnalysisVO();
dataAnalysisVO.setTotal(count);
dataAnalysisVO.setTimePeriod(timePeriod);
return Result.success(ResultCode.SUCCESS,dataAnalysisVO);
}
@GetMapping("/loginUserTotal")
public Result<DataAnalysisVO> loginUserDataAnalysis(@RequestParam Integer days){
if (checkParam(days)){
return Result.error(ResultCode.PARAM_ERROR);
}
Long count = dataAnalysisRedisService.countLoginUserTotalByDays(days);
String timePeriod = dataAnalysisRedisService.calculateTimeRanges(LocalDateTime.now(), days);
DataAnalysisVO dataAnalysisVO = new DataAnalysisVO();
dataAnalysisVO.setTotal(count);
dataAnalysisVO.setTimePeriod(timePeriod);
return Result.success(ResultCode.SUCCESS,dataAnalysisVO);
}
/**
* 检验参数
* @param days 查询天数
* @return 参数是否合法
*/
public Boolean checkParam(Integer days){
ArrayList<Integer> day = new ArrayList<>();
day.add(7);
day.add(15);
day.add(30);
day.add(365);
return days != null && day.contains(days);
}
}

View File

@@ -1,17 +1,17 @@
package com.bao.dating.controller;
import com.bao.dating.anno.Log;
import com.bao.dating.common.Result;
import com.bao.dating.common.ResultCode;
import com.bao.dating.pojo.dto.PostRequestDTO;
import com.bao.dating.pojo.entity.Post;
import com.bao.dating.pojo.vo.PostEditVO;
import com.bao.dating.service.PostService;
import com.bao.dating.util.DataAnalysisRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import java.util.List;
/**
@@ -26,6 +26,9 @@ public class PostController {
@Autowired
private PostService postService;
@Resource
private DataAnalysisRedisService dataAnalysisRedisService;
/**
* 上传媒体文件接口 like
* @param files 媒体文件数组
@@ -46,6 +49,9 @@ public class PostController {
public Result<Post> createPostJson(@RequestBody PostRequestDTO postDTO) {
// 调用 Service 层处理发布动态业务逻辑
Post result = postService.createPost(postDTO);
//这里将发布动态操作记录到redis中
Long postId = result.getPostId();
dataAnalysisRedisService.recordPostData(postId);
return Result.success(ResultCode.SUCCESS, "动态发布成功,等待审核。", result);
}

View File

@@ -9,11 +9,13 @@ import com.bao.dating.pojo.dto.UserLoginDTO;
import com.bao.dating.pojo.vo.UserInfoVO;
import com.bao.dating.pojo.vo.UserLoginVO;
import com.bao.dating.service.UserService;
import com.bao.dating.util.DataAnalysisRedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
@@ -29,6 +31,9 @@ public class UserController {
@Autowired
private UserService userService;
@Resource
private DataAnalysisRedisService dataAnalysisRedisService;
/**
* 登录
* @param userLoginDTO 登录参数
@@ -36,6 +41,12 @@ public class UserController {
@PostMapping("/login")
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
UserLoginVO userloginVO = userService.userLogin(userLoginDTO);
//将用户登录记录到redis中
if (userloginVO != null){
Long userId = userloginVO.getUserId();
dataAnalysisRedisService.recordLoginUserData(userId);
}
return Result.success(ResultCode.SUCCESS, "登录成功", userloginVO);
}
@@ -128,6 +139,11 @@ public class UserController {
}
//登录
UserLoginVO vo = userService.loginByPhone(phone);
//将用户登录操作记录到redis中
if (vo != null){
Long userId = vo.getUserId();
dataAnalysisRedisService.recordLoginUserData(userId);
}
return Result.success(ResultCode.SUCCESS, "登录成功", vo);
}
@@ -200,18 +216,10 @@ public class UserController {
if (userLoginVO == null){
return Result.error(ResultCode.FAIL,"请先注册用户或添加邮箱");
}
//将用户登录操作记录到redis中
Long userId = userLoginVO.getUserId();
dataAnalysisRedisService.recordLoginUserData(userId);
return Result.success(ResultCode.SUCCESS,"用户登录成功",userLoginVO);
}
/**
* 判断用户是否在线
* @param userId 用户ID
* @return 用户是否在线
*/
@GetMapping("/{userId}/online")
public Result<Boolean> isUserOnline(@PathVariable Long userId) {
boolean online = userService.isUserOnline(userId);
return Result.success(ResultCode.SUCCESS, "查询成功", online);
}
}

View File

@@ -70,18 +70,6 @@ public class TokenInterceptor implements HandlerInterceptor {
// 解析 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;

View File

@@ -73,14 +73,6 @@ 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);

View File

@@ -1,43 +0,0 @@
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();
}

View File

@@ -1,13 +0,0 @@
package com.bao.dating.pojo.dto;
import lombok.Data;
/**
* 用户封禁数据传输对象
* @author KilLze
*/
@Data
public class UserBanDTO {
private Long userId;
private String reason;
private Integer banDays;
}

View File

@@ -1,30 +0,0 @@
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;
}

View File

@@ -29,6 +29,4 @@ public class ChatSessionsVO {
private Integer topStatus;
/** 免打扰状态 */
private Integer muteStatus;
/** 会话状态 */
private Boolean online;
}

View File

@@ -0,0 +1,11 @@
package com.bao.dating.pojo.vo;
import lombok.Data;
@Data
public class DataAnalysisVO {
//所有总数
private Long total;
//时间段
private String timePeriod;
}

View File

@@ -26,5 +26,4 @@ public class UserInfoVO implements Serializable {
private LocalDateTime createdAt;
private Double latitude;
private Double longitude;
private Boolean online;
}

View File

@@ -1,31 +0,0 @@
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);
}

View File

@@ -92,11 +92,4 @@ public interface UserService {
* @return 用户列表
*/
List<UserInfoVO> findNearbyUsers(double lat,double lng,double radiusKm);
/**
* 判断用户是否在线
* @param userId 用户ID
* @return 是否在线
*/
boolean isUserOnline(Long userId);
}

View File

@@ -236,7 +236,6 @@ public class ChatServiceImpl implements ChatService {
vo.setSessionName("用户" + session.getTargetUserId());
vo.setAvatarUrl(null);
}
vo.setOnline(userService.isUserOnline(vo.getTargetUserId()));
return vo;
}).collect(Collectors.toList());
}

View File

@@ -1,74 +0,0 @@
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<String, Object> 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);
}
}

View File

@@ -20,7 +20,6 @@ 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;
@@ -67,9 +66,6 @@ public class UserServiceImpl implements UserService {
@Autowired
private VerificationCodeService verificationCodeService;
@Autowired
private UserBanUtil userBanValidator;
/**
* 用户登录
*
@@ -96,8 +92,6 @@ public class UserServiceImpl implements UserService {
if (!match) {
throw new RuntimeException("密码错误");
}
// 用户封禁验证
userBanValidator.validateUserNotBanned(user.getUserId());
// 生成token
String token = JwtUtil.generateToken(String.valueOf(user.getUserId()));
@@ -124,9 +118,6 @@ 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();
@@ -135,10 +126,6 @@ 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,
@@ -498,23 +485,4 @@ 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);
}
}

View File

@@ -1,26 +0,0 @@
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);
}
}

View File

@@ -0,0 +1,101 @@
package com.bao.dating.util;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;
/**
* 基于redis的数据分析工具 -统计动态总数和登录人数
*/
@Component
public class DataAnalysisRedisService {
// Redis Key 定义
//动态总数
private static final String REDIS_KEY_POST_TOTAL = "data:post:total";
//活跃人数
private static final String REDIS_KEY_LOGIN_USER_TOTAL = "data:loginUser:total";
@Resource
private RedisTemplate<String, Object> redisTemplate;
/**
* 记录动态向redis中添加数据
* @param postId 动态id
*/
public void recordPostData(Long postId) {
// 获取当前毫秒级时间戳作为Sorted Set的score
long currentTimestamp = System.currentTimeMillis();
// 1. 记录动态数据
redisTemplate.opsForZSet().add(REDIS_KEY_POST_TOTAL, postId, currentTimestamp);
// 可选设置Key的过期时间1年+1天避免数据无限累积
setKeyExpire(REDIS_KEY_POST_TOTAL);
}
/**
* 记录动态向redis中添加数据
* @param userId 用户id
*/
public void recordLoginUserData(Long userId) {
// 获取当前毫秒级时间戳作为Sorted Set的score
long currentTimestamp = System.currentTimeMillis();
// 1. 记录动态数据
redisTemplate.opsForZSet().add(REDIS_KEY_LOGIN_USER_TOTAL, userId, currentTimestamp);
// 可选设置Key的过期时间1年+1天避免数据无限累积
setKeyExpire(REDIS_KEY_LOGIN_USER_TOTAL);
}
/**
* 设置Redis Key的过期时间1年+1天确保1年内的数据都能被查询
*/
private void setKeyExpire(String redisKey) {
if (Boolean.FALSE.equals(redisTemplate.hasKey(redisKey))) {
redisTemplate.expire(redisKey, 366, TimeUnit.DAYS);
}
}
/**
* 统计指定时间段内发布的动态
* @param days 指定时间段
* @return 总数
*/
public Long countPostTotalByDays(int days) {
// 1. 计算时间范围:结束时间=当前时间,起始时间=当前时间 - N天的毫秒数
long endTimestamp = System.currentTimeMillis();
long startTimestamp = endTimestamp - (long) days * 24 * 60 * 60 * 1000;
// 2. key min max - 统计指定score范围内的成员数量高效直接返回数量
return redisTemplate.opsForZSet().count(REDIS_KEY_POST_TOTAL, startTimestamp, endTimestamp);
}
public Long countLoginUserTotalByDays(int days) {
// 1. 计算时间范围:结束时间=当前时间,起始时间=当前时间 - N天的毫秒数
long endTimestamp = System.currentTimeMillis();
long startTimestamp = endTimestamp - (long) days * 24 * 60 * 60 * 1000;
// 2. key min max - 统计指定score范围内的成员数量高效直接返回数量
return redisTemplate.opsForZSet().count(REDIS_KEY_LOGIN_USER_TOTAL, startTimestamp, endTimestamp);
}
/**
* 核心方法:传入当前时间,返回各时间段的结果
* @param currentDateTime 当前时间LocalDateTime类型可直接通过LocalDateTime.now()获取)
*/
public String calculateTimeRanges(LocalDateTime currentDateTime,int days) {
// 1. 计算各时间段的起始时间(当前时间往前推对应时长)
LocalDateTime sevenDaysAgo = currentDateTime.minusDays(7);
LocalDateTime fifteenDaysAgo = currentDateTime.minusDays(15);
LocalDateTime thirtyDaysAgo = currentDateTime.minusDays(30);
LocalDateTime oneYearAgo = currentDateTime.minusYears(1);
if (days == 7)
return sevenDaysAgo + " - " + currentDateTime;
if (days == 15)
return fifteenDaysAgo + " - " + currentDateTime;
if (days == 30)
return thirtyDaysAgo + " - " + currentDateTime;
if (days == 365)
return oneYearAgo + " - " + currentDateTime;
return null;
}
}

View File

@@ -1,65 +0,0 @@
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;
import java.util.concurrent.TimeUnit;
/**
* 用户封禁验证工具类
* 提供统一的用户封禁状态检查功能
*
* @author KilLze
*/
@Component
public class UserBanUtil {
@Autowired
private RedisTemplate<String, Object> 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);
// 获取剩余过期时间(秒)
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);
}
}
/**
* 验证当前登录用户是否被封禁
*
* @throws RuntimeException 如果用户被封禁则抛出异常
*/
public void validateCurrentUserNotBanned() {
Long userId = UserContext.getUserId();
validateUserNotBanned(userId);
}
}

View File

@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.bao.dating.mapper.UserBanMapper">
<!-- 向数据库中添加用户封禁信息 -->
<insert id="insertBan" useGeneratedKeys="true" keyProperty="id">
INSERT INTO user_ban
(user_id, reason, ban_start_time, ban_end_time, status)
VALUES
(#{userId}, #{reason}, #{banStartTime}, #{banEndTime}, #{status})
</insert>
<!-- 查询指定用户是否存在未过期的封禁信息 -->
<select id="existsActiveBan" resultType="int">
SELECT COUNT(1)
FROM user_ban
WHERE user_id = #{userId}
AND status = 1
LIMIT 1
</select>
<!-- 查询指定用户是否存在未过期的封禁信息 -->
<select id="selectActiveBan" resultType="com.bao.dating.pojo.entity.UserBan">
SELECT *
FROM user_ban
WHERE user_id = #{userId}
AND status = 1
LIMIT 1
</select>
<!-- 解封指定用户 -->
<update id="unbanUser">
UPDATE user_ban
SET status = 0
WHERE user_id = #{userId}
AND status = 1
</update>
<!-- 批量更新已过期的封禁信息 -->
<update id="updateExpiredBans">
UPDATE user_ban
SET status = 0
WHERE status = 1
AND ban_end_time IS NOT NULL
AND ban_end_time &lt; NOW()
</update>
</mapper>