SpringBoot交友APP项目实战(详细介绍+案例源码) 您所在的位置:网站首页 常州交友的微平台 SpringBoot交友APP项目实战(详细介绍+案例源码)

SpringBoot交友APP项目实战(详细介绍+案例源码)

2024-06-30 04:06| 来源: 网络整理| 查看: 265

想当个黑客 吼吼吼…

在这里插入图片描述

系列文章目录

1. 项目介绍及环境配置 2. 短信验证码登录 3. 用户信息 4. MongoDB 5. 推荐好友列表/MongoDB集群/动态发布与查看 6. 圈子动态/圈子互动 7. 即时通讯(基于第三方API) 8. 附近的人(百度地图APi) 9. 小视频 10.网关配置 11.后台管理

文章目录 系列文章目录一、 功能介绍二、 环境搭建1. MYSQL数据库2. Nginx3. 引入 admin 模块4. 创建实体类 三、 管理员登录1. 需求分析2. 获取图片验证码⑴. 接口文档⑵. 编码实现⑶. 测试⑷. 页面展示 3. 登录⑴. 接口文档⑵. 编码实现①. Controller②. Service ⑶. 页面效果 4. 查询用户资料⑴. 接口文档⑵. 编码实现①. vo对象②. Controller③. Service ⑶. 页面效果 四、 用户信息管理1. 查询用户列表⑴. 接口文档⑵. 编码实现①. Controller②. Service③. Api④. ApiImpl ⑶. 页面效果 2. 查询用户详情⑴. 接口文档⑵. 编码实现①. Controller②. Service ⑶. 页面效果 3. 查询视频列表⑴. 接口文档⑵. 编码实现①. Controller②. Service③. Api④. ApiImpl ⑶. 页面效果 4. 查询动态列表⑴. 接口文档⑵. 编码实现①. Controller②. Service③. Api④. ApiImpl ⑶. 页面效果 5. 用户冻结⑴. 需求分析⑵. 冻结①. 接口文档②. Controller③. Service④. 页面效果 ⑶. 解冻①. 接口文档②. Controller③. Service④. 页面效果 ⑷. 登录校验①. 公共类②. Service 五、 数据统计1. 数据采集⑴. 需求分析⑵. 发送日志消息①. RabbitMQ依赖②. 消息类型③. 编码实现Ⅰ. yml文件Ⅱ. 工具类 - 发送消息Ⅲ. 登录 - 发送日志消息Ⅳ. 动态 - 发送日志消息 ⑶. 获取消息内容①. 实体类Ⅰ. LogⅡ. Analysis ②. MapperⅠ. LogMapperⅡ. AnalysisMapper ③. 拦截器④. 测试 2. 定时任务⑴. 概述⑵. 入门案例①. 启动类②. 测试类③. 打印结果 ⑶. CRON表达式⑷. 数据统计①. 定时器②. Mapper③. Service④. 添加测试数据 六、 内容审核1. 阿里云内容审核⑴. 阿里云安全①. 技术选型②. 阿里云 - 内容安全③. AccessKey管理④. SDK文档 ⑵. 入门案例①. yml配置②. Properties③. template④. 启动类⑤. 测试类⑥. 测试结果 ⑶. 发送动态审核消息①. Api②. ApiImpl③. Service ⑷. 后台系统获取消息①. 动态拦截器②. Api③. ApiImpl ⑸. 完善查询动态接口 七、 推荐系统1. 理论知识⑴. 电商是推荐系统的先行者⑵. 推荐系统业务流程⑶. 协同过滤推荐算法①. 基于用户的推荐 UserCF②. 基于商品的推荐 ItemCF ⑷. ALS算法 2. 用户推荐⑴. 流程⑵. 评分规则⑶. 推荐系统部署①. docker②. SQL数据库 ⑷. 测试 3. 动态推荐⑴. 需求分析①. 流程说明②. 流程说明③. 评分规则 ⑵. 创建数据采集系统①. 新模块②. pom依赖③. yml配置文件④. 启动类⑤. 实体类 ⑶. 动态监听器 4. 视频推荐⑴. 需求分析①. 流程说明②. 评分规则 ⑵. 视频监听器①. 实体类②. 监听器③. 发送日志消息 ⑶. 测试

一、 功能介绍

