心链9----组队功能开发以及请求参数包装类和包装类实现

心链 — 伙伴匹配系统

组队功能开发

需求分析

理想的应用场景

我要跟别人一起参加竞赛或者做项目,可以发起队伍或者加入别人的队伍

用户可以 创建 一个队伍,设置队伍的人数、队伍名称(标题)、描述、超时时间 P0

  1. 队长、剩余的人数
  2. 聊天?
  3. 公开 或 private 或加密
  4. 用户创建队伍最多 5 个

展示队伍列表,根据名称搜索队伍  P0,信息流中不展示已过期的队伍
修改队伍信息 P0 ~ P1
用户可以加入队伍(其他人、未满、未过期),允许加入多个队伍,但是要有个上限  P0
是否需要队长同意?筛选审批?
用户可以退出队伍(如果队长 退出,权限转移给第二早加入的用户 —— 先来后到) P1
队长可以解散队伍 P0

分享队伍 =》 邀请其他用户加入队伍 P1
业务流程:

  1. 生成分享链接(分享二维码)
  2. 用户访问链接,可以点击加入

队伍人满后发送消息通知 P1

数据库表设计

队伍表 team
字段:

  • id 主键 bigint(最简单、连续,放 url 上比较简短,但缺点是爬虫)
  • name 队伍名称
  • description 描述
  • maxNum 最大人数
  • expireTime 过期时间
  • userId 创建人 id
  • status 0 - 公开,1 - 私有,2 - 加密
  • password 密码
  • createTime 创建时间
  • updateTime 更新时间
  • isDelete 是否删除
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 '队伍';

用户 - 队伍表 user_team
字段:

  • id 主键
  • userId 用户 id
  • teamId 队伍 id
  • joinTime 加入时间
  • createTime 创建时间
  • updateTime 更新时间
  • isDelete 是否删除
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 '用户队伍关系';

两个关系:

  1. 用户加了哪些队伍?
  2. 队伍有哪些用户?

方式:

  1. 建立用户 - 队伍关系表 teamId userId(便于修改,查询性能高一点,可以选择这个,不用全表遍历)
  2. 用户表补充已加入的队伍字段,队伍表补充已加入的用户字段(便于查询,不用写多对多的代码,可以直接根据队伍查用户、根据用户查队伍)

后端代码

实体生成

实体生成team和user-team
使用MybatisX-Generator生成domain,service和mapper文件,然后把生成的文件都移到对应的目录里面,别忘了把mapper.xml里的路径改成自己对应的。

如果直接将生成的文件拉到对应的文件,就会自动修改mapper.xml的路径

PS:别忘了在team和user_team类中的is_delete字段添加@TableLogic注解,实现逻辑删除
image.png

队伍controller接口

①增删改查
②PageRequest(序列化)---- TeamQuery继承
③自己测试 http://localhost:8080/api/doc.html#/home

@RestController
@RequestMapping("/user")
@CrossOrigin(origins = {"http://localhost:5173/"})
@Slf4j
public class TeamController {@Resourceprivate UserService userService;@Resourceprivate RedisTemplate redisTemplate;@Resourceprivate TeamService teamService;@PostMapping("/add")public BaseResponse<Long> addTeam(@RequestBody Team team){if (team == null){throw new BusinessException(ErrorCode.NULL_ERROR);}boolean save = teamService.save(team);if (!save){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"插入失败");}return ResultUtils.success(team.getId());}@PostMapping("/delete")public BaseResponse<Boolean> deleteTeam(@RequestBody long id){if (id <= 0){throw new BusinessException(ErrorCode.NULL_ERROR);}boolean result = teamService.removeById(id);if (!result){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"删除失败");}return ResultUtils.success(true);}@PostMapping("/update")public BaseResponse<Boolean> updateTeam(@RequestBody Team team){if (team == null){throw new BusinessException(ErrorCode.PARAMS_ERROR);}boolean result = teamService.updateById(team);if (!result){throw new BusinessException(ErrorCode.SYSTEM_ERROR,"更新失败");}return ResultUtils.success(true);}@GetMapping("/get")public BaseResponse<Team> getTeamById(long id){if (id <= 0){throw new BusinessException(ErrorCode.PARAMS_ERROR);}Team team = teamService.getById(id);if (team == null){throw new BusinessException(ErrorCode.NULL_ERROR);}return ResultUtils.success(team);}@GetMapping("/list")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<>(team);List<Team> teamList = teamService.list(queryWrapper);return ResultUtils.success(teamList);}@GetMapping("/list/page")public BaseResponse<Page<Team>> listPageTeams(TeamQuery teamQuery) {if (teamQuery == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR);}Team team = new Team();BeanUtils.copyProperties(teamQuery, team);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);}}

