Vue3+java开发组队功能
Vue3+java开发系统组队功能
需求分析
- 创建用户可以创建一个队伍(一个房间队长),设置队伍人数,队伍名称(标题),描述,超时时间。
- 搜索
- 加入,用户可以加入未满的队伍(其他人,未满,未过期),是否需要队长同意
- 分享队伍,邀请人员
- 显示队伍人数
- 聊天
- 修改队伍信息
- 退出
- 解散
系统(接口)设计
- 判断请求参数是否为空
- 是否登录,未登录直接跳转到登录,不允许创建
- 校验信息
- 队伍人数大于1小于20
- 队伍名称<=20
- 队伍人数<=412
- 是否公开(int)不穿默认位0,公开
- 如果是加密状态,一定3要有密码,且密码<=32
- 超时时间>当前时间
- 校验用户最多创建5个队伍
- 插入队伍信息到队伍表
- 插入用户 => 队伍关系到关系表
实现
1. 库表设计(10min)
- 数据库表设计,队伍表,队伍用户表
-- 队伍表 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)
- 使用mybatisX-generation插件自动生成实体类服务层,持久层代码
- 队伍基本增删改查代码编写
/** * 队伍接口 */ @RestController @RequestMapping("/team") @CrossOrigin(origins = {"http://localhost:5173"}, allowCredentials = "true") @Slf4j //lombok的注解,可以在类中使用log打日志 public class TeamController { @Resource private UserService userService; @Resource private 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); } }
- 查询队伍列表功能实现
- 新建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; }
- 原因:
- 实现查询队伍列表
/** * 查询组队列表 * @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); }
- 新建TeamQuery业务请求参数封装类作为作为参数
- 分页查询队伍列表功能实现
- 新建请求分页类
/** * 分页请求类 * * @author Erha */ @Data public class PageRequest implements Serializable { //使对象序列化保持唯一 private static final long serialVersionUID = -9075033996918167511L; /** * 页面大小 */ protected int pageSize; /** * 当前第几页 */ protected int pageNum; }
- 分页查询队伍实现代码
/** * 分页查询组队列表 * @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); }
- 新建请求分页类
- 使用Swagger+knif4j文档接口
3. 业务逻辑(30min)
- 创建队伍业务逻辑实现
/** * @author serendipity * @description 针对表【team(队伍)】的数据库操作Service实现 * @createDate 2023-11-28 19:33:44 */ @Service public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team> implements TeamService { @Resource private 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且<=20 int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);//如果为空,直接赋值为0 if (maxNum < 1 || maxNum > 20) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍人数不满足要求"); } //(2).队伍标题 <=20 String name = team.getName(); if (StringUtils.isBlank(name) || name.length() > 20) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不满足要求"); } // (3) 描述<= 512 String description = team.getDescription(); if (StringUtils.isNotBlank(description) && description.length() > 512) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述过长"); } //(4)status 是否公开,不传默认为0 int status = Optional.ofNullable(team.getStatus()).orElse(0); TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status); if (statusEnum == null) { throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求"); } //(5)如果status是加密状态,一定要密码 且密码<=32 String 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; } }