探花交友APP建立的后台管理系统,目的是完成探花交友项目的业务闭环,主要功能包括:用户管理、动态管理、审核管理以及系统管理。(实现的功能有:登录、首页、用户管理、动态审核)

在这里插入图片描述

二、 环境搭建 1. MYSQL数据库

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

在这里插入图片描述

新建连接 -> MySQL 在这里插入图片描述

运行SQL文件 在这里插入图片描述

表名称说明tb_admin管理员用户表tb_analysis统计数据表tb_log用户操作日志记录表tb_freeze_detail冻结用户记录 2. Nginx

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

在这里插入图片描述

解压后: 在这里插入图片描述

# 运行方式 # 1. 直接双击 nginx.exe # 2. 命令 cd nginx根目录 start nginx

浏览器输入 http://localhost:8088/ 在这里插入图片描述

3. 引入 admin 模块

网盘资源地址(不需要密码): https://pan.baidu.com/s/1daL566ehyZuQ6s5vzXYNpA?pwd=java

在这里插入图片描述

粘贴至 tanhua 项目文件根目录 -> 文件 -> 新建 -> 来自现有源代码的模块 在这里插入图片描述

4. 创建实体类

新建 tanhua-model/src/main/java/com/tanhua/model/domain/Admin.java 文件:

//后台系统的管理员对象 @Data @NoArgsConstructor @AllArgsConstructor public class Admin implements Serializable { /** * id */ private Long id; /** * 用户名 */ private String username; /** * 密码 */ private String password; /** * 头像 */ private String avatar; } 三、 管理员登录 1. 需求分析 页面刷新时,自动发送获取验证码请求到服务端输入验证码登录,登录成功返回token通过token获取用户详情,跳转主页 2. 获取图片验证码 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现

在这里插入图片描述 编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/SystemController.java 文件:

