课程总结
1、用户冻结/解冻
2、数据统计
使用RabbitMQ传递日志消息
SpringTask定时任务进行数据统计
不足之处:数据延迟
3、内容审核
基于RabbitMQ异步执行
阿里云内容审核
一. 用户冻结解冻
用户冻结/解冻使用管理员在后台系统对用户的惩罚措施。对于发布不当言论或者违法违规内容的用户,可以暂时、永久禁止其登录,评论,发布动态、
后台中解冻/冻结,就是将用户状态写入数据库中
APP端用户在进行登录,评论,发布动态时检测Redis中冻结状态
![image-20210629194728510](https://i-blog.csdnimg.cn/blog_migrate/b0959dcd833fd934f5d5f9ec6cfe6f9c.png)
1-1 用户冻结
1. 接口文档
2. ManageController
//用户冻结
@PostMapping("/users/freeze")
public ResponseEntity freeze(@RequestBody Map params) {
Map map = managerService.userFreeze(params);
return ResponseEntity.ok(map);
}
3. ManageService
//用户冻结
public Map userFreeze(Map params) {
//1、构造key
String userId = params.get("userId").toString();
String key = Constants.USER_FREEZE + userId;
//2、构造失效时间
Integer freezingTime = Integer.valueOf(params.get("freezingTime").toString()); //冻结时间,1为冻结3天,2为冻结7天,3为永久冻结
int days = 0;
if(freezingTime == 1) {
days = 3;
}else if(freezingTime == 2) {
days = 7;
}
//3、将数据存入redis
String value = JSON.toJSONString(params);
if(days>0) {
redisTemplate.opsForValue().set(key,value,days, TimeUnit.MINUTES);
}else {
redisTemplate.opsForValue().set(key,value);
}
Map retMap = new HashMap();
retMap.put("message","冻结成功");
return retMap;
}
1-2 用户解冻
1. 接口文档
![image-20220929202031405](https://i-blog.csdnimg.cn/blog_migrate/4b696aa48dcde84fcfabca67cd22a4ab.png)
2. ManageController
//用户解冻
@PostMapping("/users/unfreeze")
public ResponseEntity unfreeze(@RequestBody Map params) {
Map map = managerService.userUnfreeze(params);
return ResponseEntity.ok(map);
}
3. ManageService
//用户解冻
public Map userUnfreeze(Map params) {
Long userId = (Long) params.get("userId");
String reasonsForThawing = (String) params.get("reasonsForThawing");
//删除redis数据
redisTemplate.delete(Constants.FREEZE_USER+userId);
Map map = new HashMap();
map.put("message","解冻成功");
return map;
}
1-3 查询数据列表
1. UserInfo
添加字段
//用户状态,1为正常,2为冻结
@TableField(exist = false)
private String userStatus = "1";
2. ManageService
修改代码
public ResponseEntity findById(Long userId) {
UserInfo info = userInfoApi.findById(userId);
if(redisTemplate.hasKey(Constants.FREEZE_USER+info.getId())) {
info.setUserStatus("2");
}
return ResponseEntity.ok(info);
}
//用户列表
public PageResult findAllUsers(Integer page, Integer pagesize) {
IPage<UserInfo> iPage = userInfoApi.findAll(page, pagesize);
List<UserInfo> list = iPage.getRecords();
for (UserInfo userInfo : list) {
String key = Constants.USER_FREEZE + userInfo.getId();
if(redisTemplate.hasKey(key)) {
userInfo.setUserStatus("2");
}
}
return new PageResult(page, pagesize, iPage.getTotal(), iPage.getRecords());
}
1-4 判断用户是否冻结
用户登录, 发布评论, 发布动态判断冻结状态
登录, 评论, 发布动态对应不同的状态
@Service
public class UserFreezeService {
@Autowired
private RedisTemplate<String,String> redisTemplate;
/**
* 判断用户是否被冻结,已被冻结,抛出异常
* 参数:冻结范围,用户id
*
* 检测登录:
* checkUserStatus(“1”,106)
*/
public void checkUserStatus(String state,Long userId) {
//1、拼接key,从redis中查询数据
String key = Constants.USER_FREEZE + userId;
String value = redisTemplate.opsForValue().get(key);
//2、如果数据存在,且冻结范围一致,抛出异常
if(!StringUtils.isEmpty(value)) {
Map map = JSON.parseObject(value, Map.class);
String freezingRange = (String) map.get("freezingRange");
if(state.equals(freezingRange)) {
throw new BusinessException(ErrorResult.builder().errMessage("用户被冻结").build());
}
}
}
}
1. 登录功能检测状态
往往在获取验证码是进行判断
UserService
/**
* 发送短信验证码
* @param phone
*/
public void sendMsg(String phone) {
//根据手机号查询用户,如果用户存在,判断是否被冻结
User user = userApi.findByMobile(phone);
if(user != null) {
userFreezeService.checkUserStatus("1",user.getId());
}
//1、随机生成6位数字
//String code = RandomStringUtils.randomNumeric(6);
String code = "123456";
//2、调用template对象,发送手机短信
//template.sendSms(phone,code);
//3、将验证码存入到redis
redisTemplate.opsForValue().set("CHECK_CODE_"+phone,code, Duration.ofMinutes(5));
}
二. 数据统计
2-1 解决方案
数据库表
2-2 数据采集
1、探花系统将用户操作日志写入RabbitMQ
2、管理后台获取最新消息,构造日志数据存入数据库
1. 部署RabbitMQ
探花交友所需的第三方服务组件,已经以Docker-Compose准备好了。仅仅需要进入相关目录,以命令形式启动运行即可
#进入目录
cd /root/docker-file/rmq/
#创建容器并启动
docker-compose up –d
#查看容器
docker ps -a
服务地址:192.168.136.160:5672
管理后台:http://192.168.136.160:15672/
2. 消息类型说明
探花项目间使用RabbitMQ收发消息,这里采用topic类型消息
日志消息key规则:log.xxx
步骤
3. 实体类对象
Log
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Log {
/**
* id
*/
private Long id;
/**
* 用户id
*/
private Long userId;
/**
* 操作时间
*/
private String logTime;
/**
* 操作类型,
* 0101为登录,0102为注册,
* 0201为发动态,0202为浏览动态,0203为动态点赞,0204为动态喜欢,0205为评论,0206为动态取消点赞,0207为动态取消喜欢,
* 0301为发小视频,0302为小视频点赞,0303为小视频取消点赞,0304为小视频评论
*/
private String type;
/**
* 登陆地点
*/
private String place;
/**
* 登陆设备
*/
private String equipment;
public Log(Long userId, String logTime, String type) {
this.userId = userId;
this.logTime = logTime;
this.type = type;
}
}
Analysis
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class Analysis{
private Long id;
/**
* 日期
*/
private Date recordDate;
/**
* 新注册用户数
*/
private Integer numRegistered = 0;
/**
* 活跃用户数
*/
private Integer numActive = 0;
/**
* 登陆次数
*/
private Integer numLogin = 0;
/**
* 次日留存用户数
*/
private Integer numRetention1d = 0;
private Date created;
}
4. 发送日志消息
消息发送工具类
@Service
public class MqMessageService {
@Autowired
private AmqpTemplate amqpTemplate;
//发送日志消息
public void sendLogService(Long userId,String type,String key,String busId) {
try {
Map map = new HashMap();
map.put("userId",userId.toString());
map.put("type",type);
map.put("logTime",new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
map.put("busId",busId);
String message = JSON.toJSONString(map);
amqpTemplate.convertAndSend("tanhua.log.exchange",
"log."+key,message);
} catch (AmqpException e) {
e.printStackTrace();
}
}
//发送动态审核消息
public void sendAudiService(String movementId) {
try {
amqpTemplate.convertAndSend("tanhua.audit.exchange",
"audit.movement",movementId);
} catch (AmqpException e) {