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

相关文章

idea maven编译报错Java heap space的解决方法

《ideamaven编译报错Javaheapspace的解决方法》这篇文章主要为大家详细介绍了ideamaven编译报错Javaheapspace的相关解决方法,文中的示例代码讲解详细,感兴趣的... 目录1.增加 Maven 编译的堆内存2. 增加 IntelliJ IDEA 的堆内存3. 优化 Mave

springboot filter实现请求响应全链路拦截

《springbootfilter实现请求响应全链路拦截》这篇文章主要为大家详细介绍了SpringBoot如何结合Filter同时拦截请求和响应,从而实现​​日志采集自动化,感兴趣的小伙伴可以跟随小... 目录一、为什么你需要这个过滤器?​​​二、核心实现:一个Filter搞定双向数据流​​​​三、完整代码

如何解决mmcv无法安装或安装之后报错问题

《如何解决mmcv无法安装或安装之后报错问题》:本文主要介绍如何解决mmcv无法安装或安装之后报错问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mmcv无法安装或安装之后报错问题1.当我们运行YOwww.chinasem.cnLO时遇到2.找到下图所示这里3.

浅谈配置MMCV环境,解决报错,版本不匹配问题

《浅谈配置MMCV环境,解决报错,版本不匹配问题》:本文主要介绍浅谈配置MMCV环境,解决报错,版本不匹配问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录配置MMCV环境,解决报错,版本不匹配错误示例正确示例总结配置MMCV环境,解决报错,版本不匹配在col

Vue3使用router,params传参为空问题

《Vue3使用router,params传参为空问题》:本文主要介绍Vue3使用router,params传参为空问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录vue3使用China编程router,params传参为空1.使用query方式传参2.使用 Histo

AJAX请求上传下载进度监控实现方式

《AJAX请求上传下载进度监控实现方式》在日常Web开发中,AJAX(AsynchronousJavaScriptandXML)被广泛用于异步请求数据,而无需刷新整个页面,:本文主要介绍AJAX请... 目录1. 前言2. 基于XMLHttpRequest的进度监控2.1 基础版文件上传监控2.2 增强版多

Feign Client超时时间设置不生效的解决方法

《FeignClient超时时间设置不生效的解决方法》这篇文章主要为大家详细介绍了FeignClient超时时间设置不生效的原因与解决方法,具有一定的的参考价值,希望对大家有一定的帮助... 在使用Feign Client时,可以通过两种方式来设置超时时间:1.针对整个Feign Client设置超时时间

SpringBoot首笔交易慢问题排查与优化方案

《SpringBoot首笔交易慢问题排查与优化方案》在我们的微服务项目中,遇到这样的问题:应用启动后,第一笔交易响应耗时高达4、5秒,而后续请求均能在毫秒级完成,这不仅触发监控告警,也极大影响了用户体... 目录问题背景排查步骤1. 日志分析2. 性能工具定位优化方案:提前预热各种资源1. Flowable

微信公众号脚本-获取热搜自动新建草稿并发布文章

《微信公众号脚本-获取热搜自动新建草稿并发布文章》本来想写一个自动化发布微信公众号的小绿书的脚本,但是微信公众号官网没有小绿书的接口,那就写一个获取热搜微信普通文章的脚本吧,:本文主要介绍微信公众... 目录介绍思路前期准备环境要求获取接口token获取热搜获取热搜数据下载热搜图片给图片加上标题文字上传图片

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整