mcpField
C
crud-rest-controller

crud-rest-controller

github.com/amplicode开发134430 次安装7 周前更新
代码仓库

关于 crud-rest-controller

crud-rest-controller 是 Spring Agent Toolkit 中用于生成实体 CRUD REST 控制器的技能,可结合 Spring Data repository、DTO 映射、分页、过滤和 patch。它通过 Amplicode IntelliJ 插件的 Spring MCP 获取项目上下文,并要求代码严格遵循示例文件。

主要功能

  1. 01生成标准 CRUD REST 端点
  2. 02支持 Spring Data repository
  3. 03可选 DTO 映射与分页
  4. 04支持过滤和 patch
  5. 05仅按示例文件编写代码

适用场景

  1. 01为实体生成 CRUD REST 控制器
  2. 02为列表端点配置分页或过滤
  3. 03使用 DTO 处理实体请求与响应

MCP 相关

依赖 Amplicode IntelliJ 插件提供的 Spring MCP 服务获取项目摘要、依赖和端点信息。若 MCP 工具不可用,技能会要求先安装并配置插件。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/amplicode/spring-skills --skill crud-rest-controller

安装后在 Claude Code 中输入/crud-rest-controller确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

examples/_beans/injection/
java.md
kotlin.md
examples/_beans/repo-enhance/
java.md
kotlin.md
examples/_dependencies/
dependencies.md
examples/_methods/create/
java.md
kotlin.md
examples/_methods/delete-many/
java.md
kotlin.md
examples/_methods/delete/
java.md
kotlin.md
examples/_methods/get-list/
java.md
kotlin.md
examples/_methods/get-many/
java.md
kotlin.md
examples/_methods/get-one/
java.md
kotlin.md
examples/_methods/patch-many/
java.md
kotlin.md
examples/_methods/patch/
java.md
kotlin.md
examples/_skeletons/
java.md
kotlin.md

详细介绍

Preflight:Spring MCP

此技能属于 Spring Agent Toolkit,旨在与 Spring MCP 服务(由 Amplicode IntelliJ 插件提供)配合使用。开始任何操作前,请检查工具列表中是否有 Spring MCP 工具——这些工具会显示在 amplicode MCP 服务下(例如 get_project_summary、list_module_dependencies、get_entity_details);会将 MCP 工具扁平化到工具列表中的运行环境,会在相同名称前使用 mcp__amplicode__ 前缀。

  • 如果至少有一个 Amplicode 工具可用——MCP 已连接。继续使用以下技能。
  • 如果没有可用工具——停止并调用 amplicode-install 技能(随 Spring Agent Toolkit 一同提供)。该技能会安装 Amplicode 插件,并引导用户点击欢迎屏幕上的 «Настроить Spring Agent» 按钮并重启 MCP 客户端。完成后,MCP 工具即可使用——继续此技能。
  • 如果技能列表中未注册 amplicode-install,请用用户的语言告知用户:“此技能需要 Amplicode IntelliJ 插件及其 MCP 服务。请从 https://amplicode.ru/marketplace 将其安装到 IntelliJ IDEA Ultimate/Community 或 GigaIDE,打开任意项目,点击 Amplicode 欢迎屏幕上的 «Настроить Spring Agent》,然后重启 MCP 客户端。”

CRUD REST Controller

为实体生成一个 @RestController 类,其中包含标准 CRUD 端点,并使用 Spring Data 仓库,支持可选的 DTO 映射、分页、筛选和补丁操作。


关键:只能依据 examples/ 文件中的示例编写代码。如果没有匹配的示例——停止并询问用户。 关键:对于有固定选项的问题,优先使用 AskUserQuestion > 其类似工具 > 纯文本列表。只有在没有交互工具可用时,才将纯编号文本列表作为最后选择。 关键:运行步骤 1 前,先阅读对话上下文。步骤 2–4 中一半的问题可能已由用户的提示和此前的对话回答。重复询问已说明的信息,是此技能让人觉得迟缓的首要原因。


默认值

以下选项按主题分组。language 和 bootVersion 会自动检测;其他所有选项均按照决策原则(根据上下文推断 → 确认 → 询问)确定。

