ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vue3+java开发组队功能

2026/8/5 6:34:21 拓冰建站 浏览量
Vue3+java开发组队功能

Vue3+java开发系统组队功能

需求分析

  1. 创建用户可以创建一个队伍(一个房间队长),设置队伍人数,队伍名称(标题),描述,超时时间。
  2. 搜索
  3. 加入,用户可以加入未满的队伍(其他人,未满,未过期),是否需要队长同意
  4. 分享队伍,邀请人员
  5. 显示队伍人数
  6. 聊天
  7. 修改队伍信息
  8. 退出
  9. 解散

系统(接口)设计

  1. 判断请求参数是否为空
  2. 是否登录,未登录直接跳转到登录,不允许创建
  3. 校验信息
    1. 队伍人数大于1小于20
    2. 队伍名称<=20
    3. 队伍人数<=412
    4. 是否公开(int)不穿默认位0,公开
    5. 如果是加密状态,一定3要有密码,且密码<=32
    6. 超时时间>当前时间
    7. 校验用户最多创建5个队伍
  4. 插入队伍信息到队伍表
  5. 插入用户 => 队伍关系到关系表

实现

1. 库表设计(10min)

  1. 数据库表设计,队伍表,队伍用户表
    -- 队伍表
    create table team
    (id bigint auto_increment comment 'id'primary key,name varchar(256) not null comment '队伍名称',description varchar(1024) null comment '描述',maxNum int default 1 not null comment '最大人数',expireTime datetime null comment '过期时间',userId bigint comment '用户id',status int default 0 not null comment '0 - 公开,1 - 私有,2 - 加密',password varchar(512) null comment '密码',createTime datetime default CURRENT_TIMESTAMP null comment '创建时间',updateTime datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,isDelete tinyint default 0 not null comment '是否删除'
    )comment '队伍';-- 用户队伍关系表
    create table user_team
    (id bigint auto_increment comment 'id'primary key,userId bigint comment '用户id',teamId bigint comment '队伍id',joinTime datetime null comment '加入时间',createTime datetime default CURRENT_TIMESTAMP null comment '创建时间',updateTime datetime default CURRENT_TIMESTAMP null on update CURRENT_TIMESTAMP,isDelete tinyint default 0 not null comment '是否删除'
    )comment '用户队伍关系';
    

