springboot-patterns
Provides standard architectures and patterns for Java Spring Boot development.
Install
mkdir -p .claude/skills/springboot-patterns && curl -L -o skill.zip "https://agentskills.codes/api/skills/download/710" && unzip -o skill.zip -d .claude/skills/springboot-patterns && rm skill.zipInstalls to .claude/skills/springboot-patterns
Activation
This is the description your AI agent reads to decide when to run this skill — the better it matches your request, the more reliably it fires.
Spring Boot架构模式、REST API设计、分层服务、数据访问、缓存、异步处理和日志记录。用于Java Spring Boot后端工作。Key capabilities
- →Design REST API controllers with validation
- →Implement repository layers using Spring Data JPA
- →Configure caching with @EnableCaching
- →Set up asynchronous processing with @EnableAsync
- →Implement global exception handling
- →Configure request logging filters
How it works
The skill provides architectural patterns and code templates for Spring Boot applications, focusing on layered service structures, repository patterns, and configuration for caching and async tasks.
Inputs & outputs
When to use springboot-patterns
- →Build a Spring Boot REST controller
- →Implement a repository layer
- →Set up Spring Data JPA for persistence
About this skill
Spring Boot 开发模式
用于可扩展、生产级服务的 Spring Boot 架构和 API 模式。
何时激活
- 使用 Spring MVC 或 WebFlux 构建 REST API
- 构建控制器 → 服务 → 仓库层结构
- 配置 Spring Data JPA、缓存或异步处理
- 添加验证、异常处理或分页
- 为开发/预发布/生产环境设置配置文件
- 使用 Spring Events 或 Kafka 实现事件驱动模式
REST API 结构
@RestController
@RequestMapping("/api/markets")
@Validated
class MarketController {
private final MarketService marketService;
MarketController(MarketService marketService) {
this.marketService = marketService;
}
@GetMapping
ResponseEntity<Page<MarketResponse>> list(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size) {
Page<Market> markets = marketService.list(PageRequest.of(page, size));
return ResponseEntity.ok(markets.map(MarketResponse::from));
}
@PostMapping
ResponseEntity<MarketResponse> create(@Valid @RequestBody CreateMarketRequest request) {
Market market = marketService.create(request);
return ResponseEntity.status(HttpStatus.CREATED).body(MarketResponse.from(market));
}
}
仓库模式 (Spring Data JPA)
public interface MarketRepository extends JpaRepository<MarketEntity, Long> {
@Query("select m from MarketEntity m where m.status = :status order by m.volume desc")
List<MarketEntity> findActive(@Param("status") MarketStatus status, Pageable pageable);
}
带事务的服务层
@Service
public class MarketService {
private final MarketRepository repo;
public MarketService(MarketRepository repo) {
this.repo = repo;
}
@Transactional
public Market create(CreateMarketRequest request) {
MarketEntity entity = MarketEntity.from(request);
MarketEntity saved = repo.save(entity);
return Market.from(saved);
}
}
DTO 和验证
public record CreateMarketRequest(
@NotBlank @Size(max = 200) String name,
@NotBlank @Size(max = 2000) String description,
@NotNull @FutureOrPresent Instant endDate,
@NotEmpty List<@NotBlank String> categories) {}
public record MarketResponse(Long id, String name, MarketStatus status) {
static MarketResponse from(Market market) {
return new MarketResponse(market.id(), market.name(), market.status());
}
}
异常处理
@ControllerAdvice
class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
ResponseEntity<ApiError> handleValidation(MethodArgumentNotValidException ex) {
String message = ex.getBindingResult().getFieldErrors().stream()
.map(e -> e.getField() + ": " + e.getDefaultMessage())
.collect(Collectors.joining(", "));
return ResponseEntity.badRequest().body(ApiError.validation(message));
}
@ExceptionHandler(AccessDeniedException.class)
ResponseEntity<ApiError> handleAccessDenied() {
return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ApiError.of("Forbidden"));
}
@ExceptionHandler(Exception.class)
ResponseEntity<ApiError> handleGeneric(Exception ex) {
// Log unexpected errors with stack traces
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ApiError.of("Internal server error"));
}
}
缓存
需要在配置类上使用 @EnableCaching。
@Service
public class MarketCacheService {
private final MarketRepository repo;
public MarketCacheService(MarketRepository repo) {
this.repo = repo;
}
@Cacheable(value = "market", key = "#id")
public Market getById(Long id) {
return repo.findById(id)
.map(Market::from)
.orElseThrow(() -> new EntityNotFoundException("Market not found"));
}
@CacheEvict(value = "market", key = "#id")
public void evict(Long id) {}
}
异步处理
需要在配置类上使用 @EnableAsync。
@Service
public class NotificationService {
@Async
public CompletableFuture<Void> sendAsync(Notification notification) {
// send email/SMS
return CompletableFuture.completedFuture(null);
}
}
日志记录 (SLF4J)
@Service
public class ReportService {
private static final Logger log = LoggerFactory.getLogger(ReportService.class);
public Report generate(Long marketId) {
log.info("generate_report marketId={}", marketId);
try {
// logic
} catch (Exception ex) {
log.error("generate_report_failed marketId={}", marketId, ex);
throw ex;
}
return new Report();
}
}
中间件 / 过滤器
@Component
public class RequestLoggingFilter extends OncePerRequestFilter {
private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
long start = System.currentTimeMillis();
try {
filterChain.doFilter(request, response);
} finally {
long duration = System.currentTimeMillis() - start;
log.info("req method={} uri={} status={} durationMs={}",
request.getMethod(), request.getRequestURI(), response.getStatus(), duration);
}
}
}
分页和排序
PageRequest page = PageRequest.of(pageNumber, pageSize, Sort.by("createdAt").descending());
Page<Market> results = marketService.list(page);
容错的外部调用
public <T> T withRetry(Supplier<T> supplier, int maxRetries) {
int attempts = 0;
while (true) {
try {
return supplier.get();
} catch (Exception ex) {
attempts++;
if (attempts >= maxRetries) {
throw ex;
}
try {
Thread.sleep((long) Math.pow(2, attempts) * 100L);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw ex;
}
}
}
}
速率限制 (过滤器 + Bucket4j)
安全须知:默认情况下 X-Forwarded-For 头是不可信的,因为客户端可以伪造它。
仅在以下情况下使用转发头:
- 您的应用程序位于可信的反向代理(nginx、AWS ALB 等)之后
- 您已将
ForwardedHeaderFilter注册为 bean - 您已在应用属性中配置了
server.forward-headers-strategy=NATIVE或FRAMEWORK - 您的代理配置为覆盖(而非追加)
X-Forwarded-For头
当 ForwardedHeaderFilter 被正确配置时,request.getRemoteAddr() 将自动从转发的头中返回正确的客户端 IP。
没有此配置时,请直接使用 request.getRemoteAddr()——它返回的是直接连接的 IP,这是唯一可信的值。
@Component
public class RateLimitFilter extends OncePerRequestFilter {
private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();
/*
* SECURITY: This filter uses request.getRemoteAddr() to identify clients for rate limiting.
*
* If your application is behind a reverse proxy (nginx, AWS ALB, etc.), you MUST configure
* Spring to handle forwarded headers properly for accurate client IP detection:
*
* 1. Set server.forward-headers-strategy=NATIVE (for cloud platforms) or FRAMEWORK in
* application.properties/yaml
* 2. If using FRAMEWORK strategy, register ForwardedHeaderFilter:
*
* @Bean
* ForwardedHeaderFilter forwardedHeaderFilter() {
* return new ForwardedHeaderFilter();
* }
*
* 3. Ensure your proxy overwrites (not appends) the X-Forwarded-For header to prevent spoofing
* 4. Configure server.tomcat.remoteip.trusted-proxies or equivalent for your container
*
* Without this configuration, request.getRemoteAddr() returns the proxy IP, not the client IP.
* Do NOT read X-Forwarded-For directly—it is trivially spoofable without trusted proxy handling.
*/
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
// Use getRemoteAddr() which returns the correct client IP when ForwardedHeaderFilter
// is configured, or the direct connection IP otherwise. Never trust X-Forwarded-For
// headers directly without proper proxy configuration.
String clientIp = request.getRemoteAddr();
Bucket bucket = buckets.computeIfAbsent(clientIp,
k -> Bucket.builder()
.addLimit(Bandwidth.classic(100, Refill.greedy(100, Duration.ofMinutes(1))))
.build());
if (bucket.tryConsume(1)) {
filterChain.doFilter(request, response);
} else {
response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
}
}
}
后台作业
使用 Spring 的 @Scheduled 或与队列(如 Kafka、SQS、RabbitMQ)集成。保持处理程序是幂等的和可观察的。
可观测性
- 通过 Logback 编码器进行结构化日志记录 (JSON)
- 指标:Micrometer + Prometheus/OTel
- 追踪:带有 OpenTelemetry 或 Brave 后端的 Micrometer Tracing
生产环境默认设置
- 优先使用构造函数注入,避免字段注入
- 启用
spring.mvc.problemdetails.enabled=true以获得 RFC 7807 错误 (Spring Boot 3+) - 根据工作负载配置 HikariCP 连接池大小,设置超时
- 对查询使用
@Transactional(readOnly = true) - 在适当的地方通过
@NonNull和Optional强制执行空值安全
记住:保持控制器精简、服务专注、仓库简单,并集中处理错误。为可维护性和可测试性进行优化。
When not to use it
- →Non-Java or non-Spring Boot projects
- →Applications not requiring a layered architecture
Prerequisites
Limitations
- →Requires proper configuration of ForwardedHeaderFilter for accurate IP detection in rate limiting
- →Relies on specific Spring Boot annotations for functionality
How it compares
It provides pre-validated architectural patterns for Spring Boot rather than requiring manual implementation of standard boilerplate code.
Compared to similar skills
springboot-patterns side by side with the closest alternatives in the catalog.
| Skill | Installs | Updated | Safety | Difficulty |
|---|---|---|---|---|
| springboot-patterns (this skill) | 11 | 5mo | No flags | Intermediate |
| event-store-design | 5 | 2mo | No flags | Advanced |
| dotnet-architect | 12 | 4mo | No flags | Advanced |
| backend-development | 17 | 4mo | No flags | Intermediate |
Try saying
Example prompts that trigger this skill in your AI assistant.
More by affaan-m
View all by affaan-m →You might also like
event-store-design
wshobson
Design and implement event stores for event-sourced systems. Use when building event sourcing infrastructure, choosing event store technologies, or implementing event persistence patterns.
dotnet-architect
sickn33
Expert .NET backend architect specializing in C#, ASP.NET Core, Entity Framework, Dapper, and enterprise application patterns. Masters async/await, dependency injection, caching strategies, and performance optimization. Use PROACTIVELY for .NET API development, code review, or architecture decisions.
backend-development
skillcreatorai
Backend API design, database architecture, microservices patterns, and test-driven development. Use for designing APIs, database schemas, or backend system architecture.
backend-patterns
chenqin231
Backend architecture patterns, API design, database optimization, and server-side best practices for Node.js, Express, and Next.js API routes.
web-server-architecture
develsvai
`web/src/server/**`의 router, service, 공통 계층을 건드릴 때 사용하는 스킬이다. tRPC router와 service 책임 분리, 도메인 구조, Prisma 사용 경계를 맞춘다.
startup
matlockx
Use this skill for Go service bootstrapping with flachnetz/startup library. Covers options composition, auto-initialization, Postgres, Kafka, HTTP server, tracing, and environment patterns.