add
This commit is contained in:
@@ -1,417 +0,0 @@
|
||||
# 需求概述
|
||||
|
||||
统计项目运营数据相关功能开发。
|
||||
|
||||
## 核心技术栈
|
||||
|
||||
- Java:OpenJDK21
|
||||
- SpringBoot:3.2.9
|
||||
- MybatisPlus:3.5.7
|
||||
- RocketMQ:
|
||||
- spring-boot-starter:2.2.3
|
||||
- rocketmq-client:4.9.8
|
||||
- MySQL:8.0+
|
||||
- Redis:8.0+
|
||||
|
||||
## 目录说明
|
||||
|
||||
- 根目录:"E:\gitlab\mis-dev\mis-modules\mis-agent\src\main\java\com\lcfc\agent\stats"
|
||||
- Controller:"<根目录>\api"
|
||||
- Service:"<根目录>\service"
|
||||
- 配置类:"<根目录>\conf"
|
||||
- DTO:"<根目录>\domain\dto"
|
||||
- VO:"<根目录>\domain\vo"
|
||||
- Enum:"<根目录>\domain\enums"
|
||||
- Entity:"<根目录>\domain\entity"
|
||||
- Mapper:
|
||||
- Java源文件:"<根目录>\domain\mapper"
|
||||
- XML文件:"E:\gitlab\mis-dev\mis-modules\mis-agent\src\main\resources\mapper"
|
||||
- 消息队列相关
|
||||
- 消息载体:"<根目录>\mq\event"
|
||||
- 监听器:"<根目录>\mq\consumer"
|
||||
- SQL文件:"E:\stf\tmp\sql.md"
|
||||
- 接口文档:"E:\stf\tmp\api.md"
|
||||
|
||||
## 公共约定
|
||||
|
||||
- 代码书写规范:https://git.jkwlstv.cn/doc/prompts/src/branch/main/clean_java_code_rules.md
|
||||
- 接口文档示例:https://git.jkwlstv.cn/doc/prompts/raw/branch/main/example_rest_api_doc.md
|
||||
- SQL示例:https://git.jkwlstv.cn/doc/prompts/raw/branch/main/example_mysql_ddl.md
|
||||
- 实体类示例代码:https://git.jkwlstv.cn/doc/prompts/raw/branch/main/example_entity.md
|
||||
- 枚举类示例代码:https://git.jkwlstv.cn/doc/prompts/raw/branch/main/example_enum.md
|
||||
- 枚举类、常量类、工具函数、VO、DTO均不能复用其它目录下面的,可以抄一个放到<目录说明>中对应的目录下,因为该模块未来可能会独立出去
|
||||
|
||||
## 任务清单
|
||||
|
||||
### 生成表结构
|
||||
|
||||
- 数据库表结构字段名称、实体类字段名称,采用驼峰与下划线映射的方式。
|
||||
- 查看<Entity>目录下所有被`@TableName`注解修饰的源文件,生成MySQL建表语句,建表语句存放到<SQL文件>目录下。
|
||||
- 包含`project_id`字段的表都需要对它建立普通索引。
|
||||
- 在`project_stats_registry`表中`project_name`和`agent_id`要创建唯一索引。
|
||||
- 在`project_data_stats_daily`表中`project_id`和`daily`要创建唯一索引。
|
||||
- 实体类字段包含`@NotNull`注解,你需要结合`@Schema`注解中的`defaultValue`属性判断是否需要设置默认值。
|
||||
- 主键列是否需要用MySQL的自增序列,取决于实体类被`@TableId`注解修饰的字段,要看其`type`属性,如果是`IdType.AUTO`则使用自增,否则不需要。
|
||||
- 如果`@Schema`注解指定了`maxLength`属性,按如下原则设置字段类型:
|
||||
- 数值小于或等于2000,使用VARCHAR
|
||||
- 数值大于2000且小于10000,使用TEXT
|
||||
- 数值大于10000,使用LONGTEXT
|
||||
- 实体类的属性类型与表结构的字段类型映射关系:
|
||||
- String类型默认使用VARCHAT(255)
|
||||
- Long类型默认使用BIGINT
|
||||
- Integer类型默认使用INT
|
||||
- LocalDate类型默认使用DATE
|
||||
- LocalDateTime类型默认使用DATETIME
|
||||
- `@TableField`注解中`typeHandler`等于`JacksonTypeHandler.class`时,表结构字段类型默认使用JSON
|
||||
|
||||
### 项目日志
|
||||
|
||||
#### 清理过期错误日志
|
||||
|
||||
根据`ProjectStatsLogConfig.java`的`cleanExpireErrorLogRedisKey`属性,从Redis中查询是否存在该Key,如果存在不执行任何动作,不存在则视为今天没有清理过,需要执行清理动作,先将该Key存储到Redis中,值设置为"1",过期时间的计算公式:
|
||||
|
||||
```java
|
||||
public static long endDayOfMills() {
|
||||
LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
return Duration.between(now, endOfDay).toMillis();
|
||||
}
|
||||
```
|
||||
|
||||
RedisKey存储成功后,开启一个虚拟线程,物理删除N天前的日志,N的数值取自`ProjectStatsLogConfig.java`的`errorLogExpireDays`属性。
|
||||
|
||||
#### 创建错误日志
|
||||
|
||||
执行一遍<清理过期错误日志>然后创建`ProjectStatsLog.java`对象,然后调用Mapper接口相关方法保存,要求如下:
|
||||
|
||||
- 处理日志过程中发生异常,打印一条log即可,不要抛异常到外层。
|
||||
- 用`ERROR`填充`logLevel`字段
|
||||
- 用当前时间填充`createTime`字段
|
||||
- 调用方至少要上报`description`、`exceptionStackTrace`、`keyParameters`其中之一。如果都没上报,这条日志就不记了。
|
||||
- 如果`description`不为空,要看字符长度是否大于`ProjectStatsLogConfig.java`的`descriptionMaxLength`属性,超长则截断。
|
||||
- 如果`exceptionStackTrace`不为空,要看字符长度是否大于`ProjectStatsLogConfig.java`的`exceptionStackTraceMaxLength`属性,超长则截断。
|
||||
|
||||
#### 创建普通日志
|
||||
|
||||
执行一遍<清理过期错误日志>然后创建`ProjectStatsLog.java`对象,然后调用Mapper接口相关方法保存,要求如下:
|
||||
|
||||
- 处理日志过程中发生异常,打印一条log即可,不要抛异常到外层。
|
||||
- 用`INFO`填充`logLevel`字段
|
||||
- 用当前时间填充`createTime`字段
|
||||
- 调用方至少要上报`description`、`keyParameters`其中之一。如果都没上报,这条日志就不记了。
|
||||
- 如果`description`不为空,要看字符长度是否大于`ProjectStatsLogConfig.java`的`descriptionMaxLength`属性,超长则截断。
|
||||
|
||||
### 监听器
|
||||
|
||||
按照业务逻辑实现各个监听器的`onMessage`方法。使用try-catch语法捕获异常,如果遇到异常,打印一条log,并参考<创建错误日志>生成1条错误日志即可。
|
||||
|
||||
#### 匹配项目注册表
|
||||
|
||||
根据`projectName`和`agentId`字段去查询`project_stats_registry`表,查不到数据参考<创建错误日志>生成1条错误日志,`description`字段赋值"项目未注册",`keyParameters`赋值`onMessage`方法入参的对象。查得到数据视为满足要求,返回`ProjectStatsRegistry`对象,并继续执行业务逻辑。
|
||||
|
||||
#### ProjectAgentChatLifeCycleEventConsumer.java
|
||||
|
||||
先<匹配项目注册表>满足要求再按下述要求继续执行:
|
||||
|
||||
1. 根据今天的日期,查看`project_data_stats_daily`是否有数据,没数据`insert`否则`update`,请通过`ON DUPLICATE KEY UPDATE`实现。
|
||||
2. 把`inputToken`、`outputToken`、`callMcpToolCount`、`callSkillCount`字段累加到`project_data_stats_daily`和`project_data_stats`相关字段。
|
||||
3. 如果`kbDocUseInfo`不为空,要把相同的`kbId`合并成一条,把`docIds`去重合并。
|
||||
4. 如果`mcpUseInfo`不为空,要把相同的`mcpServerId`合并成一条,把`toolNames`去重合并。
|
||||
5. 如果`skillUseInfo`不为空,要把`skillNames`去重合并。
|
||||
6. 每收到1条数据,`project_data_stats_daily`和`project_data_stats`中的`chatNum`字段+1。
|
||||
7. 把`userId`去重合并到`project_data_stats_daily`和`project_data_stats`中的`user_id`,同时更新`userNum`字段,数值是`userId`的个数。
|
||||
8. 修改数据库表数据时,所有包含`updateTime`的表,都要设置为当前时间。
|
||||
|
||||
#### ProjectInfoUpdateEventConsumer.java
|
||||
|
||||
如果`ProjectInfoUpdatePayload.java`中的`before`和`after`的字段其中1个是Null都不执行任何操作,否则按如下要求执行:
|
||||
|
||||
1. 根据`before`中的`projectName`和`agentId`字段查询`project_stats_registry`表。查不到数据执行第2步,然后结束。查到数据从第3步继续执行。
|
||||
2. 参考<创建错误日志>生成1条错误日志,`description`赋值"项目未注册",`keyParameters`赋值`ProjectInfoUpdatePayload.java`对象。
|
||||
3. 参考<创建普通日志>生成1条普通日志,`description`赋值"项目信息变更",`keyParameters`赋值`ProjectInfoUpdatePayload.java`对象。
|
||||
4. 用`after`中的字段去覆盖第1步查出来数据,注意:只有不为空才更新!
|
||||
|
||||
#### ProjectUserDisLikeEventConsumer.java
|
||||
|
||||
先<匹配项目注册表>满足要求则执行:
|
||||
|
||||
- 从`dateTime`获取`LocalDate`值,结合`projectId`、`daily`去查询`ProjectDataStatsDaily`,存在数据将其`userDislikeCount`字段原子化+1即可。
|
||||
- 根据`projectId`查询`ProjectDataStats`,存在数据将其`userDislikeCount`字段原子化+1即可。
|
||||
|
||||
#### ProjectUserDisLikeUndoEventConsumer.java
|
||||
|
||||
先<匹配项目注册表>满足要求则执行:
|
||||
|
||||
- 从`dateTime`获取`LocalDate`值,结合`projectId`、`daily`去查询`ProjectDataStatsDaily`,存在数据将其`userDislikeCount`字段原子化-1即可。
|
||||
- 根据`projectId`查询`ProjectDataStats`,存在数据将其`userDislikeCount`字段原子化-1即可。
|
||||
|
||||
#### ProjectUserFeedbackEventConsumer.java
|
||||
|
||||
先<匹配项目注册表>满足要求则执行:
|
||||
|
||||
- 从`dateTime`获取`LocalDate`值,结合`projectId`、`daily`去查询`ProjectDataStatsDaily`,存在数据将其`userFeedbackCount`字段原子化+1即可。
|
||||
- 根据`projectId`查询`ProjectDataStats`,存在数据将其`userFeedbackCount`字段原子化+1即可。
|
||||
|
||||
#### ProjectUserFeedbackUndoEventConsumer.java
|
||||
|
||||
先<匹配项目注册表>满足要求则执行:
|
||||
|
||||
- 从`dateTime`获取`LocalDate`值,结合`projectId`、`daily`去查询`ProjectDataStatsDaily`,存在数据将其`userFeedbackCount`字段原子化-1即可。
|
||||
- 根据`projectId`查询`ProjectDataStats`,存在数据将其`userFeedbackCount`字段原子化-1即可。
|
||||
|
||||
### ProjectStatsController.java
|
||||
|
||||
- 业务逻辑的实现存放到"E:\gitlab\mis-dev\mis-modules\mis-agent\src\main\java\com\lcfc\agent\stats\service\ProjectStatsDataQueryService.java"。
|
||||
- 除了生成源码以外,还要根据<示例>里面的<接口文档>参考链接,生成接口文档,并将其存放到<目录说明>中的<接口文档>文件中。
|
||||
|
||||
#### ProjectStatsControllerRules
|
||||
|
||||
1. 分页接口参考`AgentPageController.java`中的`searchSingleAgent`方法去实现。
|
||||
|
||||
2. 数据图表请求参数中的`维度`分为:日、月、年,字段请使用枚举类。与维度一同出现的参数还有`begin`和`end`,`end`的数值可以等于`begin`但不能小于它。
|
||||
- 当`维度`等于`日`,`begin`和`end`的上报格式:"yyyy-MM-dd"
|
||||
- 当`维度`等于`月`,`begin`和`end`的上报格式:"yyyy-MM"
|
||||
- 当`维度`等于`年`,`begin`和`end`的上报格式:"yyyy"
|
||||
|
||||
3. 数据图表响应参数中的`x`代表图表的横坐标,根据不同的`维度`填充不同的数值,规则如下:
|
||||
- 当`维度`等于`日`,`begin`到`end`之间的日期,包含`begin`和`end`,格式:"yyyy-MM-dd"
|
||||
- 当`维度`等于`月`,`begin`到`end`之间的月份,包含`begin`和`end`,格式:"yyyy-MM"
|
||||
- 当`维度`等于`年`,`begin`到`end`之间的年份,包含`begin`和`end`,格式:"yyyy"
|
||||
|
||||
4. 数据图表在根据`月`和`年`这2个维度查询图表数据的时候,涉及到计算的部分,不要在数据库进行,1个项目1年的数据也就300多条,按需查询对应字段,使用Java完成计算,优先使用`Stream`。
|
||||
|
||||
5. Token的显示规则与单位请参考`AgentChatMetricsServiceImpl.java`中的`getAgentMetricsLineChartToken`处理逻辑
|
||||
|
||||
#### 项目数据统计(需要分页)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/page
|
||||
- Content-Type:application/json
|
||||
|
||||
使用`project_stats_registry`与`project_data_stats`关联查询相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|pageSize|Integer|分页参数,1页的条数,默认值:20|
|
||||
|pageNum|Integer|分页参数,1页的条数,默认值:1|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|项目ID|String|无|
|
||||
|项目名称|String|无|
|
||||
|用户数|Long|无|
|
||||
|对话数|Long|无|
|
||||
|消耗Token|String|输入和输出token相加,显示规则参考<ProjectStatsControllerRules>|
|
||||
|输入Token|String|显示规则参考<ProjectStatsControllerRules>|
|
||||
|输出Token|String|显示规则参考<ProjectStatsControllerRules>|
|
||||
|知识库文档数|Long|用kbDocNum|
|
||||
|MCP工具调用次数|Long|无|
|
||||
|Skill调用次数|Long|无|
|
||||
|
||||
#### 累计数据
|
||||
|
||||
- 请求方式:GET
|
||||
- URL:/project/stats/total?projectId={projectId}
|
||||
|
||||
根据`projectId`查询并计算`project_data_stats`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|累计用户数|Long|无|
|
||||
|累计对话数|Long|无|
|
||||
|累计消耗Token|String|累计输入和累计输出token相加,显示规则参考<ProjectStatsControllerRules>|
|
||||
|累计输入Token|String|显示规则参考<ProjectStatsControllerRules>|
|
||||
|累计输出Token|String|显示规则参考<ProjectStatsControllerRules>|
|
||||
|知识库文档数|Long|用kbDocNum|
|
||||
|知识库文档有效率|String|计算公式:调用的文档数量(去重)/ kbDocNum,精度:四舍五入保留两位小数|
|
||||
|累计点踩数|Long|无|
|
||||
|点踩率|String|计算公式=累计点踩数/累计对话数,精度:四舍五入保留两位小数|
|
||||
|累计反馈数|Long|无|
|
||||
|累计MCP工具调用个数|Long|计算所有mcpUseInfo中的toolNames总个数|
|
||||
|累计MCP工具调用次数|Long|无|
|
||||
|累计Skill调用个数|Long|提取skillUseInfo中的skillNames的个数|
|
||||
|累计Skill调用次数|Long|无|
|
||||
|
||||
|
||||
#### 数据图表(用户数)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/user
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>|如果维度是`日`,直接使用`userNum`,否则把每一天数据里的`userId`合并去重后计算总个数|
|
||||
|
||||
#### 数据图表(对话数)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/chat
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>|如果维度是`日`,直接使用`chatNum`,否则根据维度分组并求和|
|
||||
|
||||
#### 数据图表(消耗Token)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/token
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|type|枚举|三种类型:all、input、output|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>| 如果请求参数的`type`的值是`all`,取`inputToken`和`outputToken`相加的值。如果是`input`取`inputToken`。如果是`output`取`inputToken`。如果维度是`日`,直接返回`type`对应的数值,否则根据维度分组并求和,显示规则参考<ProjectStatsControllerRules>|
|
||||
|
||||
#### 数据图表(对话点踩数)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/dislike
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>| 如果维度是`日`,直接使用`userDislikeCount`,否则根据维度分组并求和|
|
||||
|
||||
#### 数据图表(对话反馈数)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/feedback
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>| 如果维度是`日`,直接使用`userFeedbackCount`,否则根据维度分组并求和|
|
||||
|
||||
#### 数据图表(MCP使用情况)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/mcp/usage
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|type|枚举值|两种类型,num=个数,count=次数|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>|如果请求参数中的`type`是`num`,则需要对`mcpUseInfo`中`mcpServerId`进行分组并去重`toolNames`,计算`toolNames`的个数,如果`type`是`count`,则使用`callMcpToolCount`。如果维度是`日`,直接返回`type`对应的数值,否则根据维度分组并求和|
|
||||
|
||||
#### 数据图表(Skill使用情况)
|
||||
|
||||
- 请求方式:POST
|
||||
- URL:/project/stats/chart/skill/usage
|
||||
- Content-Type:application/json
|
||||
|
||||
查询并计算`project_data_stats_daily`相关数据。
|
||||
|
||||
##### 请求参数
|
||||
|
||||
| 参数名称 | 类型 | 说明 |
|
||||
|:-----|:-----|:-----|
|
||||
|projectId|String|项目ID|
|
||||
|维度|枚举|参考<ProjectStatsControllerRules>|
|
||||
|begin|String|参考<ProjectStatsControllerRules>|
|
||||
|end|String|参考<ProjectStatsControllerRules>|
|
||||
|type|枚举值|两种类型,num=个数,count=次数|
|
||||
|
||||
##### 响应参数
|
||||
|
||||
| 参数名称 | 类型 | 备注 |
|
||||
|:-----|:-----|:-----|
|
||||
|x|List<String>|参考<ProjectStatsControllerRules>|
|
||||
|y|List<String>|如果请求参数中的`type`是`num`,则需要对`skillUseInfo`中`skillNames`合并然后去重`toolNames`计算个数,如果`type`是`count`,则使用`callSkillCount`。如果维度是`日`,直接返回`type`对应的数值,否则根据维度分组并求和|
|
||||
@@ -19,14 +19,12 @@
|
||||
|spring-ai-alibaba|1.1.2.2|https://java2ai.com/docs/overview|https://github.com/alibaba/spring-ai-alibaba/tree/v1.1.2.2|
|
||||
|spring-ai|1.1.2|https://docs.spring.io/spring-ai/reference/1.1/index.html|https://github.com/spring-projects/spring-ai/tree/v1.1.2|
|
||||
|
||||
## 代码编写守则
|
||||
## 必须遵守的代码编写守则
|
||||
|
||||
- [代码书写规范](./clean_java_code_rules.md)
|
||||
- [ORM实体类示例](./example_entity.md)
|
||||
- [枚举类示例](./example_enum.md)
|
||||
- [SQL示例](./example_mysql_ddl.md)
|
||||
- [书写HTTP接口文档示例](./example_rest_api_doc.md)
|
||||
- [DTO/VO示例](./example_dto_bean.md)
|
||||
- [数据库实体类与建表规范](./orm.md)
|
||||
- [JavaBean书写规范](./javabean.md)
|
||||
- [书写HTTP接口文档示例](./api_doc.md)
|
||||
|
||||
## 目录结构
|
||||
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
```java
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Schema(title = "DTO示例")
|
||||
public class ExampleDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long id;
|
||||
|
||||
@NotBlank
|
||||
@Schema(description = "字符串")
|
||||
private String strField;
|
||||
|
||||
@Schema(description = "整数", defaultValue = "0")
|
||||
private Integer intField;
|
||||
|
||||
@Schema(description = "长整数")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long longField;
|
||||
|
||||
@Schema(description = "高精度浮点数")
|
||||
private BigDecimal decimalField;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "日期类型", pattern = "yyyy-MM-dd")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private LocalDate dateField;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "时间类型", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime timeField;
|
||||
|
||||
@NotNull
|
||||
@Schema(
|
||||
title = "状态",
|
||||
description = "参考示例值",
|
||||
example = StateEnum.DESC
|
||||
)
|
||||
private StateEnum state;
|
||||
|
||||
@Schema(description = "JSON类型")
|
||||
private JsonField jsonField;
|
||||
|
||||
@Data
|
||||
public static class JsonField implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "示例字段1")
|
||||
private String field1;
|
||||
|
||||
@Schema(description = "示例字段2")
|
||||
private Integer field2;
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
@@ -1,29 +0,0 @@
|
||||
```java
|
||||
import com.baomidou.mybatisplus.annotation.EnumValue;
|
||||
import com.fasterxml.jackson.annotation.JsonCreator;
|
||||
import com.fasterxml.jackson.annotation.JsonValue;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
@Schema(description = "某某状态")
|
||||
public enum StateEnum {
|
||||
|
||||
ONLY_READ("only_read"),
|
||||
|
||||
READ_WRITE("read_write");
|
||||
|
||||
public static final String DESC = "only_read=只读、read_write=读写";
|
||||
|
||||
@JsonValue
|
||||
@EnumValue
|
||||
private final String value;
|
||||
|
||||
@JsonCreator
|
||||
public static StateEnum deserialize(String input) {
|
||||
return Arrays.stream(values()).filter(e -> e.getValue().equals(input)).findFirst().orElse(null);
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -1,16 +0,0 @@
|
||||
建表语句:
|
||||
|
||||
```sql
|
||||
CREATE TABLE `example_table` (
|
||||
`id` BIGINT NOT NULL COMMENT 'ID',
|
||||
`str_field` VARCHAR(32) NOT NULL COMMENT '字符串`,
|
||||
`int_field` INT DEFAULT NULL COMMENT '整数`,
|
||||
`long_field` BIGINT DEFAULT NULL COMMENT '长整数`,
|
||||
`decimal_field` DECIMAL(14, 2) DEFAULT NULL COMMENT '高精度浮点数`,
|
||||
`date_field` DATE NOT NULL COMMENT '日期类型`,
|
||||
`time_field` DATETIME NOT NULL COMMENT '日期类型`,
|
||||
`state` VARCHAR(32) NOT NULL COMMENT '状态:only_read、read_write',
|
||||
`json_field` JSON DATETIME NULL COMMENT 'JSON类型'
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='示例表';
|
||||
```
|
||||
@@ -1,3 +1,9 @@
|
||||
# JavaBean生成规范
|
||||
|
||||
请根据代码示例生成:数据库实体类、枚举类、DTO、VO。
|
||||
|
||||
## 数据库实体类示例
|
||||
|
||||
```java
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
@@ -22,7 +28,7 @@ import java.math.BigDecimal;
|
||||
@Data
|
||||
@TableName(value = "example_table", autoResultMap = true)
|
||||
@Schema(title = "示例表")
|
||||
public class AgentUsageStats implements Serializable {
|
||||
public class ExampleEntity implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
@@ -92,4 +98,64 @@ public class AgentUsageStats implements Serializable {
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
## DTO、VO
|
||||
|
||||
```java
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
@Data
|
||||
@Schema(title = "DTO示例")
|
||||
public class ExampleDTO implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@NotBlank
|
||||
@Schema(description = "字符串")
|
||||
private String strField;
|
||||
|
||||
@Schema(description = "长整数")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private Long longField;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "日期类型", pattern = "yyyy-MM-dd")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private LocalDate dateField;
|
||||
|
||||
@NotNull
|
||||
@Schema(description = "时间类型", pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime timeField;
|
||||
|
||||
@NotNull
|
||||
@Schema(
|
||||
title = "状态",
|
||||
description = "参考示例值",
|
||||
example = StateEnum.DESC
|
||||
)
|
||||
private StateEnum state;
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
## 枚举类代码示例
|
||||
|
||||
[enums.md](./enums.md)
|
||||
44
orm.md
Normal file
44
orm.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# 实体类与数据库表书写规范
|
||||
|
||||
- 数据库表结构字段名称、实体类字段名称,采用驼峰与下划线映射的方式。
|
||||
- 实体类字段包含`@NotNull`注解,需要结合`@Schema`注解中的`defaultValue`属性判断是否需要设置默认值。
|
||||
- 主键列是否采用MySQL自增序列,取决于实体类被`@TableId`注解修饰的字段,要看其`type`属性,如果是`IdType.AUTO`则使用自增,否则不需要。
|
||||
- 如果`@Schema`注解指定了`maxLength`属性,按如下原则设置字段类型:
|
||||
- 数值小于或等于2000,使用VARCHAR
|
||||
- 数值大于2000且小于10000,使用TEXT
|
||||
- 数值大于10000,使用LONGTEXT
|
||||
- 实体类的属性类型与表结构的字段类型映射关系:
|
||||
- String:默认VARCHAT(255)
|
||||
- Long:默认BIGINT
|
||||
- Integer:默认INT
|
||||
- LocalDate:默认DATE
|
||||
- LocalDateTime:默认DATETIME
|
||||
- `@TableField`注解中`typeHandler`等于`JacksonTypeHandler.class`时,表结构字段默认JSON类型
|
||||
- BigDecimal:默认DECIMAL(14, 2)
|
||||
|
||||
请根据以上规范,结合下文代码示例,生成建表语句和Java实体类代码。
|
||||
|
||||
## MySQL建表语句示例
|
||||
|
||||
```sql
|
||||
CREATE TABLE `example_table` (
|
||||
`id` BIGINT NOT NULL COMMENT 'ID',
|
||||
`str_field` VARCHAR(32) NOT NULL COMMENT '字符串`,
|
||||
`int_field` INT DEFAULT NULL COMMENT '整数`,
|
||||
`long_field` BIGINT DEFAULT NULL COMMENT '长整数`,
|
||||
`decimal_field` DECIMAL(14, 2) DEFAULT NULL COMMENT '高精度浮点数`,
|
||||
`date_field` DATE NOT NULL COMMENT '日期类型`,
|
||||
`time_field` DATETIME NOT NULL COMMENT '日期类型`,
|
||||
`state` VARCHAR(32) NOT NULL COMMENT '状态:only_read、read_write',
|
||||
`json_field` JSON DATETIME NULL COMMENT 'JSON类型'
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='示例表';
|
||||
```
|
||||
|
||||
## Java实体类示例
|
||||
|
||||
[javabean.md](./javabean.md#数据库实体类示例)
|
||||
|
||||
## 枚举类代码示例
|
||||
|
||||
[enums.md](./enums.md)
|
||||
Reference in New Issue
Block a user