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

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/25513.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Cyber Weekly #10

赛博新闻 1、最强开源大模型面世&#xff1a;阿里发布Qwen2 6月7日凌晨&#xff0c;阿里巴巴通义千问团队发布了Qwen2系列开源模型。该系列模型包括5个尺寸的预训练和指令微调模型&#xff1a;Qwen2-0.5B、Qwen2-1.5B、Qwen2-7B、Qwen2-57B-A14B以及Qwen2-72B。据Qwen官方博客…

Vitis HLS 学习笔记--循环边界包含变量

目录 1. 简介 2. 分析与详解 2.1 未优化 2.2 LOOP_TRIPCOUNT 优化指令 2.3 重写变量循环边界 3. 总结 1. 简介 在硬件设计中&#xff0c;循环的迭代次数通常需要是固定的&#xff0c;因为这有助于资源的预分配和时序分析。 循环边界包含变量意味着循环的迭代次数不是固…

Java进阶_抽象类与方法

抽象类概念 在面向对象的概念中&#xff0c;所有的对象都是通过类来描绘的&#xff0c;但是反过来&#xff0c;并不是所有的类都是用来描绘对象的&#xff0c;如果一个类中没有包含足够的信息来描绘一个具体的对象&#xff0c;这样的类就是抽象类。 抽象类除了不能实例化对象之…

ESP32-C3模组上跑通NVS(6)

接前一篇文章:ESP32-C3模组上跑通NVS(5) 本文内容参考: 非易失性存储库 - ESP32 - — ESP-IDF 编程指南 latest 文档 ESP

【MySQL】探索 MySQL 中的 WITH 关键字:使用公共表表达式(CTE)简化查询

我已经从你的 全世界路过 像一颗流星 划过命运 的天空 很多话忍住了 不能说出口 珍藏在 我的心中 只留下一些回忆 &#x1f3b5; 牛奶咖啡《从你的全世界路过》 探索 MySQL 中的 WITH 关键字&#xff1a;使用公共表表达式&#xff08;CTE&#xff09;简化…

按键精灵安装有乱码并且不能启动的解决办法

在国外购了电脑&#xff0c;系统是英文版 Windows 11&#xff0c;按键精灵死活都装不上去&#xff0c;打开exe的安装文件后出现乱码&#xff0c;安装完了后还是乱码&#xff0c;并且启动不了&#xff0c;以下是解决办法&#xff1a; 进入控制面板&#xff0c;并且点 Region&am…

MATLAB算法实战应用案例精讲-【数模应用】逐步回归分析(附MATLAB、R语言和python代码实现)

目录 前言 几个高频面试题目 逐步回归分析和多元线性回归的区别 知识储备 多元线性回归 模型选择 (Model Selection) 算法原理 什么是逐步回归分析 实现策略 向前选择 向后剔除 逐步回归 特征选择与逐步回归分析 2.1特征工程 2.2原始特征的问题 2.3降维与特征选…

汇编:结构体

在32位汇编中&#xff0c;结构体&#xff08;structures&#xff09;用于组织和管理复杂的数据类型&#xff0c;结构体可以包含多个不同类型的数据项&#xff08;成员&#xff09;&#xff1b;在MASM&#xff08;Microsoft Macro Assembler&#xff09;中&#xff0c;使用结构体…

CentOS安装Node.js以及JSDOM跳坑记

笔者在一台 CentOS 7.9 的服务器上使用常规的安装命令&#xff1a;sudo yum install node 来安装 Node.js&#xff0c;到最后系统提示&#xff1a; Error: Package: 2:nodejs-20.14.0-1nodesource.x86_64 (nodesource-nodejs) Requires: libstdc.so.6(GLIBCXX_3.4.20)(64bit) …

vite获取所有环境变量(env)

0.环境变量文件 API_URL8888888 VITE_API_URL99999991.定义环境变量 默认情况下&#xff0c;vite只获取以VITE_为前缀的环境变量。 为了防止意外地将一些环境变量泄漏到客户端&#xff0c;只有以 VITE_ 为前缀的变量才会暴露给经过 vite 处理的代码 但如果你觉得你是进击的巨人…