第 1 组 — 实体与仓库
选项默认值说明
entity--要为哪个实体创建 Controller
repository该实体对应的第一个现有仓库要使用哪个仓库
第 2 组 — DTO 模式
选项默认值说明
DTO modeDTO(推荐)如果该实体没有现成的 DTO,则委托给 dto-creator;用户也可以选择不使用 DTO,直接使用实体
第 3 组 — Controller 命名与路径
选项默认值说明
controllerName{EntityName}Controller根据项目的命名约定提供建议
controllerPackage与现有 Controller 相同,或使用 mainPackage从项目中自动检测
basePath/rest持久基础路径
resourcePath/{pluralizedEntityName}根据实体名称自动生成
第 4 组 — 分页与筛选
选项默认值说明
paginationtrue为 GET_LIST 启用分页
paginationTypePAGEPAGE 或 WINDOW(WINDOW 需要选择筛选;可避免计数查询开销)
filter无用于 GET_LIST 的 JPA Specification 筛选
自动检测(无需提问)
选项来源
patchStrategyObjectMapper
languageget_project_summary
bootVersionget_project_summary

智能默认值: 如果用户说“使用默认值”“全部使用默认值”“默认设置”或类似内容,则跳过所有“是否始终询问?”为“否”的问题。只询问必答问题。

智能识别回答: 当用户直接提供值,而不是从编号列表中选择时,直接接受该值。例如:

  • 问题“哪个实体?”--> 用户回答“Product” --> 这就是实体,不要再次询问
  • 问题“哪个 Repository?”--> 用户回答“ProductRepository” --> 这就是选择
  • 如果用户在一条消息中提供多个答案 --> 全部接受,跳过已回答的问题
  • 绝不要询问用户已经回答过的问题(包括隐含回答)

批量提问: 当必须提出多个问题时(即无法根据决策原则第 1–2 条得出答案),如果这些问题:

  • 属于同一逻辑部分
  • 不依赖彼此的答案

则将它们合并到一次 AskUserQuestion 调用中(每次最多 4 个问题)。

规则:

  • 每次 AskUserQuestion 调用最多 3–4 个问题
  • 在推荐选项旁标注“(推荐)”,并将其放在首位
  • 绝不要将不同决策分支的问题放在一起
  • 主要分支问题(实体选择)始终单独询问
  • 选择问题时优先使用 AskUserQuestion;只有在无法使用该工具时,才改用纯文本列表

决策原则——先看上下文,再提问

在向用户提出任何问题之前,先尝试从已收集的上下文中推导答案:项目摘要、模块依赖项、实体详情、包中的现有文件、此前的对话轮次,以及用户最初的提示。只有当上下文无法得出明确默认值,或选择确实取决于用户个人偏好(例如选择哪个实体、哪个 Repository)时,才提问。

决策优先级:

  1. 上下文明确无误 → 静默决定,不要提问。 示例:从 get_project_summary 获取语言和 JDK;实体只有一个 Repository 时选择该 Repository;根据现有控制器确定控制器包;根据现有端点确定 basePath;根据 list_module_dependencies 确定 Jackson 版本;项目已有统一使用的分页类型时采用该类型。

  2. 上下文有明显倾向 → 用一行说明决定和其他选项,让用户选择修改或保持默认。 格式:

    Will create `ProductController` at `/rest/products` with Page pagination, no DTO.
    Alternatives: use DTO, Window pagination, custom paths. OK?
    

    用户可以回答“好”/“是”/不回复,即表示接受;也可以指出其他选项,即切换选项。这与编号问题格式不同——这里只需一行确认。

  3. 上下文无法得出明确默认值 → 使用 AskUserQuestion(首选)或类似方式提问,并将推荐选项放在首位。 如果可以使用 AskUserQuestion,请使用该工具,并将推荐选项标注为“(推荐)”后置于首位。如果没有可用的交互式选择工具,则改用纯文本列表。 绝不要逐步提问(“哪个实体?”→ 用户选择 → “哪个 Repository?”→ …),而应在一次批量调用中提出所有问题。

  4. 关键输入的上下文完全为空 → 直接提问。 适用于:未提及要选择哪个实体,以及用户本身的意图。

