Compare commits
4 Commits
feature-Da
...
6d95b8d391
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6d95b8d391 | ||
|
|
1c2a4edae9 | ||
|
|
088c94e723 | ||
|
|
a3d0d7423c |
51
src/main/java/com/bao/dating/controller/AdminController.java
Normal file
51
src/main/java/com/bao/dating/controller/AdminController.java
Normal file
@@ -0,0 +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<UserBan> banInfo(@PathVariable Long userId) {
|
||||||
|
|
||||||
|
UserBan ban = userBanService.getActiveBan(userId);
|
||||||
|
return Result.success(ResultCode.SUCCESS, "查询成功", ban);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,66 +0,0 @@
|
|||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,17 +1,17 @@
|
|||||||
package com.bao.dating.controller;
|
package com.bao.dating.controller;
|
||||||
|
|
||||||
|
|
||||||
|
import com.bao.dating.anno.Log;
|
||||||
import com.bao.dating.common.Result;
|
import com.bao.dating.common.Result;
|
||||||
import com.bao.dating.common.ResultCode;
|
import com.bao.dating.common.ResultCode;
|
||||||
import com.bao.dating.pojo.dto.PostRequestDTO;
|
import com.bao.dating.pojo.dto.PostRequestDTO;
|
||||||
import com.bao.dating.pojo.entity.Post;
|
import com.bao.dating.pojo.entity.Post;
|
||||||
import com.bao.dating.pojo.vo.PostEditVO;
|
import com.bao.dating.pojo.vo.PostEditVO;
|
||||||
import com.bao.dating.service.PostService;
|
import com.bao.dating.service.PostService;
|
||||||
import com.bao.dating.util.DataAnalysisRedisService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -26,9 +26,6 @@ public class PostController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PostService postService;
|
private PostService postService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DataAnalysisRedisService dataAnalysisRedisService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 上传媒体文件接口 like
|
* 上传媒体文件接口 like
|
||||||
* @param files 媒体文件数组
|
* @param files 媒体文件数组
|
||||||
@@ -49,9 +46,6 @@ public class PostController {
|
|||||||
public Result<Post> createPostJson(@RequestBody PostRequestDTO postDTO) {
|
public Result<Post> createPostJson(@RequestBody PostRequestDTO postDTO) {
|
||||||
// 调用 Service 层处理发布动态业务逻辑
|
// 调用 Service 层处理发布动态业务逻辑
|
||||||
Post result = postService.createPost(postDTO);
|
Post result = postService.createPost(postDTO);
|
||||||
//这里将发布动态操作记录到redis中
|
|
||||||
Long postId = result.getPostId();
|
|
||||||
dataAnalysisRedisService.recordPostData(postId);
|
|
||||||
return Result.success(ResultCode.SUCCESS, "动态发布成功,等待审核。", result);
|
return Result.success(ResultCode.SUCCESS, "动态发布成功,等待审核。", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,13 +9,11 @@ import com.bao.dating.pojo.dto.UserLoginDTO;
|
|||||||
import com.bao.dating.pojo.vo.UserInfoVO;
|
import com.bao.dating.pojo.vo.UserInfoVO;
|
||||||
import com.bao.dating.pojo.vo.UserLoginVO;
|
import com.bao.dating.pojo.vo.UserLoginVO;
|
||||||
import com.bao.dating.service.UserService;
|
import com.bao.dating.service.UserService;
|
||||||
import com.bao.dating.util.DataAnalysisRedisService;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.annotation.Resource;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -31,9 +29,6 @@ public class UserController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private UserService userService;
|
private UserService userService;
|
||||||
|
|
||||||
@Resource
|
|
||||||
private DataAnalysisRedisService dataAnalysisRedisService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 登录
|
* 登录
|
||||||
* @param userLoginDTO 登录参数
|
* @param userLoginDTO 登录参数
|
||||||
@@ -41,12 +36,6 @@ public class UserController {
|
|||||||
@PostMapping("/login")
|
@PostMapping("/login")
|
||||||
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
|
public Result<UserLoginVO> login(@RequestBody UserLoginDTO userLoginDTO) {
|
||||||
UserLoginVO userloginVO = userService.userLogin(userLoginDTO);
|
UserLoginVO userloginVO = userService.userLogin(userLoginDTO);
|
||||||
//将用户登录记录到redis中
|
|
||||||
if (userloginVO != null){
|
|
||||||
Long userId = userloginVO.getUserId();
|
|
||||||
dataAnalysisRedisService.recordLoginUserData(userId);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Result.success(ResultCode.SUCCESS, "登录成功", userloginVO);
|
return Result.success(ResultCode.SUCCESS, "登录成功", userloginVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,11 +128,6 @@ public class UserController {
|
|||||||
}
|
}
|
||||||
//登录
|
//登录
|
||||||
UserLoginVO vo = userService.loginByPhone(phone);
|
UserLoginVO vo = userService.loginByPhone(phone);
|
||||||
//将用户登录操作记录到redis中
|
|
||||||
if (vo != null){
|
|
||||||
Long userId = vo.getUserId();
|
|
||||||
dataAnalysisRedisService.recordLoginUserData(userId);
|
|
||||||
}
|
|
||||||
return Result.success(ResultCode.SUCCESS, "登录成功", vo);
|
return Result.success(ResultCode.SUCCESS, "登录成功", vo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,9 +200,6 @@ public class UserController {
|
|||||||
if (userLoginVO == null){
|
if (userLoginVO == null){
|
||||||
return Result.error(ResultCode.FAIL,"请先注册用户或添加邮箱");
|
return Result.error(ResultCode.FAIL,"请先注册用户或添加邮箱");
|
||||||
}
|
}
|
||||||
//将用户登录操作记录到redis中
|
|
||||||
Long userId = userLoginVO.getUserId();
|
|
||||||
dataAnalysisRedisService.recordLoginUserData(userId);
|
|
||||||
return Result.success(ResultCode.SUCCESS,"用户登录成功",userLoginVO);
|
return Result.success(ResultCode.SUCCESS,"用户登录成功",userLoginVO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ public class TokenInterceptor implements HandlerInterceptor {
|
|||||||
}
|
}
|
||||||
// 从 header 获取 token
|
// 从 header 获取 token
|
||||||
String token = request.getHeader("token");
|
String token = request.getHeader("token");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
log.info("jwt校验: {}", token);
|
log.info("jwt校验: {}", token);
|
||||||
|
|
||||||
// 验证 token 是否有效(包括是否过期)
|
// 验证 token 是否有效(包括是否过期)
|
||||||
if (!JwtUtil.validateToken(token)) {
|
if (!JwtUtil.validateToken(token)) {
|
||||||
log.error("Token无效或已过期");
|
log.error("Token无效或已过期");
|
||||||
@@ -66,10 +66,22 @@ public class TokenInterceptor implements HandlerInterceptor {
|
|||||||
response.getWriter().write("登录已失效, 请重新登录");
|
response.getWriter().write("登录已失效, 请重新登录");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析 token
|
// 解析 token
|
||||||
Long userId = Long.valueOf(JwtUtil.getSubjectFromToken(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进行比对
|
// 从Redis获取存储的token进行比对
|
||||||
Object redisTokenObj = redisTemplate.opsForValue().get("login:token:" + userId);
|
Object redisTokenObj = redisTemplate.opsForValue().get("login:token:" + userId);
|
||||||
String redisToken = redisTokenObj != null ? redisTokenObj.toString() : null;
|
String redisToken = redisTokenObj != null ? redisTokenObj.toString() : null;
|
||||||
|
|||||||
@@ -73,6 +73,14 @@ public class WsAuthInterceptor implements HandshakeInterceptor {
|
|||||||
|
|
||||||
Long userId = Long.valueOf(userIdStr);
|
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进行比对
|
// 从Redis获取存储的token进行比对
|
||||||
String redisTokenKey = "login:token:" + userId;
|
String redisTokenKey = "login:token:" + userId;
|
||||||
Object redisTokenObj = redisTemplate.opsForValue().get(redisTokenKey);
|
Object redisTokenObj = redisTemplate.opsForValue().get(redisTokenKey);
|
||||||
|
|||||||
43
src/main/java/com/bao/dating/mapper/UserBanMapper.java
Normal file
43
src/main/java/com/bao/dating/mapper/UserBanMapper.java
Normal file
@@ -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();
|
||||||
|
}
|
||||||
13
src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java
Normal file
13
src/main/java/com/bao/dating/pojo/dto/UserBanDTO.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
30
src/main/java/com/bao/dating/pojo/entity/UserBan.java
Normal file
30
src/main/java/com/bao/dating/pojo/entity/UserBan.java
Normal file
@@ -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;
|
||||||
|
}
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package com.bao.dating.pojo.vo;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public class DataAnalysisVO {
|
|
||||||
//所有总数
|
|
||||||
private Long total;
|
|
||||||
//时间段
|
|
||||||
private String timePeriod;
|
|
||||||
}
|
|
||||||
31
src/main/java/com/bao/dating/service/UserBanService.java
Normal file
31
src/main/java/com/bao/dating/service/UserBanService.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -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<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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,6 +20,7 @@ import com.bao.dating.util.CodeUtil;
|
|||||||
import com.bao.dating.util.FileUtil;
|
import com.bao.dating.util.FileUtil;
|
||||||
import com.bao.dating.util.JwtUtil;
|
import com.bao.dating.util.JwtUtil;
|
||||||
import com.bao.dating.util.MD5Util;
|
import com.bao.dating.util.MD5Util;
|
||||||
|
import com.bao.dating.util.UserBanUtil;
|
||||||
import io.jsonwebtoken.Claims;
|
import io.jsonwebtoken.Claims;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -66,6 +67,9 @@ public class UserServiceImpl implements UserService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private VerificationCodeService verificationCodeService;
|
private VerificationCodeService verificationCodeService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private UserBanUtil userBanValidator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用户登录
|
* 用户登录
|
||||||
*
|
*
|
||||||
@@ -92,6 +96,8 @@ public class UserServiceImpl implements UserService {
|
|||||||
if (!match) {
|
if (!match) {
|
||||||
throw new RuntimeException("密码错误");
|
throw new RuntimeException("密码错误");
|
||||||
}
|
}
|
||||||
|
// 用户封禁验证
|
||||||
|
userBanValidator.validateUserNotBanned(user.getUserId());
|
||||||
// 生成token
|
// 生成token
|
||||||
String token = JwtUtil.generateToken(String.valueOf(user.getUserId()));
|
String token = JwtUtil.generateToken(String.valueOf(user.getUserId()));
|
||||||
|
|
||||||
@@ -485,4 +491,4 @@ public class UserServiceImpl implements UserService {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
26
src/main/java/com/bao/dating/task/UserBanScheduleTask.java
Normal file
26
src/main/java/com/bao/dating/task/UserBanScheduleTask.java
Normal file
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,101 +0,0 @@
|
|||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
65
src/main/java/com/bao/dating/util/UserBanUtil.java
Normal file
65
src/main/java/com/bao/dating/util/UserBanUtil.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
50
src/main/resources/com/bao/dating/mapper/UserBanMapper.xml
Normal file
50
src/main/resources/com/bao/dating/mapper/UserBanMapper.xml
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
<?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 < NOW()
|
||||||
|
</update>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
Reference in New Issue
Block a user