@RestController @RequestMapping("/system/users") public class SystemController { @Autowired private AdminService adminService; @Autowired private RedisTemplate redisTemplate; // 获取验证码图片 @GetMapping("/verification") public void verification(String uuid, HttpServletResponse response) throws IOException { // 1. 生成验证码对象 LineCaptcha captcha = CaptchaUtil.createLineCaptcha(299, 97); // 2. 验证码存入redis String code = captcha.getCode(); redisTemplate.opsForValue().set(Constants.CAP_CODE + uuid, code); // 3. 输出验证码图片 captcha.write(response.getOutputStream()); } } ⑶. 测试

浏览器输入 localhost:18083//system/users/verification?uuid=123 : 在这里插入图片描述

改为 网关请求: 浏览器输入 localhost:8888/admin/system/users/verification?uuid=123 页面不变

⑷. 页面展示

在这里插入图片描述

3. 登录 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现

在这里插入图片描述

①. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/SystemController.java 文件:

/** * 用户登录: */ @PostMapping("/login") public ResponseEntity login(@RequestBody Map map) { Map retMap = adminService.login(map); return ResponseEntity.ok(retMap); } ②. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/AdminService.java 文件:

// 用户登录 public Map login(Map map) { //1、获取请求的参数(username,password,verificationCode(验证码),uuid) String username = (String) map.get("username"); String password = (String) map.get("password"); String verificationCode = (String) map.get("verificationCode"); String uuid = (String) map.get("uuid"); //2、判断用户名或者密码是否为空 if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) { //用户名或者密码为空 throw new BusinessException("用户名或者密码为空"); } //3、判断验证码是否正确 if (StringUtils.isEmpty(username)) { //验证码为空 throw new BusinessException("验证码为空"); } //从redis中获取验证码 String key = Constants.CAP_CODE+uuid; String code = redisTemplate.opsForValue().get(key); if (StringUtils.isEmpty(code) || !code.equals(verificationCode)) { //验证码错误 throw new BusinessException("验证码错误"); } redisTemplate.delete(key); //4、根据用户名查询用户 QueryWrapper qw = new QueryWrapper().eq("username", username); Admin admin = adminMapper.selectOne(qw); //5、判断用户是否存在,密码是否一致 password = SecureUtil.md5(password); //md5加密 if(admin == null || !admin.getPassword().equals(password)) { //用户名错误或者密码不一致 throw new BusinessException("用户名或者密码"); } //6、通过JWT生成token Map claims = new HashMap(); claims.put("username", username); claims.put("id", admin.getId()); String token = JwtUtils.getToken(claims); //8、构造返回值 Map resMap = new HashMap(); resMap.put("token", token); return resMap; } ⑶. 页面效果

(暂时还不能实现跳转页面) 在这里插入图片描述

4. 查询用户资料 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现

博主在编写开发项目时,遇到无法处理的mysql版本问题,使用了跨过校验规则,如果遇到了同样的问题,可以查看下方gitee仓库地址(关键词:后台登录_跨过校验) Gitee仓库: https://gitee.com/yuan0_0/tanhua_20220918.git

①. vo对象

新建 tanhua-model/src/main/java/com/tanhua/model/vo/AdminVo.java 文件:

@Data @NoArgsConstructor @AllArgsConstructor public class AdminVo { // id private String id; // 用户名 private String username; // 头像 private String avatar; public static AdminVo init(Admin admin) { AdminVo vo = new AdminVo(); vo.setAvatar(admin.getAvatar()); vo.setUsername(admin.getUsername()); vo.setId(admin.getId().toString()); return vo; } } ②. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/SystemController.java 文件:

/** * 获取用户的信息 */ @PostMapping("/profile") public ResponseEntity profile() { AdminVo vo = adminService.profile(); return ResponseEntity.ok(vo); } ③. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/AdminService.java 文件:

// 获取用户信息 public AdminVo profile() { Long userId = AdminHolder.getUserId(); Admin admin = adminMapper.selectById(userId); return AdminVo.init(admin); } ⑶. 页面效果

在这里插入图片描述 在这里插入图片描述

四、 用户信息管理

后台管理系统可以对所有注册用户进行统一管理。如查看用户列表,用户详情,用户发布的视频/动态等

1. 查询用户列表 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现 ①. Controller

新建 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

@RestController @RequestMapping("/manage") public class ManageController { @Autowired private ManagerService managerService; /** * 查询用户列表 */ @GetMapping("/users") public ResponseEntity users(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pagesize) { PageResult result = managerService.findAllUsers(page,pagesize); return ResponseEntity.ok(result); } } ②. Service

新建 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

@Service public class ManagerService { @DubboReference private UserInfoApi userInfoApi; // 查询用户列表 public PageResult findAllUsers(Integer page, Integer pagesize) { IPage iPage = userInfoApi.findALL(page, pagesize); return new PageResult(page, pagesize, iPage.getTotal(), iPage.getRecords()); } } ③. Api

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/UserInfoApi.java 文件:

// 分页查询 IPage findALL(Integer page, Integer pagesize); ④. ApiImpl

编辑 tanhua-dubbo/tanhua-dubbo-db/src/main/java/com/tanhua/dubbo/api/UserInfoApiImpl.java 文件:

// 分页查询 @Override public IPage findALL(Integer page, Integer pagesize) { return userInfoMapper.selectPage(new Page(page, pagesize), null); } ⑶. 页面效果

浏览器输入 http://127.0.0.1:8088 : 在这里插入图片描述

2. 查询用户详情 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现 ①. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

/** * 查询用户详情 */ @GetMapping("/users/{userId}") public ResponseEntity findUserById(@PathVariable("userId") Long userId) { UserInfo userInfo = managerService.findUserById(userId); return ResponseEntity.ok(userInfo); } ②. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

// 查询用户详情 public UserInfo findUserById(Long userId) { return userInfoApi.findById(userId); } ⑶. 页面效果

在这里插入图片描述

3. 查询视频列表 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现 ①. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

/** * 查询视频列表 */ @GetMapping("/videos") public ResponseEntity videos(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pagesize, Long uid ) { PageResult result = managerService.findAllVideos(page,pagesize,uid); return ResponseEntity.ok(result); } ②. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

// 查询视频列表 public PageResult findAllVideos(Integer page, Integer pagesize, Long uid) { return videoApi.findByUserId(page, pagesize, uid); } ③. Api

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/VideoApi.java 文件:

// 根据用户id查询 PageResult findByUserId(Integer page, Integer pagesize, Long userId); ④. ApiImpl

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/VideoApiImpl.java 文件:

// 根据用户id查询 @Override public PageResult findByUserId(Integer page, Integer pagesize, Long userId) { Query query = Query.query(Criteria.where("userId").in(userId)); long count = mongoTemplate.count(query, Video.class); query.skip((page - 1) * pagesize).limit(pagesize) .with(Sort.by(Sort.Order.desc("created"))); List list = mongoTemplate.find(query, Video.class); return new PageResult(page, pagesize, count, list); } ⑶. 页面效果

在这里插入图片描述 在这里插入图片描述

4. 查询动态列表 ⑴. 接口文档

在这里插入图片描述

⑵. 编码实现 ①. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

/** * 查询动态列表 */ @GetMapping("/messages") public ResponseEntity messages(@RequestParam(defaultValue = "1") Integer page, @RequestParam(defaultValue = "10") Integer pagesize, Long uid,Integer state ) { PageResult result = managerService.findAllMovements(page,pagesize,uid,state); return ResponseEntity.ok(result); } ②. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

// 查询动态列表 public PageResult findAllMovements(Integer page, Integer pagesize, Long uid, Integer state) { //1、调用API查询数据 :Movment对象 PageResult result = movementApi.findByUserId(uid, state, page, pagesize); //2、解析PageResult,获取Movment对象列表 List items = (List) result.getItems(); //3、一个Movment对象转化为一个Vo if(CollUtil.isEmpty(items)) { return new PageResult(); } List userIds = CollUtil.getFieldValues(items, "userId", Long.class); Map map = userInfoApi.findByIds(userIds, null); List vos = new ArrayList(); for (Movement movement : items) { UserInfo userInfo = map.get(movement.getUserId()); if(userInfo != null) { MovementsVo vo = MovementsVo.init(userInfo, movement); vos.add(vo); } } //4、构造返回值 result.setItems(vos); return result; } ③. Api

编辑 tanhua-dubbo/tanhua-dubbo-interface/src/main/java/com/tanhua/dubbo/api/MovementApi.java 文件:

// 根据用户id,查询 PageResult findByUserId(Long uid, Integer state, Integer page, Integer pagesize); ④. ApiImpl

编辑 tanhua-dubbo/tanhua-dubbo-mongo/src/main/java/com/tanhua/dubbo/api/MovementApiImpl.java 文件:

// 根据用户id,查询 @Override public PageResult findByUserId(Long uid, Integer state, Integer page, Integer pagesize) { Query query = new Query(); if(uid != null) { query.addCriteria(Criteria.where("userId").is(uid)); } if(state != null) { query.addCriteria(Criteria.where("state").is(state)); } long count = mongoTemplate.count(query, Movement.class); query.with(Sort.by(Sort.Order.desc("created"))).limit(pagesize).skip((page -1) * pagesize); List list = mongoTemplate.find(query, Movement.class); return new PageResult(page,pagesize,count,list); } ⑶. 页面效果

在这里插入图片描述

5. 用户冻结 ⑴. 需求分析

用户冻结/解冻是管理员在后台系统对用户的惩罚措施。对于发布不当言论或者违法违规内容的用户,可以暂时、永久禁止其登录,评论,发布动态、

Mysql数据库 使用Mysql记录冻结数据,记录冻结状态。对于临时性冻结,需要配合定时任务扫描进行解冻 Redis 使用Redis记录冻结数据,借助Redis的失效时间对临时性冻结解冻

在这里插入图片描述

⑵. 冻结 ①. 接口文档

在这里插入图片描述

②. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

/** * 用户冻结 */ @PostMapping("/users/freeze") public ResponseEntity freeze(@RequestBody Map params) { Map map = managerService.userFreeze(params); return ResponseEntity.ok(map); } ③. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

// 用户冻结 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); } // 4. 构造返回值 Map retMap = new HashMap(); retMap.put("message", "冻结成功"); return retMap; } ④. 页面效果

在这里插入图片描述 在这里插入图片描述

⑶. 解冻 ①. 接口文档

在这里插入图片描述

②. Controller

编辑 tanhua-admin/src/main/java/com/tanhua/admin/controller/ManageController.java 文件:

/** * 用户解冻 */ @PostMapping("/users/unfreeze") public ResponseEntity unfreeze(@RequestBody Map params) { Map map = managerService.userUnfreeze(params); return ResponseEntity.ok(map); } ③. Service

编辑 tanhua-admin/src/main/java/com/tanhua/admin/service/ManagerService.java 文件:

// 用户解冻 public Map userUnfreeze(Map params) { // 1. 构造key String userId = params.get("userId").toString(); String key = Constants.USER_FREEZE + userId; // 2. 删除redis数据 redisTemplate.delete(key); // 3. 构造返回值 Map retMap = new HashMap(); retMap.put("message", "解冻成功"); return retMap; } ④. 页面效果

在这里插入图片描述

⑷. 登录校验 ①. 公共类

新建 tanhua-app-server/src/main/java/com/tanhua/server/service/UserFreezeService.java 文件:

@Service public class UserFreezeService { @Autowired private RedisTemplate redisTemplate; 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()); } } } } ②. Service

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