如何提问 — 优先使用 AskUserQuestion

必须提问时,优先使用 AskUserQuestion 工具(或其同类工具),而不是在回复正文中编写编号列表。只有在没有可用的交互式选项工具时,才改用纯文本。

此技能中调用 AskUserQuestion 的规则:

  • 每次调用最多可包含 4 个彼此独立的问题(工具会将它们一并呈现)。可用此方式在一次往返中批量处理相关决策。
  • 每个问题有 2–4 个选项。工具会自动添加一个供自由输入的“其他”选项,切勿手动添加。
  • 将推荐选项放在首位,并在标签后附加 (Recommended)。
  • header 是一个 12 字符的标签(例如“Entity”、“DTO mode”、“Paths”)。
  • 每个选项都应有一段说明,解释该选项的含义。

以下情况不适合使用 AskUserQuestion:

  • 需要自由输入,且没有可枚举的选项(例如任意类名、任意路径)——用纯文本提问。
  • 原则 2 中的“单行确认”形式——这是一个有明显是/否答案的普通问题,不是枚举选项。

下面步骤 2–4 中由屏幕内容驱动的问题列表,是针对情况 4 的备用方案,不是要从头到尾依次执行的脚本。如果根据原则 1–3 已经确定某个问题的答案,跳过该问题。


步骤 0 —— 首先查看对话上下文(必需,不调用工具)

在调用任何 MCP 工具、提出任何问题之前,重新阅读用户的提示和本次对话之前的内容,提取其中已经说明的信息。这一步无需耗费任何成本,还能避免此技能最常见的错误——询问用户已经提供的信息。

在脑中列出输入项,并逐项勾选用户已经明确或隐含提供的内容:

输入项在提示/上下文中查找
实体类名(Product、Order、Vet);“针对 X”;IDE 中打开的文件;文件路径;本次对话中最近讨论过的实体
仓库“使用 ProductRepository”、“配合 OrderRepo”;或可推断的信息——如果该实体只有一个仓库
DTO 模式“使用 DTO”、“不使用 DTO”、“直接使用实体”、“映射到 ProductDto”
控制器名称“命名为 ProductResource”、“类名为 FooController”
路径“使用 /api/products”、“基础路径 /rest”、“资源路径 /items”
分页“使用分页”、“不分页”、“使用 Window”、“使用 Page”
筛选器“使用筛选器”、“不使用筛选器”、“使用 JPA Specification”
方法“所有 CRUD 操作”、“仅读取”、“只读”、“不包含删除”、“GET + CREATE”、“完整 CRUD”
智能默认值“使用默认值”、“全部使用默认值”、“默认设置”、“照常”
先前已知的项目信息编程语言、JDK、依赖项——如果本次对话之前已讨论过,则视为已知;不要重新获取

对于每个已明确说明或有充分依据可推断的输入: 将其标记为已确定,并跳过步骤 2–4 中相应的问题。用户写了“为 Product 创建 CRUD 控制器”时,不要问“实体是什么?”——答案就是 Product。如果该实体只有一个仓库,不要问“使用哪个仓库?”

对于每个尚未回答的输入:遵循上文的决策原则——先尝试根据项目上下文推断(步骤 1),然后再提问。

步骤 0 是在脑中完成的,不是工具调用。不要向用户宣布此步骤。不要写“步骤 0 已完成”。开始步骤 1 之前,只需先在脑中梳理用户已经说明的内容。


步骤 1 —— 收集最少的项目上下文(自动执行,不提问)

只调用结果会被后续步骤实际使用的 MCP 工具。不要“以防万一”提前获取数据——这里的每个变量都必须有明确的后续用途。

工具变量用途
get_project_summarylanguage、bootMajor、moduleName、buildFile、mainPackagelanguage → 选择参考文件(java 或 kotlin);bootMajor → jakarta 或 javax、Jackson 版本;moduleName → 消除多模块歧义;buildFile → 步骤 6 中注入依赖;mainPackage → 控制器包名回退值
list_module_dependencies(moduleName)presentDeps用于推导下方标志——SpringDoc/Validation/Jackson 功能门控、步骤 6 依赖检查
list_project_endpointsendpoints步骤 4 中检测路径冲突,以及检测现有 basePath/命名约定

