关于 spring-boot-engineer
用于构建 Spring Boot 服务的开发技能,覆盖架构、分层实现、安全、测试与部署检查。重点包括构造器注入、API 输入校验,以及通过 Actuator 验证健康状态。
主要功能
- 01分层服务架构指导
- 02REST API 与输入校验
- 03Spring Security 和 OAuth2 指导
- 04单元、集成与切片测试
- 05Actuator 健康与可观测性检查
适用场景
- 01搭建 Spring Boot REST 功能
- 02为端点添加校验与安全机制
- 03测试服务层和 Web 层
- 04部署前检查应用健康状态
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ farmage/ opencode-skills --skill spring-boot-engineer安装后在 Claude Code 中输入/spring-boot-engineer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/cloud.mddata.mdsecurity.mdtesting.mdweb.md详细介绍
Spring Boot 工程师
核心工作流
- 分析需求 — 明确服务边界、API、数据模型和安全需求
- 设计架构 — 规划微服务、数据访问、云集成和安全;编码前确认设计
- 实现 — 使用构造器注入和分层架构创建服务(参见下方的快速入门)
- 保障安全 — 添加 Spring Security、OAuth2、方法级安全和 CORS 配置;确认安全规则编译通过且测试通过。如果编译或测试失败:检查错误输出,修复失败的规则或配置,然后重新运行再继续
- 测试 — 编写单元测试、集成测试和切片测试;运行
./mvnw test(或./gradlew test),并确认全部通过后再继续。如果测试失败:检查堆栈跟踪,定位失败的断言或组件,修复问题,然后重新运行完整测试套件 - 部署 — 通过 Actuator 配置健康检查和可观测性;验证
/actuator/health返回UP。如果健康状态为DOWN:检查响应中的components详情,解决故障组件(例如数据源、消息代理),然后重新验证
参考指南
根据上下文加载详细指南:
| 主题 | 参考文档 | 加载时机 |
|---|---|---|
| Web 层 | references/web.md | 控制器、REST API、验证、异常处理 |
| 数据访问 | references/data.md | Spring Data JPA、存储库、事务、投影 |
| 安全 | references/security.md | Spring Security 6、OAuth2、JWT、方法级安全 |
| 云原生 | references/cloud.md | Spring 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