/** * 发送短信验证码 * @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)); } 五、 数据统计 1. 数据采集 ⑴. 需求分析

后台系统首页中,显示各种统计数据,比如:累计用户数、新增用户数、登录次数等内容

在这里插入图片描述 用户日志表(tb_log): 在这里插入图片描述

0101-登录,0102-注册,0201-发动态,0202-查看,0203-点赞,0204-喜欢,0205-评论,0206-取消点赞,0207-取消喜欢0301-发视频,0302-视频点赞,0303-视频取消点赞,0304-视频评论

日统计表(tb_analysis): 在这里插入图片描述

⑵. 发送日志消息 ①. RabbitMQ依赖

探花交友项目所需的第三方服务组件,已经以Docker-Compose准备好了。仅仅需要进入相关目录,以命令形式启动运行即可

# 进入目录 cd /root/docker-file/rmq/ # 创建容器并启动 docker-compose up –d # 查看容器 docker ps -a

在这里插入图片描述

②. 消息类型

探花项目间使用RabbitMQ收发消息,这里采用topic类型消息 日志消息key规则:log.xxx 在这里插入图片描述

③. 编码实现 Ⅰ. yml文件

编辑 tanhua-app-server/src/main/resources/application.yml 文件:

server: port: 18080 spring: profiles: active: prod application: name: tanhua-app-server cloud: nacos: discovery: server-addr: 192.168.136.160:8848 config: server-addr: 192.168.136.160:8848 file-extension: yml Ⅱ. 工具类 - 发送消息

新建 tanhua-app-server/src/main/java/com/tanhua/server/service/MqMessageService.java 文件:

@Service public class MqMessageService { @Autowired private AmqpTemplate amqpTemplate; //发送日志消息 public void sendLogMessage(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 sendAudiMessage(String movementId) { try { amqpTemplate.convertAndSend("tanhua.audit.exchange", "audit.movement",movementId); } catch (AmqpException e) { e.printStackTrace(); } } } Ⅲ. 登录 - 发送日志消息

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/UserService.java 文件:

/** * 验证登录 * @param phone * @param code */ public Map loginVerification(String phone, String code) { // 1. 从redis中获取验证码 String redisCode = redisTemplate.opsForValue().get("CHECK_CODE_" + phone); // 2. 对验证码进行校验 if(StringUtils.isEmpty(redisCode) || !redisCode.equals(code)) { // throw new RuntimeException("验证码错误"); throw new BusinessException(ErrorResult.loginError()); } // 3. 删除redis中的验证码 redisTemplate.delete("CHECK_CODE_" + phone); // 4. 通过手机号查询用户 User user = userApi.findByMobile(phone); boolean isNew = false; // 5. 如果用户不存在,创建用户保存到数据库 String type = "0101"; // 登录 if(user == null) { type = "0102"; // 注册 user = new User(); user.setMobile(phone); // user.setCreated(new Date()); // user.setUpdated(new Date()); user.setPassword(DigestUtils.md5Hex("123456")); Long userId = userApi.save(user); user.setId(userId); isNew = true; // 注册环信用户 String hxUser = "hx" + user.getId(); Boolean create = huanXinTemplate.createUser(hxUser, Constants.INIT_PASSWORD); if(create) { user.setHxUser(hxUser); user.setHxPassword(Constants.INIT_PASSWORD); userApi.update(user); } } // 发送日志消息 // try { // Map map = new HashMap(); // map.put("userId", user.getId().toString()); // map.put("type", type); // map.put("logTime", new SimpleDateFormat("yyyy-MM-dd").format(new Date())); // String message = JSON.toJSONString(map); // amqpTemplate.convertAndSend("tanhua.log.exchange", "log.user", message); // } catch (Exception e) { // e.printStackTrace(); // } mqMessageService.sendLogMessage(user.getId(), type, "user", null); // 6. 通过JWT生成token(存入手机号和用户ID) Map tokenMap = new HashMap(); tokenMap.put("id", user.getId()); tokenMap.put("mobile", phone); String token = JwtUtils.getToken(tokenMap); // 7. 构造返回值 Map retMap = new HashMap(); retMap.put("token", token); retMap.put("isNew", isNew); return retMap; } Ⅳ. 动态 - 发送日志消息

编辑 tanhua-app-server/src/main/java/com/tanhua/server/service/MovementService.java 文件:

// 查询单条动态 public MovementsVo findById(String movementId) { // 发送日志 mqMessageService.sendLogMessage(UserHolder.getUserId(), "0202", "movement", movementId); // 1. 调用API查询动态详情 Movement movement = movementApi.findById(movementId); // 2. 转换vo对象 if(movement != null) { UserInfo userInfo = userInfoApi.findById(movement.getUserId()); return MovementsVo.init(userInfo, movement); } else { return null; } } ⑶. 获取消息内容 ①. 实体类 Ⅰ. Log

新建 tanhua-model/src/main/java/com/tanhua/model/domain/Log.java 文件:

@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

新建 tanhua-model/src/main/java/com/tanhua/model/domain/Analysis.java 文件:

@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; } ②. Mapper Ⅰ. LogMapper

