一、接口设计
1. 请求参数:封装添加队伍参数 TeamAddRequest
package com.example.usercenter.model.request;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import lombok.Data;
import java.io.Serializable;
import java.util.Date;
/**
* 用户登录请求参数
* @author Ghost
* @version 1.0
*/
@Data
public class TeamAddRequest implements Serializable{
private static final long serialVersionUID = 6993746803531411917L;
/**
* id
*/
@TableId(type = IdType.AUTO)
private Long id;
/**
* 队伍名称
*/
private String name;
/**
* 描述
*/
private String description;
/**
* 最大人数
*/
private Integer maxNum;
/**
* 过期时间
*/
private Date expireTime;
/**
* 用户id
*/
private Long userId;
/**
* 0 - 公开,1 - 私有,2 - 加密
*/
private Integer status;
/**
* 密码
*/
private String password;
}
2. 请求路径:/team/add
3. 请求方式:POST
4. 响应数据:添加成功的队伍 id
二、业务逻辑
1. 请求参数是否为空?
2. 是否登录,未登录不允许创建
3. 校验信息
- 队伍人数 > 1 且 <= 20
- 队伍标题 <= 20
- 描述 <= 512
- status 是否公开(int)不传默认为 0(公开)
- 如果 status 是加密状态,一定要有密码,且密码 <= 32
- 超时时间 > 当前时间
- 校验用户最多创建 5 个队伍
4. 插入队伍信息到队伍表
5. 插入用户 => 队伍关系到关系表
注意❗
- 操作两张表(队伍表和用户队伍关系表)时需要开启事务功能,使用 @Transactional 注解在方法上开启事务
- 如果添加队伍和添加用户队伍关系中间出现异常,添加队伍也失败,回滚到方法执行之前
- Controller
@PostMapping("/add")
public BaseResponse<Long> addTeam(@RequestBody TeamAddRequest teamAddRequest, HttpServletRequest request) {
if (teamAddRequest == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR);
}
User loginUser = userService.getLoginUser(request);
Team team = new Team();
BeanUtils.copyProperties(teamAddRequest, team);
long teamId = teamService.addTeam(team, loginUser);
return ResultUtils.success(teamId);
}
- Service
package com.example.usercenter.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.usercenter.common.ErrorCode;
import com.example.usercenter.constant.enums.TeamStatusEnum;
import com.example.usercenter.exception.BusinessException;
import com.example.usercenter.model.domain.Team;
import com.example.usercenter.model.domain.User;
import com.example.usercenter.model.domain.UserTeam;
import com.example.usercenter.service.TeamService;
import com.example.usercenter.mapper.TeamMapper;
import com.example.usercenter.service.UserTeamService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Date;
import java.util.Optional;
/**
* @author 20890
* @description 针对表【team(队伍)】的数据库操作Service实现
* @createDate 2024-01-22 18:27:55
*/
@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.NOT_LOGIN);
}
final long userId = loginUser.getId();
// 3. 校验信息
// 1. 队伍人数 > 1 且 <= 20
int maxNum = Optional.ofNullable(team.getMaxNum()).orElse(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 是否公开(int)不传默认为 0(公开)
int status = Optional.ofNullable(team.getStatus()).orElse(0);
TeamStatusEnum teamStatus = TeamStatusEnum.getTeamEnumByValue(status);
if (teamStatus == null) {
throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不符合要求");
}
// 5. 如果 status 是加密状态,一定要有密码,且密码 <= 32
String password = team.getPassword();
if (status == TeamStatusEnum.SECRET.getValue() && (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,用户可能同时创建很多个队伍
QueryWrapper<UserTeam> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("user_id", userId);
long hasTeamNum = userTeamService.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.SYSTEM_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.SYSTEM_ERROR,"创建队伍失败");
}
return teamId;
}
}
三、接口测试
1. 使用 Knife4j 接口文档进行测试
2. 查看数据库