2. 增删改查代码实现(10min)

  1. 使用mybatisX-generation插件自动生成实体类服务层,持久层代码
  2. 队伍基本增删改查代码编写
    /*** 队伍接口*/
    @RestController
    @RequestMapping("/team")
    @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true")
    @Slf4j //lombok的注解,可以在类中使用log打日志
    public class TeamController {@Resourceprivate UserService userService;@Resourceprivate TeamService teamService;/*** 增加队伍* @param team* @return*/@PostMapping("/add")public BaseResponse<Long>  addTeam(@RequestBody Team team){//接收前端传来队伍的信息if(team == null){throw new  BusinessException(ErrorCode.PARAMS_ERROR);}boolean save = teamService.save(team);//teamService继承自Iservices的接口,底层实现了serviceImpl//需要返回新生成数据的id,使用mybatis的组件回写if(!save){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"插入失败");}return ResultUtils.success(team.getId());}/*** 删除队伍** @param id* @return*/@PostMapping("/delete")public BaseResponse<Boolean> deleteTeam(@RequestBody long id){//接收前端传来队伍的信息if(id <= 0){throw new  BusinessException(ErrorCode.PARAMS_ERROR);}boolean result = teamService.removeById(id);//teamService继承自Iservices的接口,底层实现了serviceImpl//需要返回新生成数据的id,使用mybatis的组件回写if(!result){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"删除失败");}return ResultUtils.success(true);}/*** 改动队伍** @param team* @return*/@PostMapping("/delete")public BaseResponse<Boolean> updateTeam(@RequestBody Team team){//接收前端传来队伍的信息if(team == null){throw new  BusinessException(ErrorCode.PARAMS_ERROR);}boolean result = teamService.updateById(team);//teamService继承自Iservices的接口,底层实现了serviceImpl//需要返回新生成数据的id,使用mybatis的组件回写if(!result){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"更新失败");}return ResultUtils.success(true);}/*** 查询队伍** @param id* @return*/@GetMapping("/delete")public BaseResponse<Team> getTeamById(@RequestBody long id){//接收前端传来队伍id的信息if(id <= 0){throw new  BusinessException(ErrorCode.PARAMS_ERROR);}Team team = teamService.getById(id);//teamService继承自Iservices的接口,底层实现了serviceImpl//需要返回新生成数据的id,使用mybatis的组件回写if(team == null){throw new BusinessException(ErrorCode.NULL_ERROR,"数据为空!");}return ResultUtils.success(team);}
    }
  3. 查询队伍列表功能实现
    1. 新建TeamQuery业务请求参数封装类作为作为参数
      • 原因:
        1. 请求参数和实体类不一样;
        2. 有些参数用不到;
        3. 多个实体类映射到同一个字段
        4. 有些字段要隐藏不返回到前端
      • 代码实现
        /*** 队伍查询封装类*/
        @EqualsAndHashCode(callSuper = true)
        @Data
        public class TeamQuery extends PageRequest {/*** id*/@TableId(type = IdType.AUTO)private Long id;/*** 队伍名称*/private String name;/*** 描述*/private String description;/*** 最大人数*/private Integer maxNum;/*** 用户id*/private Long userId;/*** 0 - 公开,1 - 私有,2 - 加密*/private Integer status;
        }
        
    2. 实现查询队伍列表
      /*** 查询组队列表* @param teamQuery* @return*/
      @GetMapping("/list")
      //新建teamQuery业务请求参数封装类作为,原因:1.请求参数和实体类不一样;2.有些参数用不到;3.有些字段要隐藏不返回到前端
      public BaseResponse<List<Team>> listTeams(TeamQuery teamQuery){if (teamQuery == null){throw new BusinessException(ErrorCode.PARAMS_ERROR);}Team team = new Team();BeanUtils.copyProperties(team,teamQuery);QueryWrapper<Team> queryWrapper = new QueryWrapper<>();List<Team> teamList = teamService.list(queryWrapper);return ResultUtils.success(teamList);
      }
      
  4. 分页查询队伍列表功能实现
    1. 新建请求分页类
      /*** 分页请求类** @author Erha*/
      @Data
      public class PageRequest implements Serializable {//使对象序列化保持唯一private static final long serialVersionUID = -9075033996918167511L;/*** 页面大小*/protected int pageSize;/*** 当前第几页*/protected int pageNum;
      }
      
    2. 分页查询队伍实现代码
      /*** 分页查询组队列表* @param teamQuery* @return*/
      @GetMapping("/list/page")
      public BaseResponse<Page<Team>> listTeamsByPage(TeamQuery teamQuery){if(teamQuery == null){throw new  BusinessException(ErrorCode.PARAMS_ERROR);}Team team = new Team();BeanUtils.copyProperties(team, teamQuery);//把哪个对象的字段复制到另外一个中Page<Team> page = new Page<>(teamQuery.getPageNum(), teamQuery.getPageSize());QueryWrapper<Team> queryWrapper = new QueryWrapper<>(team);Page<Team> Resultpage = teamService.page(page, queryWrapper);return ResultUtils.success(Resultpage);}
      
  5. 使用Swagger+knif4j文档接口
    在这里插入图片描述

3. 业务逻辑(30min)

  1. 创建队伍业务逻辑实现
    /**
    * @author serendipity
    * @description 针对表【team(队伍)】的数据库操作Service实现
    * @createDate 2023-11-28 19:33:44
    */
    @Service
    public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>implements TeamService {@Resourceprivate UserTeamService userTeamService;@Override@Transactional(rollbackFor = Exception.class)public long addTeam(Team team, User loginUser) {//1.请求参数是否为空if (team == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}//2.是否登录,未登录不允许创建if (loginUser == null) {throw new BusinessException(ErrorCode.NO_AUTH);}final long userId = loginUser.getId();//3.检验信息//(1).队伍人数>1且<=20int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);//如果为空,直接赋值为0if (maxNum < 1 || maxNum > 20) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不满足要求");}//(2).队伍标题 <=20String name = team.getName();if (StringUtils.isBlank(name) || name.length() > 20) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不满足要求");}// (3) 描述<= 512String description = team.getDescription();if (StringUtils.isNotBlank(description) && description.length() > 512) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述过长");}//(4)status 是否公开,不传默认为0int status = Optional.ofNullable(team.getStatus()).orElse(0);TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);if (statusEnum == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");}//(5)如果status是加密状态,一定要密码 且密码<=32String password = team.getPassword();if (TeamStatusEnum.SECRET.equals(statusEnum)) {if (StringUtils.isBlank(password) || password.length() > 32) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");}}//(6)超出时间 > 当前时间Date expireTime = team.getExpireTime();if (new Date().after(expireTime)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "超出时间 > 当前时间");}//(7)校验用户最多创建5个队伍//todo 有bug。可能同时创建100个队伍QueryWrapper<Team> queryWrapper = new QueryWrapper<>();queryWrapper.eq("userId", userId);long hasTeamNum = this.count(queryWrapper);if (hasTeamNum >= 5) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户最多创建5个队伍");}//4.插入队伍消息到队伍表team.setId(null);team.setUserId(userId);boolean result = this.save(team);Long teamId = team.getId();if (!result || teamId == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");}//5. 插入用户 ==> 队伍关系 到关系表UserTeam userTeam = new UserTeam();userTeam.setUserId(userId);userTeam.setTeamId(teamId);userTeam.setJoinTime(new Date());result = userTeamService.save(userTeam);if (!result) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "创建队伍失败");}return teamId;}
    }
    
  2. 用户退出队伍
    • 请求参数:队伍id
    • 逻辑:
      1. 校验请求参数
      2. 校验队伍是否存在
      3. 校验我是否已加入队伍
      4. 如果队伍
        1. 只剩一人,队伍解散
        2. 还有其他人
          1. 如果是队长退出队伍,权限转移给第二早加入的用户 —— 先来后到
          2. 只用取 id 最小的 2 条数据,其中一条是当前队长的id,当前队长退出后,新队长顺位给最早加
            入的下一位队员
      5. 非队长,自己退出队伍