mcpField
S
spring-boot-engineer

spring-boot-engineer

github.com/farmage开发224283 次安装5 周前更新
代码仓库

关于 spring-boot-engineer

用于构建 Spring Boot 服务的开发技能,覆盖架构、分层实现、安全、测试与部署检查。重点包括构造器注入、API 输入校验,以及通过 Actuator 验证健康状态。

主要功能

  1. 01分层服务架构指导
  2. 02REST API 与输入校验
  3. 03Spring Security 和 OAuth2 指导
  4. 04单元、集成与切片测试
  5. 05Actuator 健康与可观测性检查

适用场景

  1. 01搭建 Spring Boot REST 功能
  2. 02为端点添加校验与安全机制
  3. 03测试服务层和 Web 层
  4. 04部署前检查应用健康状态

安装

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

$npx skills add https://github.com/farmage/opencode-skills --skill spring-boot-engineer

安装后在 Claude Code 中输入/spring-boot-engineer确认已加载。

包含的文件

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

references/
cloud.md
data.md
security.md
testing.md
web.md

详细介绍

Spring Boot 工程师

核心工作流

  1. 分析需求 — 明确服务边界、API、数据模型和安全需求
  2. 设计架构 — 规划微服务、数据访问、云集成和安全;编码前确认设计
  3. 实现 — 使用构造器注入和分层架构创建服务(参见下方的快速入门)
  4. 保障安全 — 添加 Spring Security、OAuth2、方法级安全和 CORS 配置;确认安全规则编译通过且测试通过。如果编译或测试失败:检查错误输出,修复失败的规则或配置,然后重新运行再继续
  5. 测试 — 编写单元测试、集成测试和切片测试;运行 ./mvnw test(或 ./gradlew test),并确认全部通过后再继续。如果测试失败:检查堆栈跟踪,定位失败的断言或组件,修复问题,然后重新运行完整测试套件
  6. 部署 — 通过 Actuator 配置健康检查和可观测性;验证 /actuator/health 返回 UP。如果健康状态为 DOWN:检查响应中的 components 详情,解决故障组件(例如数据源、消息代理),然后重新验证

参考指南

根据上下文加载详细指南:

主题参考文档加载时机
Web 层references/web.md控制器、REST API、验证、异常处理
数据访问references/data.mdSpring Data JPA、存储库、事务、投影
安全references/security.mdSpring Security 6、OAuth2、JWT、方法级安全
云原生references/cloud.mdSpring Cloud、Config、Discovery、Gateway、弹性
测试references/testing.md@SpringBootTest、MockMvc、Testcontainers、测试切片

快速入门 — 最小可用结构

标准的 Spring Boot 功能由以下层组成。将这些示例用作复制粘贴的起点。

实体
@Entity
@Table(name = "products")
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @NotBlank
    private String name;

    @DecimalMin("0.0")
    private BigDecimal price;

    // getters / setters or use @Data (Lombok)
}
存储库
public interface ProductRepository extends JpaRepository<Product, Long> {
    List<Product> findByNameContainingIgnoreCase(String name);
}
服务(构造器注入)
@Service
public class ProductService {
    private final ProductRepository repo;

    public ProductService(ProductRepository repo) { // constructor injection — no @Autowired
        this.repo = repo;
    }

    @Transactional(readOnly = true)
    public List<Product> search(String name) {
        return repo.findByNameContainingIgnoreCase(name);
    }

    @Transactional
    public Product create(ProductRequest request) {
        var product = new Product();
        product.setName(request.name());
        product.setPrice(request.price());
        return repo.save(product);
    }
}
REST 控制器
@RestController
@RequestMapping("/api/v1/products")
@Validated
public class ProductController {
    private final ProductService service;

    public ProductController(ProductService service) {
        this.service = service;
    }

    @GetMapping
    public List<Product> search(@RequestParam(defaultValue = "") String name) {
        return service.search(name);
    }

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public Product create(@Valid @RequestBody ProductRequest request) {
        return service.create(request);
    }
}
DTO(record)
public record ProductRequest(
    @NotBlank String name,
    @DecimalMin("0.0") BigDecimal price
) {}
全局异常处理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Map<String, String> handleValidation(MethodArgumentNotValidException ex) {
        return ex.getBindingResult().getFieldErrors().stream()
            .collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
    }

    @ExceptionHandler(EntityNotFoundException.class)
    @ResponseStatus(HttpStatus.NOT_FOUND)
    public Map<String, String> handleNotFound(EntityNotFoundException ex) {
        return Map.of("error", ex.getMessage());
    }
}
测试切片
@WebMvcTest(ProductController.class)
class ProductControllerTest {
    @Autowired MockMvc mockMvc;
    @MockBean ProductService service;

    @Test
    void createProduct_validRequest_returns201() throws Exception {
        var product = new Product(); product.setName("Widget"); product.setPrice(BigDecimal.TEN);
        when(service.create(any())).thenReturn(product);

        mockMvc.perform(post("/api/v1/products")
                .contentType(MediaType.APPLICATION_JSON)
                .content("""{"name":"Widget","price":10.0}"""))
            .andExpect(status().isCreated())
            .andExpect(jsonPath("$.name").value("Widget"));
    }
}

约束

必须做到
规则正确模式
构造器注入public MyService(Dep dep) { this.dep = dep; }
验证 API 输入每个会修改数据的端点都使用 @Valid @RequestBody MyRequest req
类型安全的配置将 @ConfigurationProperties(prefix = "app") 绑定到 record/类
使用恰当的构造型注解业务逻辑使用 @Service,数据访问使用 @Repository,HTTP 使用 @RestController
事务范围多步写操作使用 @Transactional;读操作使用 @Transactional(readOnly = true)
隐藏内部细节在 @RestControllerAdvice 中捕获领域异常;返回问题详情,而非堆栈跟踪
将密钥移出代码使用环境变量或 Spring Cloud Config,绝不要放在 application.properties 中
不得这样做
  • 使用字段注入(在字段上添加 @Autowired)
  • 跳过 API 端点的输入验证
  • 在适用 @Service/@Repository/@Controller 时使用 @Component
  • 混用阻塞式和响应式代码(例如,在 WebFlux 调用链中调用 .block())
  • 在 application.properties/application.yml 中存储密钥或凭据
  • 对 URL、凭据或特定环境的值进行硬编码
  • 使用已弃用的 Spring Boot 2.x 模式(例如 WebSecurityConfigurerAdapter)

文档

评论

支持 Markdown