用户查询活动功能开发文档
文章目录
逻辑分析
用户可以根据以下输入条件查询活动:
userId
(必填): 用户IDstatus
(可选): 活动状态activityName
(可选): 活动名称startTime
(可选): 活动开始时间endTime
(可选): 活动结束时间orderBy
(可选): 排序字段,默认按参与人数排序order
(可选): 排序方式,升序或降序,默认降序
功能概述
该功能的主要目的是根据用户ID查询相关活动,并根据特定条件筛选和排序这些活动。查询结果还会包含一个check
字段,用于表示用户在每个活动中的参与状态。
主要逻辑
-
用户参与状态计算:
check = 0
:活动未开始或已结束,或当前时间不在活动时间范围内。check = 1
:活动进行中,且用户未参与该活动,并且当前时间在活动时间范围内。check = 2
:用户已经参与该活动,且当前时间在活动时间范围内。check = 3
:用户已经达成了打卡天数要求。
-
查询条件:
- 根据输入的
status
、activityName
、startTime
和endTime
等条件筛选活动。 - 可以根据参与人数、开始时间、结束时间和活动名称进行排序,默认按参与人数降序排列。
- 根据输入的
-
数据库表连接:
activity
表:存储活动的基本信息。user_activity
表:记录用户参与活动的情况。check_in_activity
表:记录用户的打卡情况。
数据库表结构
活动表 activity
-- ----------------------------
-- Table structure for activity
-- ----------------------------
DROP TABLE IF EXISTS `activity`;
CREATE TABLE `activity` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动名称',
`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动描述',
`requirements` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动要求',
`start_time` date NULL DEFAULT NULL COMMENT '活动开始时间',
`end_time` date NULL DEFAULT NULL COMMENT '活动结束时间',
`participants_count` int NULL DEFAULT 0 COMMENT '活动参与人数',
`reward` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动奖励机制',
`status` tinyint NULL DEFAULT NULL COMMENT '活动状态(0未开始,1进行中,2已结束)',
`picture` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '活动图片链接',
`count_day` int NULL DEFAULT 0 COMMENT '活动打卡要求时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
用户活动表 user_activity
-- ----------------------------
-- Table structure for user_activity
-- ----------------------------
DROP TABLE IF EXISTS `user_activity`;
CREATE TABLE `user_activity` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
`user_id` int NULL DEFAULT NULL COMMENT '外键,关联用户信息表',
`activity_id` int NULL DEFAULT NULL COMMENT '外键,关联活动信息表',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
打卡活动表 check_in_activity
-- ----------------------------
-- Table structure for check_in_activity
-- ----------------------------
DROP TABLE IF EXISTS `check_in_activity`;
CREATE TABLE `check_in_activity` (
`id` int NOT NULL AUTO_INCREMENT COMMENT '主键,自增长',
`user_id` int NULL DEFAULT NULL COMMENT '外键,关联用户信息表',
`activity_id` int NULL DEFAULT NULL COMMENT '活动id',
`text` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '打卡文案',
`time` datetime NULL DEFAULT NULL COMMENT '打卡时间',
`images` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '打卡图片(最多9张)',
`analysis` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT 'AI智能分析',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 10 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
查询过程
-
主查询:
- 从
activity
表中选择所有字段,计算每个活动的check
字段。 - 使用
LEFT JOIN
连接user_activity
表,通过活动ID和用户ID进行匹配。
- 从
-
过滤条件:
- 通过输入的
status
、activityName
、startTime
和endTime
进行条件筛选。
- 通过输入的
-
排序:
- 先根据
check
字段从大到小排序,再根据指定的orderBy
字段排序。
- 先根据
SQL查询语句
<select id="searchActivities" parameterType="Map" resultType="java.util.HashMap">
SELECT a.*,
CASE
WHEN (
SELECT COUNT(DISTINCT DATE(cia.time))
FROM check_in_activity cia
WHERE cia.user_id = #{userId}
AND cia.activity_id = a.id
) >= a.count_day THEN 3
WHEN a.status = 1 AND NOW() BETWEEN a.start_time AND a.end_time THEN
CASE
WHEN ua.user_id IS NOT NULL THEN 2
ELSE 1
END
ELSE 0
END AS `check`
FROM activity a
LEFT JOIN user_activity ua ON a.id = ua.activity_id AND ua.user_id = #{userId}
WHERE 1 = 1
<if test="status != null">
AND a.status = #{status}
</if>
<if test="activityName != null and activityName != ''">
AND a.name LIKE CONCAT('%', #{activityName}, '%')
</if>
<if test="startTime != null">
AND a.start_time >= #{startTime}
</if>
<if test="endTime != null">
AND a.end_time <= #{endTime}
</if>
ORDER BY
`check` DESC,
<choose>
<when test="orderBy == 'participants_count'">
a.participants_count
</when>
<when test="orderBy == 'start_time'">
a.start_time
</when>
<when test="orderBy == 'end_time'">
a.end_time
</when>
<when test="orderBy == 'name'">
a.name
</when>
<otherwise>
a.participants_count
</otherwise>
</choose>
${order}
</select>
代码分析
SQL查询语句详解
-
SELECT子句:
SELECT a.*
- 选择
activity
表的所有字段。
- 选择
-
计算
check
字段:CASE WHEN ( SELECT COUNT(DISTINCT DATE(cia.time)) FROM check_in_activity cia WHERE cia.user_id = #{userId} AND cia.activity_id = a.id ) >= a.count_day THEN 3 WHEN a.status = 1 AND NOW() BETWEEN a.start_time AND a.end_time THEN CASE WHEN ua.user_id IS NOT NULL THEN 2 ELSE 1 END ELSE 0 END AS `check`
- 首先计算用户在特定活动中的打卡天数是否达到要求,如果达到了,
check
为3。 - 如果活动进行中,并且当前时间在活动的时间范围内,则进一步检查用户是否已经参与:
- 如果用户已经参与,
check
为2。 - 如果用户未参与,
check
为1。
- 如果用户已经参与,
- 如果活动未进行中,或当前时间不在活动时间范围内,
check
为0。
- 首先计算用户在特定活动中的打卡天数是否达到要求,如果达到了,
-
LEFT JOIN子句:
FROM activity a LEFT JOIN user_activity ua ON a.id = ua.activity_id AND ua.user_id = #{userId}
- 使用
LEFT JOIN
连接user_activity
表,通过活动ID和用户ID进行匹配,以获取用户参与活动的情况。
- 使用
-
过滤条件:
WHERE 1 = 1 <if test="status != null"> AND a.status = #{status} </if> <if test="activityName != null and activityName != ''"> AND a.name LIKE CONCAT('%', #{activityName}, '%') </if> <if test="startTime != null"> AND a.start_time >= #{startTime} </if> <if test="endTime != null"> AND a.end_time <= #{endTime} </if>
- 根据输入的
status
、activityName
、startTime
和endTime
进行条件筛选。
- 根据输入的
-
排序:
ORDER BY `check` DESC, <choose> <when test="orderBy == 'participants_count'"> a.participants_count </when> <when test="orderBy == 'start_time'"> a.start_time </when> <when test="orderBy == 'end_time'"> a.end_time </when> <when test="orderBy == 'name'"> a.name </when> <otherwise> a.participants_count </otherwise> </choose> ${order}
- 先根据
check
字段从大到小排序。 - 再根据指定的
orderBy
字段排序。 order
字段指定排序方式,升序或降序。
- 先根据
代码实现详解
import java.util.Map;
import java.util.HashMap;
public class ActivityService {
// 查询活动的方法
public Map<String, Object> searchActivities(Map<String, Object> params) {
// 执行SQL查询
List<Map<String, Object>> activities = activityMapper.searchActivities(params);
// 构建返回结果
Map<String, Object> result = new HashMap<>();
result.put("msg", "success");
result.put("result", activities);
result.put("code", 200);
return result;
}
}
-
方法定义:
public Map<String, Object> searchActivities(Map<String, Object> params)
- 定义一个方法
searchActivities
,接收一个参数params
,返回一个Map
对象。
- 定义一个方法
-
执行SQL查询:
List<Map<String, Object>> activities = activityMapper.searchActivities(params);
- 调用
activityMapper
的searchActivities
方法,传入params
参数,执行SQL查询,并返回活动列表。
- 调用
-
构建返回结果:
Map<String, Object> result = new HashMap<>(); result.put("msg", "success"); result.put("result", activities); result.put("code", 200);
- 创建一个
HashMap
对象result
,并将查询结果、消息和状态码放入其中。
- 创建一个
-
返回结果:
return result;
- 返回
result
对象。
- 返回
参数说明
userId
:用户ID,必填。status
:活动状态,可选。activityName
:活动名称,可选,支持模糊查询。startTime
:活动开始时间,可选,查询开始时间大于等于该时间的活动。endTime
:活动结束时间,可选,查询结束时间小于等于该时间的活动。orderBy
:排序字段,可选,支持按参与人数、开始时间、结束时间和活动名称排序。order
:排序方式,可选,支持升序(asc)和降序(desc)。
返回结果说明
msg
:消息,表示查询成功。result
:查询结果列表,包含活动信息和用户参与状态。code
:状态码,200表示成功。
Base URLs:
POST 用户查询活动
POST /user/searchActivities
根据userId查询活动,可以加上活动名称等条件值,可以根据参与人数等条件升序或降序排序。
会返回该用户是否已经参与该活动,能否参与该活动check:
1、活动进行中,且用户未参与该活动,且当前时间在时间范围内,可以参与该活动check=1;
2、活动未开始或者活动已经结束,或者在活动时间外,check=0;
3、用户已经参与该活动,且在活动时间内,check=2;
4、用户已经达成打卡天数,check=3;
Body 请求参数
{
"userId": 5,
"status": null,
"activityName": "",
"startTime": "",
"endTime": "",
"orderBy": "participants_count",
"order": "desc"
}
请求参数
名称 | 位置 | 类型 | 必选 | 说明 |
---|---|---|---|---|
token | header | string | 否 | none |
body | body | object | 否 | none |
» userId | body | integer | 是 | none |
» status | body | integer | 否 | 活动状态(0未开始,1进行中,2已结束) |
» activityName | body | string | 否 | none |
» startTime | body | string | 否 | none |
» endTime | body | string | 否 | none |
» orderBy | body | string | 是 | 根据什么排序,就填什么:比如participants_count、name、start_time、end_time |
» order | body | string | 是 | desc降序 或 asc升序 |
返回示例
成功
{
"msg": "success",
"result": [
{
"reward": "大白兔礼包",
"start_time": "2024-06-01",
"requirements": "连续打卡1天",
"participants_count": 100,
"name": "六一活动",
"end_time": "2024-06-07",
"description": "儿童节活动",
"count_day": 1,
"id": 1,
"check": 3,
"picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221703940.png",
"status": 0
},
{
"reward": "有机会获得健康饮食礼包或运动器材",
"start_time": "2024-06-14",
"requirements": "用户每天上传一张照片,这张照片可以是与父亲一起共进餐,或者为父亲准备的美食照片。可以只包含食物,不一定要包含父亲。即图片要求满足下面之一即可:1.有食物;2.有人物和食物;",
"participants_count": 1003,
"name": "\"父爱如山,食在心间\"父亲节特别活动",
"end_time": "2024-06-23",
"description": "上传与父亲的进餐瞬间",
"count_day": 5,
"id": 8,
"check": 1,
"picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406161248411.jpg",
"status": 1
},
{
"reward": "春节大礼包",
"start_time": "2024-01-01",
"requirements": "连续打卡10天",
"participants_count": 1000,
"name": "春节活动",
"end_time": "2024-03-01",
"description": "春节活动",
"count_day": 10,
"id": 3,
"check": 0,
"picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221705143.png",
"status": 1
},
{
"reward": "劳动礼包",
"start_time": "2024-05-01",
"requirements": "连续打卡5天",
"participants_count": 500,
"name": "五一活动",
"end_time": "2024-05-30",
"description": "劳动节活动",
"count_day": 5,
"id": 2,
"check": 0,
"picture": "https://lhplanet-1316168555.cos.ap-beijing.myqcloud.com/shanyi/development-documentation/development-documentation-v3.0.assets/202406221704667.png",
"status": 1
}
],
"code": 200
}
返回结果
状态码 | 状态码含义 | 说明 | 数据模型 |
---|---|---|---|
200 | OK | 成功 | Inline |
返回数据结构
状态码 200
名称 | 类型 | 必选 | 约束 | 中文名 | 说明 |
---|---|---|---|---|---|
» code | integer | true | none | none | |
» msg | string | true | none | none | |
» result | [object] | true | none | none | |
»» reward | string | true | none | none | |
»» start_time | string | true | none | none | |
»» requirements | string | true | none | none | |
»» participants_count | integer | true | none | none | |
»» name | string | true | none | none | |
»» end_time | string | true | none | none | |
»» description | string | true | none | none | |
»» count_day | integer | true | none | none | |
»» id | integer | true | none | none | |
»» check | integer | true | none | none | |
»» picture | string | true | none | none | |
»» status | integer | true | none | none |
设计优势和合理性
- 清晰的逻辑结构:
- 通过使用
CASE
语句和多个WHEN
子句,清晰地定义了用户在不同状态下的参与情况。check
字段的计算逻辑明确,便于理解和维护。
- 通过使用
- 灵活的查询条件:
- 使用
<if>
和<choose>
标签,允许根据不同条件动态生成SQL查询,增强了查询的灵活性和可定制性。用户可以根据需要筛选活动,并根据特定字段进行排序。
- 使用
- 高效的数据过滤:
- 使用
LEFT JOIN
将用户活动数据与活动数据连接,通过条件过滤精确获取用户相关的活动信息,避免了不必要的数据处理和计算。
- 使用
- 丰富的排序选项:
- 支持按多个字段排序,且排序方式可选(升序或降序),满足了用户的多样化需求。
- 参与状态的多维度检查:
- 通过多个条件判断用户的参与状态,不仅考虑了用户是否参与,还考虑了打卡天数等条件,确保返回的状态信息准确。