- 完成REQ-010-17(性能优化和限流处理)的所有6个阶段 - 创建ADR文档:0026-performance-optimization.md - 创建Prompt文档:027-performance-optimization.md - 创建会话记录:20260119-performance-optimization.md - 创建变更记录:20260119-performance-optimization.md - 创建复盘报告:20260119-performance-optimization-retro.md - 更新index.md和CHANGELOG.md - 完成REQ-010-2(基础实体类和Mapper创建)的前3个阶段 - 更新ADR文档:0011-entity-mapper-create.md - 创建Prompt文档:002-entity-mapper-create.md - 更新index.md 所有文档均按照SSOT方法论创建,包括需求定义、架构决策、提示词资产化、执行会话、变更记录和闭环复盘。
22 KiB
22 KiB
元数据任务定义管理 - 实现提示词
提示词信息
输入引用
真源文档
- REQ-010-4.md - 元数据任务定义管理需求文档
- ADR-0013.md - 元数据任务定义管理架构决策
- metadata-module.md - Salesforce Metadata API 模块说明
- file/index.md - 文件模块 API 文档索引
技术规范
- Spring Boot 3 + Vue 3 技术栈
- MyBatis Plus 持久层框架
- RESTful API 设计规范
- 项目编码规范
提示词内容
角色设定
你是一个经验丰富的 Spring Boot 全栈开发工程师,专注于 Salesforce 元数据管理系统的开发。你熟悉以下技术栈:
- 后端: Spring Boot 3, MyBatis Plus, MySQL
- 前端: Vue 3, Element Plus
- Salesforce API: Metadata API, Partner API
- 工具: Maven, Git, Postman
任务目标
实现元数据任务定义管理功能,包括:
-
任务定义 CRUD 功能
- 创建元数据任务
- 编辑元数据任务
- 删除元数据任务
- 查询元数据任务列表(支持分页和条件查询)
-
package.xml 内容配置
- 可视化编辑 package.xml 内容
- package.xml 格式验证
- 支持多种元数据类型配置
- 支持通配符配置
-
API 版本选择
- API 版本列表展示
- API 版本验证
- API 版本友好显示
-
调度类型选择
- 支持 Manual 和 Cron 两种调度类型
- 调度类型验证
- 调度类型友好显示
-
Cron 表达式配置
- Cron 表达式编辑
- Cron 表达式验证
- Cron 表达式预览
-
任务验证功能
- package.xml 格式验证
- Cron 表达式验证
- 验证失败返回详细错误信息
实现要求
1. 数据模型
根据 ADR-0013 中定义的数据模型,创建以下实体类:
@Data
@TableName("datai_meta_task")
public class DataiMetaTask {
@TableId(type = IdType.AUTO)
private Long id;
private String taskName;
private String taskType;
private Long orgConfigId;
@TableField(type = DbType.TEXT)
private String packageXml;
private String apiVersion;
private String scheduleType;
private String cronExpression;
private String status;
private String description;
private String createdBy;
private LocalDateTime createdTime;
private String updatedBy;
private LocalDateTime updatedTime;
}
2. Mapper 接口
@Mapper
public interface DataiMetaTaskMapper extends BaseMapper<DataiMetaTask> {
/**
* 查询任务列表
*/
IPage<DataiMetaTask> selectTaskPage(Page<DataiMetaTask> page, @Param("taskName") String taskName,
@Param("taskType") String taskType, @Param("status") String status);
/**
* 根据组织配置ID查询任务
*/
List<DataiMetaTask> selectByOrgConfigId(@Param("orgConfigId") Long orgConfigId);
}
3. Service 层
@Service
public class DataiMetaTaskServiceImpl implements IDataiMetaTaskService {
@Autowired
private DataiMetaTaskMapper taskMapper;
@Autowired
private PackageXmlValidator packageXmlValidator;
@Autowired
private CronExpressionValidator cronValidator;
/**
* 创建任务
*/
@Override
@Transactional
public Long createTask(DataiMetaTask task) {
// 验证 package.xml
ValidationResult xmlValidation = packageXmlValidator.validate(task.getPackageXml());
if (!xmlValidation.isSuccess()) {
throw new BusinessException(xmlValidation.getErrorMessage());
}
// 验证 Cron 表达式(如果是 Cron 调度)
if ("Cron".equals(task.getScheduleType())) {
ValidationResult cronValidation = cronValidator.validate(task.getCronExpression());
if (!cronValidation.isSuccess()) {
throw new BusinessException(cronValidation.getErrorMessage());
}
}
// 设置默认状态
task.setStatus("Active");
task.setCreatedTime(LocalDateTime.now());
task.setUpdatedTime(LocalDateTime.now());
// 保存任务
taskMapper.insert(task);
return task.getId();
}
/**
* 更新任务
*/
@Override
@Transactional
public void updateTask(DataiMetaTask task) {
// 验证 package.xml
ValidationResult xmlValidation = packageXmlValidator.validate(task.getPackageXml());
if (!xmlValidation.isSuccess()) {
throw new BusinessException(xmlValidation.getErrorMessage());
}
// 验证 Cron 表达式(如果是 Cron 调度)
if ("Cron".equals(task.getScheduleType())) {
ValidationResult cronValidation = cronValidator.validate(task.getCronExpression());
if (!cronValidation.isSuccess()) {
throw new BusinessException(cronValidation.getErrorMessage());
}
}
// 更新任务
task.setUpdatedTime(LocalDateTime.now());
taskMapper.updateById(task);
}
/**
* 删除任务
*/
@Override
@Transactional
public void deleteTask(Long id) {
taskMapper.deleteById(id);
}
/**
* 查询任务列表
*/
@Override
public IPage<DataiMetaTask> selectTaskPage(Integer pageNum, Integer pageSize, String taskName,
String taskType, String status) {
Page<DataiMetaTask> page = new Page<>(pageNum, pageSize);
QueryWrapper<DataiMetaTask> wrapper = new QueryWrapper<>();
if (StringUtils.isNotBlank(taskName)) {
wrapper.like("taskName", taskName);
}
if (StringUtils.isNotBlank(taskType)) {
wrapper.eq("taskType", taskType);
}
if (StringUtils.isNotBlank(status)) {
wrapper.eq("status", status);
}
wrapper.orderByDesc("createdTime");
return taskMapper.selectTaskPage(page, taskName, taskType, status);
}
/**
* 验证任务
*/
@Override
public ValidationResult validateTask(DataiMetaTask task) {
// 验证 package.xml
ValidationResult xmlValidation = packageXmlValidator.validate(task.getPackageXml());
if (!xmlValidation.isSuccess()) {
return xmlValidation;
}
// 验证 Cron 表达式(如果是 Cron 调度)
if ("Cron".equals(task.getScheduleType())) {
ValidationResult cronValidation = cronValidator.validate(task.getCronExpression());
if (!cronValidation.isSuccess()) {
return cronValidation;
}
}
return ValidationResult.success();
}
}
4. Controller 层
@RestController
@RequestMapping("/metadata/task")
public class DataiMetaTaskController {
@Autowired
private IDataiMetaTaskService taskService;
/**
* 创建任务
*/
@PostMapping
public Result<Long> createTask(@Valid @RequestBody DataiMetaTask task) {
Long taskId = taskService.createTask(task);
return Result.success(taskId);
}
/**
* 更新任务
*/
@PutMapping("/{id}")
public Result<Void> updateTask(@PathVariable Long id, @Valid @RequestBody DataiMetaTask task) {
task.setId(id);
taskService.updateTask(task);
return Result.success();
}
/**
* 删除任务
*/
@DeleteMapping("/{id}")
public Result<Void> deleteTask(@PathVariable Long id) {
taskService.deleteTask(id);
return Result.success();
}
/**
* 查询任务列表
*/
@GetMapping("/list")
public Result<IPage<DataiMetaTask>> list(
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize,
@RequestParam(required = false) String taskName,
@RequestParam(required = false) String taskType,
@RequestParam(required = false) String status) {
IPage<DataiMetaTask> page = taskService.selectTaskPage(pageNum, pageSize, taskName, taskType, status);
return Result.success(page);
}
/**
* 查询任务详情
*/
@GetMapping("/{id}")
public Result<DataiMetaTask> getTask(@PathVariable Long id) {
DataiMetaTask task = taskService.getById(id);
return Result.success(task);
}
/**
* 验证任务
*/
@PostMapping("/{id}/validate")
public Result<ValidationResult> validateTask(@PathVariable Long id) {
DataiMetaTask task = taskService.getById(id);
ValidationResult result = taskService.validateTask(task);
return Result.success(result);
}
}
5. package.xml 验证器
@Component
public class PackageXmlValidator {
private static final List<String> SUPPORTED_METADATA_TYPES = Arrays.asList(
"CustomObject", "CustomField", "ApexClass", "ApexTrigger",
"Layout", "Workflow", "ValidationRule", "Flow"
);
public ValidationResult validate(String packageXml) {
try {
// 解析 XML
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document doc = builder.parse(new InputSource(new StringReader(packageXml)));
// 验证根元素
NodeList types = doc.getElementsByTagName("types");
if (types.getLength() == 0) {
return ValidationResult.error("package.xml 必须包含 types 元素");
}
// 验证元数据类型
for (int i = 0; i < types.getLength(); i++) {
Element type = (Element) types.item(i);
String typeName = type.getTextContent();
if (!isSupportedMetadataType(typeName)) {
return ValidationResult.error("不支持的元数据类型: " + typeName);
}
}
return ValidationResult.success();
} catch (Exception e) {
return ValidationResult.error("package.xml 格式错误: " + e.getMessage());
}
}
private boolean isSupportedMetadataType(String typeName) {
return SUPPORTED_METADATA_TYPES.contains(typeName);
}
}
6. Cron 表达式验证器
@Component
public class CronExpressionValidator {
public ValidationResult validate(String cronExpression) {
try {
// 使用 Quartz 的 CronExpression 验证
CronExpression cron = new CronExpression(cronExpression);
// 验证是否有效
if (!cron.isValid()) {
return ValidationResult.error("Cron 表达式格式错误");
}
// 验证是否能够计算下次执行时间
Date nextValidTime = cron.getNextValidTimeAfter(new Date());
if (nextValidTime == null) {
return ValidationResult.error("Cron 表达式无法计算下次执行时间");
}
return ValidationResult.success(nextValidTime);
} catch (Exception e) {
return ValidationResult.error("Cron 表达式解析错误: " + e.getMessage());
}
}
}
7. 前端组件
<template>
<div class="task-manager">
<el-card>
<template #header>
<span>元数据任务管理</span>
<el-button type="primary" @click="showCreateDialog">创建任务</el-button>
</template>
<!-- 搜索表单 -->
<el-form :inline="true" :model="searchForm">
<el-form-item label="任务名称">
<el-input v-model="searchForm.taskName" placeholder="请输入任务名称" />
</el-form-item>
<el-form-item label="任务类型">
<el-select v-model="searchForm.taskType" placeholder="请选择任务类型">
<el-option label="拉取" value="retrieve" />
<el-option label="部署" value="deploy" />
</el-select>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="handleSearch">查询</el-button>
<el-button @click="handleReset">重置</el-button>
</el-form-item>
</el-form>
<!-- 任务列表 -->
<el-table :data="taskList" border>
<el-table-column prop="taskName" label="任务名称" />
<el-table-column prop="taskType" label="任务类型">
<template #default="{ row }">
<el-tag v-if="row.taskType === 'retrieve'" type="success">拉取</el-tag>
<el-tag v-else type="warning">部署</el-tag>
</template>
</el-table-column>
<el-table-column prop="scheduleType" label="调度类型" />
<el-table-column prop="status" label="状态">
<template #default="{ row }">
<el-tag v-if="row.status === 'Active'" type="success">启用</el-tag>
<el-tag v-else type="info">禁用</el-tag>
</template>
</el-table-column>
<el-table-column prop="createdTime" label="创建时间" />
<el-table-column label="操作" width="300">
<template #default="{ row }">
<el-button size="small" @click="handleEdit(row)">编辑</el-button>
<el-button size="small" type="danger" @click="handleDelete(row)">删除</el-button>
</template>
</el-table-column>
</el-table>
<!-- 分页 -->
<el-pagination
v-model:current-page="pagination.pageNum"
v-model:page-size="pagination.pageSize"
:total="pagination.total"
@current-change="handlePageChange"
@size-change="handleSizeChange"
/>
</el-card>
<!-- 创建/编辑对话框 -->
<el-dialog v-model="dialogVisible" :title="dialogTitle" width="80%">
<el-form :model="taskForm" :rules="formRules" ref="taskFormRef">
<el-form-item label="任务名称" prop="taskName">
<el-input v-model="taskForm.taskName" placeholder="请输入任务名称" />
</el-form-item>
<el-form-item label="任务类型" prop="taskType">
<el-select v-model="taskForm.taskType" placeholder="请选择任务类型">
<el-option label="拉取" value="retrieve" />
<el-option label="部署" value="deploy" />
</el-select>
</el-form-item>
<el-form-item label="组织配置" prop="orgConfigId">
<el-select v-model="taskForm.orgConfigId" placeholder="请选择组织配置">
<el-option
v-for="org in orgList"
:key="org.id"
:label="org.orgName"
:value="org.id"
/>
</el-select>
</el-form-item>
<el-form-item label="package.xml" prop="packageXml">
<el-input
v-model="taskForm.packageXml"
type="textarea"
:rows="10"
placeholder="请输入 package.xml 内容"
/>
</el-form-item>
<el-form-item label="API 版本" prop="apiVersion">
<el-select v-model="taskForm.apiVersion" placeholder="请选择 API 版本">
<el-option label="58.0" value="58.0" />
<el-option label="57.0" value="57.0" />
<el-option label="56.0" value="56.0" />
</el-select>
</el-form-item>
<el-form-item label="调度类型" prop="scheduleType">
<el-select v-model="taskForm.scheduleType" placeholder="请选择调度类型">
<el-option label="手动" value="Manual" />
<el-option label="Cron" value="Cron" />
</el-select>
</el-form-item>
<el-form-item label="Cron 表达式" prop="cronExpression" v-if="taskForm.scheduleType === 'Cron'">
<el-input v-model="taskForm.cronExpression" placeholder="请输入 Cron 表达式" />
<div class="cron-preview">
下次执行时间: {{ cronPreview }}
</div>
</el-form-item>
<el-form-item label="任务描述">
<el-input
v-model="taskForm.description"
type="textarea"
:rows="3"
placeholder="请输入任务描述"
/>
</el-form-item>
</el-form>
<template #footer>
<el-button @click="dialogVisible = false">取消</el-button>
<el-button type="primary" @click="handleSave">保存</el-button>
<el-button type="info" @click="handleValidate">验证</el-button>
</template>
</el-dialog>
</div>
</template>
<script setup>
import { ref, reactive, computed } from 'vue';
import { ElMessage } from 'element-plus';
const taskList = ref([]);
const dialogVisible = ref(false);
const dialogTitle = ref('创建任务');
const taskFormRef = ref(null);
const searchForm = reactive({
taskName: '',
taskType: '',
status: ''
});
const taskForm = reactive({
id: null,
taskName: '',
taskType: 'retrieve',
orgConfigId: null,
packageXml: '',
apiVersion: '58.0',
scheduleType: 'Manual',
cronExpression: '',
description: ''
});
const pagination = reactive({
pageNum: 1,
pageSize: 10,
total: 0
});
const orgList = ref([]);
const cronPreview = computed(() => {
// 计算 Cron 表达式的下次执行时间
if (taskForm.scheduleType === 'Cron' && taskForm.cronExpression) {
// 调用后端 API 计算
return '计算中...';
}
return '';
});
const formRules = {
taskName: [{ required: true, message: '请输入任务名称', trigger: 'blur' }],
taskType: [{ required: true, message: '请选择任务类型', trigger: 'change' }],
orgConfigId: [{ required: true, message: '请选择组织配置', trigger: 'change' }],
packageXml: [{ required: true, message: '请输入 package.xml 内容', trigger: 'blur' }],
apiVersion: [{ required: true, message: '请选择 API 版本', trigger: 'change' }],
scheduleType: [{ required: true, message: '请选择调度类型', trigger: 'change' }],
cronExpression: [{ required: true, message: '请输入 Cron 表达式', trigger: 'blur' }]
};
const handleSearch = () => {
// 查询任务列表
};
const handleReset = () => {
searchForm.taskName = '';
searchForm.taskType = '';
searchForm.status = '';
handleSearch();
};
const showCreateDialog = () => {
dialogTitle.value = '创建任务';
Object.assign(taskForm, {
id: null,
taskName: '',
taskType: 'retrieve',
orgConfigId: null,
packageXml: '',
apiVersion: '58.0',
scheduleType: 'Manual',
cronExpression: '',
description: ''
});
dialogVisible.value = true;
};
const handleEdit = (row) => {
dialogTitle.value = '编辑任务';
Object.assign(taskForm, row);
dialogVisible.value = true;
};
const handleDelete = (row) => {
ElMessage.confirm('确定要删除该任务吗?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
// 调用删除 API
ElMessage.success('删除成功');
handleSearch();
});
};
const handleSave = () => {
taskFormRef.value.validate((valid) => {
if (valid) {
// 调用保存 API
ElMessage.success('保存成功');
dialogVisible.value = false;
handleSearch();
}
});
};
const handleValidate = () => {
// 调用验证 API
};
const handlePageChange = (pageNum) => {
pagination.pageNum = pageNum;
handleSearch();
};
const handleSizeChange = (pageSize) => {
pagination.pageSize = pageSize;
handleSearch();
};
</script>
<style scoped>
.task-manager {
padding: 20px;
}
.cron-preview {
margin-top: 10px;
padding: 10px;
background-color: #f5f7fa;
border-radius: 4px;
}
</style>
输出格式
1. 代码结构
datai-salesforce-metadata/
├── src/main/java/com/datai/metadata/
│ ├── controller/
│ │ └── DataiMetaTaskController.java
│ ├── service/
│ │ ├── IDataiMetaTaskService.java
│ │ └── impl/
│ │ └── DataiMetaTaskServiceImpl.java
│ ├── mapper/
│ │ └── DataiMetaTaskMapper.java
│ ├── entity/
│ │ └── DataiMetaTask.java
│ └── validator/
│ ├── PackageXmlValidator.java
│ └── CronExpressionValidator.java
└── src/main/resources/
└── mapper/
└── DataiMetaTaskMapper.xml
2. 单元测试
必须为以下类编写单元测试:
- DataiMetaTaskServiceImpl
- PackageXmlValidator
- CronExpressionValidator
- DataiMetaTaskController
3. 集成测试
必须编写以下集成测试:
- 任务 CRUD 操作
- package.xml 验证
- Cron 表达式验证
- API 接口测试
4. API 文档
必须为以下接口编写 API 文档:
- POST /metadata/task - 创建任务
- PUT /metadata/task/{id} - 更新任务
- DELETE /metadata/task/{id} - 删除任务
- GET /metadata/task/list - 查询任务列表
- GET /metadata/task/{id} - 查询任务详情
- POST /metadata/task/{id}/validate - 验证任务
注意事项
- package.xml 存储: 使用 TEXT 类型存储,避免 VARCHAR 长度限制
- Cron 表达式: 使用 Quartz 库进行验证,确保格式正确
- 事务管理: 创建、更新、删除操作必须使用 @Transactional 注解
- 参数验证: 使用 @Valid 注解进行参数验证
- 异常处理: 使用统一的异常处理机制,返回友好的错误信息
- 日志记录: 记录关键操作的日志,便于问题排查
- 权限控制: 根据用户权限控制任务的访问和操作
参考资料
- REQ-010-4.md - 元数据任务定义管理需求
- ADR-0013.md - 元数据任务定义管理架构决策
- metadata-module.md - Salesforce Metadata API 模块说明
- Authentication.canvas - 项目架构视觉化展示