心链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

相关文章

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

qt5cored.dll报错怎么解决? 电脑qt5cored.dll文件丢失修复技巧

《qt5cored.dll报错怎么解决?电脑qt5cored.dll文件丢失修复技巧》在进行软件安装或运行程序时,有时会遇到由于找不到qt5core.dll,无法继续执行代码,这个问题可能是由于该文... 遇到qt5cored.dll文件错误时,可能会导致基于 Qt 开发的应用程序无法正常运行或启动。这种错

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热

SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志

《SpringBoot项目配置logback-spring.xml屏蔽特定路径的日志》在SpringBoot项目中,使用logback-spring.xml配置屏蔽特定路径的日志有两种常用方式,文中的... 目录方案一:基础配置(直接关闭目标路径日志)方案二:结合 Spring Profile 按环境屏蔽关

SpringBoot排查和解决JSON解析错误(400 Bad Request)的方法

《SpringBoot排查和解决JSON解析错误(400BadRequest)的方法》在开发SpringBootRESTfulAPI时,客户端与服务端的数据交互通常使用JSON格式,然而,JSON... 目录问题背景1. 问题描述2. 错误分析解决方案1. 手动重新输入jsON2. 使用工具清理JSON3.

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

MySQL 设置AUTO_INCREMENT 无效的问题解决

《MySQL设置AUTO_INCREMENT无效的问题解决》本文主要介绍了MySQL设置AUTO_INCREMENT无效的问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参... 目录快速设置mysql的auto_increment参数一、修改 AUTO_INCREMENT 的值。

关于跨域无效的问题及解决(java后端方案)

《关于跨域无效的问题及解决(java后端方案)》:本文主要介绍关于跨域无效的问题及解决(java后端方案),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录通用后端跨域方法1、@CrossOrigin 注解2、springboot2.0 实现WebMvcConfig

Go语言中泄漏缓冲区的问题解决

《Go语言中泄漏缓冲区的问题解决》缓冲区是一种常见的数据结构,常被用于在不同的并发单元之间传递数据,然而,若缓冲区使用不当,就可能引发泄漏缓冲区问题,本文就来介绍一下问题的解决,感兴趣的可以了解一下... 目录引言泄漏缓冲区的基本概念代码示例:泄漏缓冲区的产生项目场景:Web 服务器中的请求缓冲场景描述代码