步骤 1 到此为止。不要获取:

  • list_all_domain_entities —— 仅当用户未在提示词中指定实体时才需要。延后到步骤 2,作为惰性回退。
  • list_entity_repositories —— 需要先知道实体,这将在步骤 2 中确定。延后到步骤 3,作为惰性回退。
  • get_entity_details —— 需要先知道实体。延后到步骤 2。
  • list_entity_dtos / list_entity_mappers —— 需要先知道实体以及 DTO 决策。延后到步骤 4。

调用 get_project_summary 后,确定:

  • language:Java 或 Kotlin
  • bootMajor:2、3 或 4(用于 jakarta 或 javax、Jackson 版本)
  • 检查 presentDeps 中是否包含 org.springdoc:springdoc-openapi --> hasSpringDoc
  • 检查 presentDeps 中是否包含 org.hibernate.validator:hibernate-validator 或 org.springframework.boot:spring-boot-starter-validation --> hasValidation
  • **Jackson 版本检测:**检查 presentDeps 中是否包含 tools.jackson:jackson-databind 或 tools.jackson:jackson-core --> jacksonMajor = 3。否则,如果包含 com.fasterxml.jackson:jackson-databind --> jacksonMajor = 2。Spring Boot 4.x 使用 Jackson 3.x(tools.jackson 包),Spring Boot 2.x/3.x 使用 Jackson 2.x(com.fasterxml.jackson 包)。
    • 如果 jacksonMajor = 3:JsonNodeFqn = tools.jackson.databind.JsonNode,ObjectMapperFqn = tools.jackson.databind.ObjectMapper
    • 如果 jacksonMajor = 2:JsonNodeFqn = com.fasterxml.jackson.databind.JsonNode,ObjectMapperFqn = com.fasterxml.jackson.databind.ObjectMapper
  • PagedModel 检测:PagedModel(org.springframework.data.web.PagedModel)在 Spring Data 3.2+ 中可用。如果 bootMajor >= 3(Spring Boot 3.2+)或 bootMajor = 4,则对带 Page 分页的 GET_LIST 使用 PagedModel 包装器。否则直接返回 Page<Entity>。

如果是多模块项目(get_project_summary 中包含多个模块): 询问要使用哪个模块。然后使用该模块重新调用特定模块的 MCP 工具。


步骤 2 -- 选择实体

到步骤 0 时,如果用户提到了实体,你应该已经知道该实体。 最常见的情况:用户写了“为 Product 创建 CRUD 控制器” → 实体是 Product,跳过提问,直接执行下面的获取操作。

延迟回退 — 仅当实体未知时: 调用 list_all_domain_entities(moduleName) → entities,然后通过 AskUserQuestion 提问(选项 = 列表中的实体名称,最多 4 个;如果 实体超过 4 个,根据上下文选择最可能的 4 个候选项,并 补充说明用户可以通过“Other”输入其他名称)。

这是唯一应该调用 list_all_domain_entities 的地方。如果 用户在提示词中指定了实体,不要调用它。

确定实体 FQN 后,调用 get_entity_details(entityFqn) 获取:

  • IdType -- 实体 ID 字段类型(例如 java.lang.Long、java.util.UUID)
  • entityVar -- 首字母小写的实体名称(例如 product)
  • entityVarPlural -- 首字母小写的复数实体名称(例如 products)
  • EntityName -- 类的简单名称(例如 Product)
  • EntityNamePlural -- 简单名称的复数形式(例如 Products)
  • 实体是否具有验证注解 --> entityHasValidation

步骤 3 -- 选择仓库

到步骤 0 时,如果用户提到了仓库,你可能已经知道该仓库。

调用 list_entity_repositories(entityFqn) → repos。然后应用 决策原则:

  • 如果恰好存在一个仓库 → 静默选择它(原则 1)。
  • 如果用户指定了某个仓库 → 直接使用,跳过提问。
  • 如果存在多个仓库 → 通过 AskUserQuestion 提问,选项来自 repos。
  • 如果不存在仓库 → 告知用户,并建议手动创建或使用单独的技能。

