心链14-----项目功能完善补坑+自动跳转登录页 + 重复加入队伍问题(分布式锁) 并发请求问题解决 + 项目部署上线

本文主要是介绍心链14-----项目功能完善补坑+自动跳转登录页 + 重复加入队伍问题(分布式锁) 并发请求问题解决 + 项目部署上线,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

心链 — 伙伴匹配系统

一、todo

image.png

1、强制登录,自动跳转到登录页

解决:axios 全局配置响应拦截、并且添加重定向
1.在myAxios里配置响应拦截

image.png

这里我们要改变history 模式的实现,在main.ts里修改
image.png

当登录成功后,重定向到个人用户页面 PS:别忘了引入route
image.png

2.修改队伍页面的加入队伍按钮为创建队伍

在TeamPage页面,修改加入队伍为创建队伍(按钮部分)
把doJoinTeam全局修改为toAddTeam
这个按钮太丑了,我们更换它的样式,变成圆形放在右下角
image.png
写一个全局样式
image.png

在main.ts中引入
image.png

右下角的按钮:

image.png

3.区分公开和加密房间;加入有密码的房间,要指定密码

在TeamPage页面加入tabs标签,来区分公开还是加密
image.png

后端我们以前根据状态查询只查询公开,现在修改为当不是管理员和私人才会报权限错误

image.png

回到前端,我们在TeamPage页面实现onTabChange方法

image.png

上面定义的active是为了页面默认显示公开队伍
修改搜索队伍,传入状态

image.png

现在点击公开和加密可以切换查看不同类型的队伍
加密队伍需要输入密码才可以加入,我们这使用Dialog 弹出框组件,把它放入team-card-list.vue里(最下面的位置)

    <van-dialog v-model:show="showPasswordDialog" title="请输入密码" show-cancel-button @confirm="doJoinTeam" @cancel="doJoinCancel"><van-field v-model="password" placeholder="请输入密码"/></van-dialog>

在里面修改加入doJoinTeam方法,实现doJoinCancel方法和判断是不是加密房间preJoinTeam方法


/*** 加入队伍*/
const doJoinTeam = async () => {if (!joinTeamId.value){return;}const res = await myAxios.post('/team/join', {teamId: joinTeamId.value,password: password.value});if (res?.code === 0) {Toast.success('加入成功');doJoinCancel();} else {Toast.fail('加入失败' + (res.description ? `${res.description}` : ''));}
}const showPasswordDialog = ref(false);
const password = ref('');
const joinTeamId = ref(0);/*** 判断是不是加密房间,是的话显示密码框* @param team*/
const preJoinTeam = (team: TeamType) => {joinTeamId.value = team.id;if (team.status === 0) {doJoinTeam()} else {showPasswordDialog.value = true;}
}const doJoinCancel = () => {joinTeamId.value = 0;password.value = '';
}

在这里插入图片描述

测试加入队伍(加密)功能是否正常

点击加入队伍,输入密码
image.png
刷新一下,显示退出队伍,功能正常
image.png

4.展示已加入队伍人数

这个我们后端还未实现,所以在获取队伍列表接口,获取这个参数
首先在封装类里添加字段(TeamUserVO)
image.png
修改listTeams接口,修改整理为如下