新建 tanhua-admin/src/main/java/com/tanhua/admin/mapper/LogMapper.java 文件:

public interface LogMapper extends BaseMapper { } Ⅱ. AnalysisMapper

新建 tanhua-admin/src/main/java/com/tanhua/admin/mapper/AnalysisMapper.java 文件:

public interface AnalysisMapper extends BaseMapper { } ③. 拦截器

新建 tanhua-admin/src/main/java/com/tanhua/admin/listener/LogListener.java 文件:

@Component public class LogListener { @Autowired private LogMapper logMapper; @RabbitListener( bindings = @QueueBinding( value = @Queue( value = "tanhua.log.queue", durable = "true" ), exchange = @Exchange( value = "tanhua.log.exchange", type = ExchangeTypes.TOPIC), key = {"log.*"} ) ) public void log(String message) { try { Map map = JSON.parseObject(message, Map.class); map.forEach((k, v) -> System.out.println(k + "--" + v)); // 1. 解析map获取数据 Long userId = Long.valueOf(map.get("userId").toString()); String type = (String) map.get("type"); String logTime = (String) map.get("logTime"); // 2. 构造log对象,保存到数据库 Log log = new Log(userId, logTime, type); logMapper.insert(log); } catch (NumberFormatException e) { e.printStackTrace(); } } } ④. 测试

在这里插入图片描述

2. 定时任务 ⑴. 概述

定时任务调度,一句话概括就是:基于给定的时间点、给定的时间间隔、自动执行的任务

java自带的API、java.util.Timer类、java.util.TimerTask类Quartz框架、开源、功能强大、使用起来稍显复杂Spring 3.0以后自带了task 调度工具,比Quartz更加的简单方便 ⑵. 入门案例 ①. 启动类

编辑 tanhua-admin/src/main/java/com/tanhua/admin/AdminServerApplication.java 文件:

@SpringBootApplication(exclude = {MongoAutoConfiguration.class, MongoDataAutoConfiguration.class}) @MapperScan("com.tanhua.admin.mapper") @EnableScheduling // 开启定时任务 public class AdminServerApplication { public static void main(String[] args) { SpringApplication.run(AdminServerApplication.class,args); } } ②. 测试类

编辑 tanhua-admin/src/main/java/com/tanhua/admin/task/AnalysisTask.java 文件:

@Component public class AnalysisTask { /** * 配置时间规则: 每5秒执行一次 */ @Scheduled( cron = "0/5 * * * * ? ") public void analysis() { //业务逻辑 String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); System.out.println("当前时间:"+time); } } ③. 打印结果

在这里插入图片描述

⑶. CRON表达式 Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义corn从左到右(用空格隔开):秒 分 时 期 月 周 年

Cron 表达式支持到六个域

名称是否必须允许值特殊字符秒是0-59, - * /分是0-59, - * /时是0-23, - * /日是1-31, - * ? / L W C月是1-12 或 JAN-DEC, - * /周是1-7 或 SUN-SAT, - * ? / L C # *:匹配该域的任意值?:忽略该域,只能用在周和日两个域。因为二者会相互影响-:表示范围。例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次/:表示起始时间开始触发,然后每隔固定时间触发一次,:表示列出枚举值

示例:

0 15 10 ? * * - 每天上午10:15触发0 15 10 * * ? - 每天上午10:15触发0 * 14 * * ? - 在每天下午2点到下午2:59期间的每1分钟触发0 0/5 14 * * ? - 在每天下午2点到下午2:55期间的每5分钟触发0 0/5 14,18 * * ? - 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发 ⑷. 数据统计 ①. 定时器

编辑 tanhua-admin/src/main/java/com/tanhua/admin/task/AnalysisTask.java 文件:

@Component public class AnalysisTask { @Autowired private AnalysisService analysisService; /** * 配置时间规则: 每5秒执行一次 */ @Scheduled( cron = "0/10 * * * * ? ") public void analysis() { //业务逻辑 String time = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()); System.out.println("当前时间:"+time); try { analysisService.analysis(); } catch (Exception e) { e.printStackTrace(); } } } ②. Mapper

编辑 tanhua-admin/src/main/java/com/tanhua/admin/mapper/LogMapper.java 文件:

public interface LogMapper extends BaseMapper { @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE TYPE=#{type} AND log_time=#{logTime}") Integer queryByTypeAndLogTime(@Param("type") String type, @Param("logTime") String logTime); //根据操作时间和类型 @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE log_time=#{logTime}") Integer queryByLogTime(String logTime); //展示记录时间查询 @Select("SELECT COUNT(DISTINCT user_id) FROM tb_log WHERE log_time=#{today} AND user_id IN (\n " + " SELECT user_id FROM tb_log WHERE TYPE=\"0102\" AND log_time=#{yestoday} \n " + ")") Integer queryNumRetention1d(@Param("today") String today,@Param("yestoday") String yestoday); //查询次日留存 } ③. Service

新建 tanhua-admin/src/main/java/com/tanhua/admin/service/AnalysisService.java 文件:

@Service public class AnalysisService { @Autowired private LogMapper logMapper; @Autowired private AnalysisMapper analysisMapper; /** * 定时统计日志数据到统计表中 */ public void analysis() throws ParseException { // 1、查询tb_log表中的数 (每日注册用户数,每日登陆用户,活跃的用户数据,次日留存的用户) // 1.1 定义查询的日期 String todayStr = new SimpleDateFormat("yyyy-MM-dd").format(new Date()); String yesTodayStr = DateUtil.yesterday().toString("yyyy-MM-dd"); // 1.2 统计数据 - 注册用户数 Integer regCount = logMapper.queryByTypeAndLogTime("0102",todayStr); // 1.3 统计数据 - 登陆用户 Integer loginCount = logMapper.queryByTypeAndLogTime("0101",todayStr); // 1.4 统计数据 - 活跃用户 Integer activeCount = logMapper.queryByLogTime(todayStr); // 1.5 统计数据 - 次日留存 Integer numRetention1d = logMapper.queryNumRetention1d(todayStr, yesTodayStr); // 2. 构造Analysis对象 // 2.1 根据日期查询书库 QueryWrapper qw = new QueryWrapper(); qw.eq("record_date", new SimpleDateFormat("yyyy-MM-dd").parse(todayStr)); Analysis analysis = analysisMapper.selectOne(qw); // 3、完成统计数据的更新或者保存 if(analysis != null) { // 3.1 如果存在,就更新 analysis.setNumRegistered(regCount); analysis.setNumLogin(loginCount); analysis.setNumActive(activeCount); analysis.setNumRetention1d(numRetention1d); analysisMapper.updateById(analysis); } else { // 3.2 如果不存在,就保存 analysis = new Analysis(); analysis.setNumRegistered(regCount); analysis.setNumLogin(loginCount); analysis.setNumActive(activeCount); analysis.setNumRetention1d(numRetention1d); analysis.setRecordDate(new SimpleDateFormat("yyyy-MM-dd").parse(todayStr)); analysis.setCreated(new Date()); analysisMapper.insert(analysis); } } } ④. 添加测试数据

新建 tanhua-admin/src/test/java/com/tanhua/admin/LogTest.java 文件:

@RunWith(SpringRunner.class) @SpringBootTest public class LogTest { @Autowired private LogMapper logMapper; // 输入想创建日志的日期时间 private String logTime = "2022-11-30"; //模拟登录数据 public void testInsertLoginLog() { for (int i = 0; i


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有