选择后:

  • repoFieldName -- 首字母小写的仓库类名称(例如 productRepository)
  • RepoFqn -- 仓库类的 FQN

步骤 4 -- DTO 和自定义问题

到步骤 0 时,如果用户提到了 DTO 模式(例如“使用 DTO”“不使用 DTO”“直接使用实体”“映射到 ProductDto”),你可能已经知道该模式。 如果已知,跳过提问并继续。

如果未知,通过 AskUserQuestion 提问:

问题标题选项(第一个 = 推荐)
使用 DTO 进行映射?DTO 模式是,使用 DTO(推荐):选择现有 DTO 或通过 dto-creator 创建 / 否,直接使用实体
如果选择 DTO:

调用 list_entity_dtos(entityFqn) 和 list_entity_mappers(entityFqn)。

如果找到现有 DTO 和映射器: 请用户选择。提取:

  • DtoFqn -- DTO 类的 FQN
  • dtoVar -- 首字母小写的 DTO 名称
  • mapperFieldName -- 首字母小写的映射器类名称
  • toDtoMethodName -- 映射器方法,实体 --> DTO(例如 toDto)
  • toEntityMethodName -- 映射器方法,DTO --> 实体(例如 toEntity)
  • updateMethodName -- 用于更新的映射器方法(例如 updateWithNullValues)

警告:CREATE 和 PATCH 操作要求映射器具有 toEntity 和 updateWithNull 方法。

如果该实体不存在 DTO: 委托 dto-creator 创建 一个。dto-creator 技能会处理 DTO 生成,并会 自动委托 mapper-creator 创建映射器(因为 DTO 用于 REST 控制器 —— 转换不可避免)。二者创建完成后,返回此处并继续步骤 4 的路径设置。

如果 DTO 存在但没有映射器: 委托 mapper-creator 创建 一个。映射器创建完成后,返回此处并继续。

路径、分页与筛选设置

应用 决策原则。这些设置几乎总是能根据上下文推导出合适的默认值——除非用户明确要求自定义,否则使用原则 2(单行确认):

Will create `{EntityName}Controller` in `{controllerPackage}` at `{basePath}/{entityVarPlural}`, Page pagination, no filter. OK?

用户可以回答“好”/“是”或保持沉默 → 接受所有默认值;也可以覆盖特定值 → 仅应用这些覆盖项。

只有在用户明确要求精细控制(“自定义路径”“配置分页”),或上下文无法得出明确的默认值时,才改为逐项提问。

如果用户选择了筛选器:请用户选择现有的筛选器类。提取 FilterFqn 和 toSpecificationMethodName。如果仓库没有扩展 JpaSpecificationExecutor,则添加它(WA-repo-enhance)。

方法选择

到步骤 0 时,你可能已经知道用户需要哪些方法(例如“只读”“仅 GET 和 CREATE”“完整 CRUD”)。如果已知,则跳过提问。

如果未知,则通过 AskUserQuestion 提问:

问题标题选项(第一项为推荐选项)
要生成哪些 CRUD 方法?方法完整 CRUD(推荐):GET_LIST、GET_ONE、GET_MANY、CREATE、PATCH、PATCH_MANY、DELETE、DELETE_MANY / 标准 CRUD:GET_LIST、GET_ONE、CREATE、PATCH、DELETE / 只读:GET_LIST、GET_ONE / 自定义:逐项选择方法

将所选方法集存储为 selectedMethods。步骤 5.3 仅生成这些方法,跳过其余方法。


步骤 5 -- 生成代码

5.1 创建控制器类(WA1)

根据 language 读取 examples/_skeletons/java.md 或 examples/_skeletons/kotlin.md。

应用变量替换:

  • {packageName} --> controllerPackage
  • {className} --> controllerName
  • {requestPath} --> basePath + resourcePath

使用 Write 工具创建 src/main/{java,kotlin}/{package-path}/{controllerName}.{java,kt}。

5.2 添加 Bean 注入(WA2)

读取 examples/_beans/injection/java.md 或 kotlin.md。

为仓库添加构造函数参数。如果使用 DTO 和 Mapper:还要注入 Mapper Bean。 注入 ${ObjectMapperFqn} 字段(在步骤 1 中解析:Jackson 3.x 使用 tools.jackson.databind.ObjectMapper,Jackson 2.x 使用 com.fasterxml.jackson.databind.ObjectMapper)。