@GetMapping("/list")public BaseResponse<List<TeamUserVO>> listTeams(TeamQuery teamQuery, HttpServletRequest request) {if (teamQuery == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}boolean isAdmin = userService.isAdmin(request);// 1、查询队伍列表List<TeamUserVO> teamList = teamService.listTeams(teamQuery, isAdmin);final List<Long> teamIdList = teamList.stream().map(TeamUserVO::getId).collect(Collectors.toList());// 2、判断当前用户是否已加入队伍QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();try {User loginUser = userService.getLoginUser(request);userTeamQueryWrapper.eq("userId", loginUser.getId());userTeamQueryWrapper.in("teamId", teamIdList);List<UserTeam> userTeamList = userTeamService.list(userTeamQueryWrapper);// 已加入的队伍 id 集合Set<Long> hasJoinTeamIdSet = userTeamList.stream().map(UserTeam::getTeamId).collect(Collectors.toSet());teamList.forEach(team -> {boolean hasJoin = hasJoinTeamIdSet.contains(team.getId());team.setHasJoin(hasJoin);});} catch (Exception e) {}// 3、查询已加入队伍的人数QueryWrapper<UserTeam> userTeamJoinQueryWrapper = new QueryWrapper<>();userTeamJoinQueryWrapper.in("teamId", teamIdList);List<UserTeam> userTeamList = userTeamService.list(userTeamJoinQueryWrapper);// 队伍 id => 加入这个队伍的用户列表Map<Long, List<UserTeam>> teamIdUserTeamList = userTeamList.stream().collect(Collectors.groupingBy(UserTeam::getTeamId));teamList.forEach(team -> team.setHasJoinNum(teamIdUserTeamList.getOrDefault(team.getId(), new ArrayList<>()).size()));return ResultUtils.success(teamList);}

在前端的TeamCardList里修改原来的最大人数为已加入人数
image.png

如果爆红的在队伍规范类型里添加字段
image.png
刷新页面,成功显示还当前队伍人数和最大人数
image.png

5.重复加入队伍的问题(加锁、分布式锁)并发请求时可能出现问题

只要我们点的足够快,就可以在同一时间内往数据库插入多条同样的数据,所以这里我们使用分布式锁(推荐)
使用两把锁,一把锁锁队伍,一把锁锁用户(实现较难,不推荐)
修改jointeam的实现方法

    @Overridepublic boolean joinTeam(TeamJoinRequest teamJoinRequest, User loginUser) {if (teamJoinRequest == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}Long teamId = teamJoinRequest.getTeamId();Team team = getTeamById(teamId);Date expireTime = team.getExpireTime();if (expireTime != null && expireTime.before(new Date())) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已过期");}Integer status = team.getStatus();TeamStatusEnum teamStatusEnum = TeamStatusEnum.getEnumByValue(status);if (TeamStatusEnum.PRIVATE.equals(teamStatusEnum)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "禁止加入私有队伍");}String password = teamJoinRequest.getPassword();if (TeamStatusEnum.SECRET.equals(teamStatusEnum)) {if (StringUtils.isBlank(password) || !password.equals(team.getPassword())) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");}}// 该用户已加入的队伍数量long userId = loginUser.getId();// 只有一个线程能获取到锁RLock lock = redissonClient.getLock("yupao:join_team");try {// 抢到锁并执行while (true) {if (lock.tryLock(0, -1, TimeUnit.MILLISECONDS)) {System.out.println("getLock: " + Thread.currentThread().getId());QueryWrapper<UserTeam> userTeamQueryWrapper = new QueryWrapper<>();userTeamQueryWrapper.eq("userId", userId);long hasJoinNum = userTeamService.count(userTeamQueryWrapper);if (hasJoinNum > 5) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "最多创建和加入 5 个队伍");}// 不能重复加入已加入的队伍userTeamQueryWrapper = new QueryWrapper<>();userTeamQueryWrapper.eq("userId", userId);userTeamQueryWrapper.eq("teamId", teamId);long hasUserJoinTeam = userTeamService.count(userTeamQueryWrapper);if (hasUserJoinTeam > 0) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户已加入该队伍");}// 已加入队伍的人数long teamHasJoinNum = this.countTeamUserByTeamId(teamId);if (teamHasJoinNum >= team.getMaxNum()) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍已满");}// 修改队伍信息 UserTeam userTeam = new UserTeam();userTeam.setUserId(userId);userTeam.setTeamId(teamId);userTeam.setJoinTime(new Date());return userTeamService.save(userTeam);}}} catch (InterruptedException e) {log.error("doCacheRecommendUser error", e);return false;} finally {// 只能释放自己的锁if (lock.isHeldByCurrentThread()) {System.out.println("unLock: " + Thread.currentThread().getId());lock.unlock();}}}

别忘了引入 RedissonClient
image.png
项目基本完成

二、部署上线

先区分多环境:前端区分开发和线上接口,后端 prod 改为用线上公网可访问的数据库
前端:Vercel(免费)
https://vercel.com/
后端:微信云托管(部署容器的平台,付费)
https://cloud.weixin.qq.com/cloudrun/service
(免备案!!!)

注意如果后端使用微信云托管,一定要写一个dokerfile