:::success

这边我们需要新建请求参数包装类和包装类,原因如下:
为什么需要请求参数包装类?
  1. 请求参数名称 / 类型和实体类不一样
  2. 有一些参数用不到,如果要自动生成接口文档,会增加理解成本
  3. 对个实体类映射到同一个对象
为什么需要包装类?

可能有些字段需要隐藏,不能返回给前端
或者有些字段某些方法是不关心的

在model包里新建一个dto包,写一个包装类TeamQuery
:::

/*** 队伍查询封装类* @TableName team*/
@EqualsAndHashCode(callSuper = true)
@Data
public class TeamQuery extends PageRequest {/*** id*/private Long id;/*** id 列表*/private List<Long> idList;/*** 搜索关键词(同时对队伍名称和描述搜索)*/private String searchText;/*** 队伍名称*/private String name;/*** 描述*/private String description;/*** 最大人数*/private Integer maxNum;/*** 用户id*/private Long userId;/*** 0 - 公开,1 - 私有,2 - 加密*/private Integer status;
}

在common包下新建分页请求参数包装类

@Data
public class PageRequest implements Serializable {private static final long serialVersionUID = -4162304142710323660L;/*** 页面大小*/protected int pageSize;/*** 当前是第几页*/protected int pageNum;
}

接口系统设计

1、创建队伍

用户可以 创建 一个队伍,设置队伍的人数、队伍名称(标题)、描述、超时时间 P0
队长、剩余的人数
聊天?
公开 或 private 或加密
信息流中不展示已过期的队伍

  1. 请求参数是否为空?
  2. 是否登录,未登录不允许创建
  3. 校验信息
    1. 队伍人数 > 1 且 <= 20
    2. 队伍标题 <= 20
    3. 描述 <= 512
    4. status 是否公开(int)不传默认为 0(公开)
    5. 如果 status 是加密状态,一定要有密码,且密码 <= 32
    6. 超时时间 > 当前时间
    7. 校验用户最多创建 5 个队伍
  4. 插入队伍信息到队伍表
  5. 插入用户 => 队伍关系到关系表
    @PostMapping("/add")public BaseResponse<Long> addTeam(@RequestBody TeamAddRequest teamAddRequest, HttpServletRequest request){if (teamAddRequest == null){throw new BusinessException(ErrorCode.NULL_ERROR);}User logininUser = userService.getLogininUser(request);Team team = new Team();BeanUtils.copyProperties(teamAddRequest,team);long teamId = teamService.addTeam(team,logininUser);return ResultUtils.success(teamId);}