VUE + nodejs实战

BVDN搭建 D: cd nodejs ::npm install bootstrap ::npm install jquery ::npm install popper.js ::npm install vue npm install vue-router pauseapp.html <!DOCTYPE html> <!DOCTYPE html> <html> <head><!--bootstrap--><link rel"…

vue面试题一

一、请解释Vue.js是什么&#xff1f; Vue.js 是一个构建用户界面的渐进式框架。它的核心库只关注视图层&#xff0c;不仅易于上手&#xff0c;也便于与第三方库或已有项目整合。Vue.js 的目标是通过尽可能简单的 API 实现响应的数据绑定和组合的视图组件。 以下是 Vue.js 的一…

MySQL 5.7详细下载安装配置教程(MySQL 5.7安装包)_mysql5.7的安装教程

记录MySQL 5.7 的下载安装教程&#xff0c;并提供了Mysql 安装包 &#xff0c;以下是详细下载安装过程。 一、下载Mysql安装包 网盘下载&#xff1a; 下载MySQL 5.7安装包&#xff0c;网盘下载地址&#xff1a;点击此处直接下载 官网下载&#xff1a; 进入官网&#xff0c…

为什么选择Python作为AI开发语言

为什么Python适合AI 在当前的科技浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;无疑是最热门的话题之一。无论是自动驾驶、智能推荐还是自然语言处理&#xff0c;AI都在不断改变我们的生活。而在这场技术革命中&#xff0c;Python作为主要的编程语言之一&#xff0c;…

python-win10跑通chattts笔记(亲测可跑)0.8.010

python-win10跑通chattts笔记-亲测可跑 背景项目地址安装过程使用技巧参考链接背景 克隆了项目中的代码,在无conda环境下使用pip安装了依赖,最后报错cl: 命令行 error D8021 :无效的数值参数“/Wno-register” error: command C:\,最后通过使用conda解决了,以此记录下 项…

构建LangChain应用程序的示例代码:27、FLARE:前瞻性主动检索增强生成技术实现与应用的示例

FLARE&#xff1a;前瞻性主动检索增强生成 这个示例是前瞻性主动检索增强生成&#xff08;FLARE&#xff09;的实现。 请查看原始仓库。 基本思想是&#xff1a; 开始回答问题如果开始生成模型不确定的标记&#xff0c;查找相关文档使用这些文档继续生成重复直到完成 在查…

【设计模式】行为型设计模式之 迭代器模式

介绍 迭代器模式&#xff08;Iterator Pattern&#xff09; 是行为设计模式之一&#xff0c;它提供了一种访问集合对象&#xff08;如列表、数组或其他集合结构&#xff09;中元素的方式&#xff0c;而不需要暴露集合的内部结构。迭代器模式定义了一个迭代器接口&#xff0c;该…

沪深历史行情下载,金融数据库查询

行情在线测试 在线测试 历史行情 jvQuant提供2008创立至今的历史股票行情数据&#xff0c;包含沪深主板、科创板、创业板&#xff0c;股票日内行情。 下载地址 http://jvquant.com/query/history?&token<token>&year<数据年份>.zip Copy 例:下载20…

K8S - 用kubectl远程访问内网的k8s集群

在之前的文章 K8S - 在任意node里执行kubectl 命令 介绍过&#xff0c; 通过任何node 的主机&#xff0c; 用kubectl 管理集群是很简单 无非就是两个步骤: 下载 k8s master 上的admin.conf在当前主机配置 K8SCONFIG 环境变量指向 下载的config file 其他内网主机也适用 其…

【Tools】探索动态隧道代理与普通代理:它们是什么,有何不同?

我已经从你的 全世界路过 像一颗流星 划过命运 的天空 很多话忍住了 不能说出口 珍藏在 我的心中 只留下一些回忆 &#x1f3b5; 牛奶咖啡《从你的全世界路过》 在互联网的世界中&#xff0c;代理服务器&#xff08;Proxy Server&#xff09;是一个重要的…