FROM maven:3.5-jdk-8-alpine as builder# Copy local code to the container image.
WORKDIR /app
COPY pom.xml .
COPY src ./src# Build a release artifact.
RUN mvn package -DskipTests# Run the web service on container startup.
CMD ["java","-jar","/app/target/yupao-backend-0.0.1-SNAPSHOT.jar","--spring.profiles.active=prod"]

前端部署需要区分线上和本地环境
首先打包如果报错(大概率是因为ts语法的检查),在packjson里修改build
image.png
区分环境
在myAxios里配置(实现自动根据环境来更换地址)
image.png

在这里插入图片描述

这篇关于心链14-----项目功能完善补坑+自动跳转登录页 + 重复加入队伍问题(分布式锁) 并发请求问题解决 + 项目部署上线的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1048174

相关文章

SQL Server跟踪自动统计信息更新实战指南

《SQLServer跟踪自动统计信息更新实战指南》本文详解SQLServer自动统计信息更新的跟踪方法,推荐使用扩展事件实时捕获更新操作及详细信息,同时结合系统视图快速检查统计信息状态,重点强调修... 目录SQL Server 如何跟踪自动统计信息更新:深入解析与实战指南 核心跟踪方法1️⃣ 利用系统目录

使用IDEA部署Docker应用指南分享

《使用IDEA部署Docker应用指南分享》本文介绍了使用IDEA部署Docker应用的四步流程:创建Dockerfile、配置IDEADocker连接、设置运行调试环境、构建运行镜像,并强调需准备本... 目录一、创建 dockerfile 配置文件二、配置 IDEA 的 Docker 连接三、配置 Do

解决pandas无法读取csv文件数据的问题

《解决pandas无法读取csv文件数据的问题》本文讲述作者用Pandas读取CSV文件时因参数设置不当导致数据错位,通过调整delimiter和on_bad_lines参数最终解决问题,并强调正确参... 目录一、前言二、问题复现1. 问题2. 通过 on_bad_lines=‘warn’ 跳过异常数据3

解决RocketMQ的幂等性问题

《解决RocketMQ的幂等性问题》重复消费因调用链路长、消息发送超时或消费者故障导致,通过生产者消息查询、Redis缓存及消费者唯一主键可以确保幂等性,避免重复处理,本文主要介绍了解决RocketM... 目录造成重复消费的原因解决方法生产者端消费者端代码实现造成重复消费的原因当系统的调用链路比较长的时

python运用requests模拟浏览器发送请求过程

《python运用requests模拟浏览器发送请求过程》模拟浏览器请求可选用requests处理静态内容,selenium应对动态页面,playwright支持高级自动化,设置代理和超时参数,根据需... 目录使用requests库模拟浏览器请求使用selenium自动化浏览器操作使用playwright

深度解析Nginx日志分析与499状态码问题解决

《深度解析Nginx日志分析与499状态码问题解决》在Web服务器运维和性能优化过程中,Nginx日志是排查问题的重要依据,本文将围绕Nginx日志分析、499状态码的成因、排查方法及解决方案展开讨论... 目录前言1. Nginx日志基础1.1 Nginx日志存放位置1.2 Nginx日志格式2. 499

SpringBoot监控API请求耗时的6中解决解决方案

《SpringBoot监控API请求耗时的6中解决解决方案》本文介绍SpringBoot中记录API请求耗时的6种方案,包括手动埋点、AOP切面、拦截器、Filter、事件监听、Micrometer+... 目录1. 简介2.实战案例2.1 手动记录2.2 自定义AOP记录2.3 拦截器技术2.4 使用Fi

kkFileView启动报错:报错2003端口占用的问题及解决

《kkFileView启动报错:报错2003端口占用的问题及解决》kkFileView启动报错因office组件2003端口未关闭,解决:查杀占用端口的进程,终止Java进程,使用shutdown.s... 目录原因解决总结kkFileViewjavascript启动报错启动office组件失败,请检查of

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

SQL Server安装时候没有中文选项的解决方法

《SQLServer安装时候没有中文选项的解决方法》用户安装SQLServer时界面全英文,无中文选项,通过修改安装设置中的国家或地区为中文中国,重启安装程序后界面恢复中文,解决了问题,对SQLSe... 你是不是在安装SQL Server时候发现安装界面和别人不同,并且无论如何都没有中文选项?这个问题也