public interface TeamService extends IService<Team> {/***   添加队伍* @param team* @param loginUser* @return*/long addTeam(Team team, User loginUser);
}
@Service
public class TeamServiceImpl extends ServiceImpl<TeamMapper, Team>implements TeamService{@ResourceUserTeamService userTeamService;@Transactional(rollbackFor = Exception.class)@Overridepublic long addTeam(Team team, User loginUser) {//1. 请求参数是否为空?if (team == null){throw  new BusinessException(ErrorCode.NULL_ERROR);}//2. 是否登录,未登录不允许创建if (loginUser == null) {throw  new BusinessException(ErrorCode.NOT_LOGIN);}final long userId = loginUser.getId();//3. 校验信息//  a. 队伍人数 > 1 且 <= 20Integer maxNum = Optional.ofNullable(team.getMaxNum()).orElse(0);if (maxNum < 1 || maxNum >20){throw new BusinessException(ErrorCode.PARAMS_ERROR,"队伍人数不符合要求");}//  b. 队伍标题 <= 20String name = team.getName();if (StringUtils.isBlank(name) || name.length() > 20) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍标题不满足要求");}//  c. 描述 <= 512String description = team.getDescription();if (StringUtils.isNotBlank(description) && description.length() > 512) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍描述过长");}//  d. status 是否公开(int)不传默认为 0(公开)int status = Optional.ofNullable(team.getStatus()).orElse(0);TeamStatusEnum statusEnum = TeamStatusEnum.getEnumByValue(status);if (statusEnum == null) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "队伍状态不满足要求");}//  e. 如果 status 是加密状态,一定要有密码,且密码 <= 32String password = team.getPassword();if (TeamStatusEnum.SECRET.equals(statusEnum)) {if (StringUtils.isBlank(password) || password.length() > 32) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码设置不正确");}}//  f. 超时时间 > 当前时间Date expireTime = team.getExpireTime();if (new Date().after(expireTime)) {throw new BusinessException(ErrorCode.PARAMS_ERROR, "超时时间 > 当前时间");}//  g. 校验用户最多创建 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;}
}
/*** 队伍状态枚举*/
public enum TeamStatusEnum {PUBLIC(0, "公开"),PRIVATE(1, "私有"),SECRET(2, "加密");private int value;private String text;public static TeamStatusEnum getEnumByValue(Integer value) {if (value == null) {return null;}TeamStatusEnum[] values = TeamStatusEnum.values();for (TeamStatusEnum teamStatusEnum : values) {if (teamStatusEnum.getValue() == value) {return teamStatusEnum;}}return null;}TeamStatusEnum(int value, String text) {this.value = value;this.text = text;}public int getValue() {return value;}public void setValue(int value) {this.value = value;}public String getText() {return text;}public void setText(String text) {this.text = text;}
}
/*** 用户添加队伍请求体** @author yupi*/
@Data
public class TeamAddRequest implements Serializable {private static final long serialVersionUID = 3191241716373120793L;/*** 队伍名称*/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;
}

ps:这里过期时间的获取可从控制台输入一下代码来实现,单单的输入年月日会导致数据库里的时间增加8小时(应该是时区的问题)
image.png
多次发送添加请求,当插入5次之后,再插入会报错
image.png

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

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

相关文章

【WEB系列】过滤器Filter

Filter&#xff0c;过滤器&#xff0c;属于Servlet规范&#xff0c;并不是Spring独有的。其作用从命名上也可以看出一二&#xff0c;拦截一个请求&#xff0c;做一些业务逻辑操作&#xff0c;然后可以决定请求是否可以继续往下分发&#xff0c;落到其他的Filter或者对应的Servl…

海报在线制作系统

文章转载自&#xff1a;FastAdmin海报在线制作系统 - 源码1688 应用介绍 介绍 新机构海报是一款基于FastAdminThinkPHP开发的一款新机构海报。 采用JavaScript vue canvas技术&#xff0c;实现在线一键制作海报&#xff0c;生成海报。 功能特性 1、自由创作 2、一键制作…

Django使用正则表达式

本书1-7章样章及配套资源下载链接: https://pan.baidu.com/s/1OGmhHxEMf2ZdozkUnDkAkA?pwdnanc 源码、PPT课件、教学视频等&#xff0c;可以从前言给出的下载信息下载&#xff0c;大家可以评估一下。 在Django框架的新版本&#xff08;v2.0 &#xff09;中&#xff0c;URLc…

ECharts 图形化看板 模板(简单实用)

目录 一、官网 二、模板 ①定义请求​编辑 ② 将请求统一管理&#xff0c;别的页面引用多个请求时更便于导入。​编辑 ③最终模板 三、执行效果 四、后端代码 4.1 controller 4.2 xml 4.3 测试接口 一、官网 获取 ECharts - 入门篇 - 使用手册 - Apache ECharts 二、…

ARM32开发——串口库封装(初级)

&#x1f3ac; 秋野酱&#xff1a;《个人主页》 &#x1f525; 个人专栏:《Java专栏》《Python专栏》 ⛺️心若有所向往,何惧道阻且长 文章目录 开发流程分组创建 接口定义完整代码 开发流程 在文件系统中&#xff0c;创建库目录Library在keil工程中&#xff0c;创建分组管理…

Vue3-组件通信详解

文章目录 组件通信的含义Vue3组件通信和Vue2的区别组件通信的具体实现props&#xff08;父子组件通信&#xff09;自定义事件&#xff08;子传父&#xff09;mitt&#xff08;任意组件间通信&#xff09;v-model$attrs &#xff08;非props的父子组件通信&#xff09; r e f s …

知识图谱应用---智慧金融

文章目录 智慧金融典型应用 智慧金融 智慧金融作为一个有机整体&#xff0c;知识图谱提供了金融领域知识提取、融合、分析、推断、决策等功能&#xff0c;如下图所示。在场景方面&#xff0c;智慧金融涵盖智慧支付、智慧财富管理、智慧银行、智慧证券、智慧保险、智慧风控等诸多…

智能分析设备助力废固运输车辆信息采集

进出车辆信息采集&#xff0c;这一环节可谓是整个废固生产及处理企业监管体系中的基石。前端摄像机以其敏锐的感知能力&#xff0c;精准捕捉废固运输车辆的车牌、车头、车尾以及车厢的细致画面&#xff0c;同时记录下对应的视频流信息。这些信息的采集不仅为后续的监管提供了详…

Git存储库的推送保护

Git存储库的推送保护 昨天有一个提交一直提示&#xff1a;Push rejected Push rejected Push master to origin/master was rejected by remote起初在网络上找各种解决办法&#xff0c;先列举以下找到的各类方法 提交用户的用户名和邮箱与Git不一致&#xff0c;这个只需要通…

Warning:成交前,永远相信意外即将发生

作为一名首次次创业者&#xff0c;随着创业进入深层次阶段&#xff0c;越来越感觉到&#xff1a;创业是一条不归路&#xff0c;因为路上不止有惊喜&#xff0c;还有风尘。创业之前我认为世界是“天圆地方”的&#xff0c; 创业后你猜我怎么看这个世界的&#xff1f; 创业前我一…

项目-基于LangChain的ChatPDF系统

问答系统需求文档 一、项目概述 本项目旨在开发一个能够上传 PDF 文件&#xff0c;并基于 PDF 内容进行问答互动的系统。用户可以上传 PDF 文件&#xff0c;系统将解析 PDF 内容&#xff0c;并允许用户通过对话框进行问答互动&#xff0c;获取有关 PDF 文件内容的信息。 二、…

excel 插入图片不变形的方法

在单元格内插入形状&#xff0c; 设置图片格式 设置图片的高宽

【Linux进程篇】Linux中的等待机制与替换策略

W...Y的主页 &#x1f60a; 代码仓库分享&#x1f495; 目录 ​编辑 进程等待 进程等待必要性 进程等待的方法 wait方法 waitpid方法 获取子进程status 阻塞与非阻塞 进程程序替换 替换原理 替换函数 进程等待 进程等待必要性 之前讲过&#xff0c;子进程退出&am…

傲医医疗集成引擎 Rhapsody 在超融合信创平台表现如何?

作者&#xff1a;SmartX 商业团队 黄玉辉 随着越来越多的医疗用户基于超融合基础设施实现 IT 基础架构信创转型&#xff0c;超融合信创架构在医疗业务场景中的实际表现也得到更多关注。尤其是集成平台业务场景——作为三甲医院互联互通评级中不可缺少的核心业务系统&#xff0…

“云环境下的等保测评新趋势:混合云安全策略与合规性考量“

在云环境尤其是混合云场景下&#xff0c;等保测评&#xff08;信息安全等级保护测评&#xff09;的新趋势聚焦于更加灵活、高效且全面的安全策略&#xff0c;以及确保合规性。以下是几个关键点&#xff1a; 混合云安全策略的新趋势&#xff1a; 1. 统一安全管理&#xff1a;由…

概率分布、回归分析、假设检验……用 DolphinDB 函数库快速实现概率统计分析

在金融和物联网等领域&#xff0c;概率统计与分析扮演着至关重要的角色。DolphinDB 作为一款强大的时序数据库&#xff0c;提供了一系列内置的概率统计与分析函数&#xff0c;能够满足用户的各种需求。 金融领域 风险管理&#xff1a;通过概率统计分析&#xff0c;金融机构可…

【主题广泛|投稿优惠】2024年交通运输与信息科学国际会议(ICTIS 2024)

2024年交通运输与信息科学国际会议&#xff08;ICTIS 2024&#xff09; 2024 International Conference on Transportation and Information Science 【重要信息】 大会地点&#xff1a;青岛 大会官网&#xff1a;http://www.icictis.com 投稿邮箱&#xff1a;icictissub-conf.…

【Vue】成绩案例

文章目录 一、功能描述二、思路分析三、完整代码 一、功能描述 1.渲染功能 2.删除功能 3.添加功能 4.统计总分&#xff0c;求平均分 二、思路分析 渲染功能 v-for :key v-bind:动态绑定class的样式&#xff08;来回切换&#xff09; 删除功能 v-on绑定事件&#xff0c; 阻止…

线性代数|机器学习-P2 A的列向量空间

文章目录 1. Ax矩阵的形式2. ACR 矩阵分解2.1 rank1 矩阵分解2.2 rank2 矩阵分解2.3 ACMR,求M 3. Ax 向量 1. Ax矩阵的形式 假设我们有如下矩阵A&#xff1a; A x [ 2 1 3 3 1 4 5 7 12 ] [ x 1 x 2 x 3 ] \begin{equation} Ax\begin{bmatrix} 2&1&3\\\\ 3&1&am…

【微信小程序开发】小程序中的上滑加载更多,下拉刷新是如何实现的?

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…