使用 Edit 工具修改控制器类。

5.3 添加 CRUD 方法(WA3-WA11)

对于 selectedMethods 中的每个方法(来自步骤 4 的方法选择):

  1. 确定示例文件路径: examples/_methods/{method-name}/{language}.md

  2. 读取示例文件

  3. 根据以下条件选择正确的代码变体:

    • DTO 模式(不使用 DTO 或使用 DTO)
    • 对于 GET_LIST:分页(PAGE/WINDOW/无)和筛选(有/无)
    • 对于 PATCH/PATCH_MANY:ObjectMapper 或 ObjectPatcher,以及 DTO 或不使用 DTO(4 种组合)
    • 对于 CREATE:带或不带 @Valid
  4. 应用变量替换(仅限 Variables 部分中声明的变量)

  5. FQN 处理(至关重要): 示例中包含 FQN(例如 org.springframework.web.bind.annotation.GetMapping、 org.springframework.data.domain.Pageable、实体/DTO/仓库 FQN)。编写最终文件时,必须:

    1. 将正文中的每个 FQN 替换为其短名称
    2. 收集所有缩短的 FQN,并添加对应的 import 行 紧跟在 package 语句之后,按顺序排列,不得重复
    3. 与控制器属于同一包的类不得导入
    4. java.lang 中的类型不得导入
    5. Kotlin:遵循相同规则——在正文中缩短名称,并在顶部添加 import 行
  6. 使用 Edit 工具将方法插入控制器类的主体中

5.4 如有需要,添加 JpaSpecificationExecutor(WA-repo-enhance)

如果已选择筛选器,且仓库尚未扩展 JpaSpecificationExecutor:

读取 examples/_beans/repo-enhance/java.md 或 kotlin.md。 使用 Edit 工具,将 org.springframework.data.jpa.repository.JpaSpecificationExecutor<{EntityFqn}> 添加到仓库的 extends 列表中。


步骤 6 —— 依赖项和属性(自动)

  1. 读取 examples/_dependencies/dependencies.md
  2. 对于每个不在 presentDeps 中的工件:
    • 使用步骤 1 中的 buildFile
    • 编辑构建文件以添加依赖项
  3. 调用 refresh_build_system_model
  4. 不为此技能编写任何属性(控制器没有 application.properties 条目)
  5. 报告:“已创建控制器 {controllerName},包含 {EntityName} 的 CRUD 端点。已添加依赖项:[列表]。”

防止幻觉检查清单

编写任何代码之前,请确认:

  • 代码来自某个 examples/ 文件(注明具体文件)
  • 只替换了已声明的变量
  • 没有“凭知识”添加任何框架 API 调用
  • 导入列表涵盖正文中所有缩写的 FQN(没有遗漏导入,也没有多余导入)
  • 方法签名与示例完全一致
  • 没有添加注释或便捷方法
  • 正文中缩写了示例中的 FQN,且在 package 后添加了对应的 import 行(IDE 不会替你完成这一步)
  • 仅当 hasSpringDoc = true 时才添加 @ParameterObject 注解
  • 仅当 hasValidation = true 且实体具有验证注解时才添加 @Valid 注解
  • PATCH 和 PATCH_MANY 方法根据项目依赖使用 ObjectMapper(后备方案)或 ObjectPatcher
  • PATCH_MANY 中的 getId() 与实体实际的 ID 访问器一致
  • Jackson FQN 在 Jackson 3.x(Spring Boot 4.x)中使用 tools.jackson.databind.*,在 Jackson 2.x(Spring Boot 2.x/3.x)中使用 com.fasterxml.jackson.databind.*。绝不能将其中一种写死——始终从步骤 1 解析 ${JsonNodeFqn} 和 ${ObjectMapperFqn}。
  • 使用 Page 分页的 GET_LIST 应采用 PagedModel<Entity> 包装器(Spring Data 3.2+ / Boot 3.2+/4.x),或直接返回 Page<Entity>(较旧版本)。选择正确的示例变体。

评论

支持 Markdown