Communitygithub.com

springboot-patterns

Spring Boot 架构模式,涵盖 REST API 设计、分层服务、数据访问、缓存、异步处理和日志记录。用于 Java Spring Boot 后端开发。

springboot-patterns 是什么?

该技能提供了构建可扩展、生产级 Spring Boot 服务的完整架构和 API 模式。它涵盖了从 REST API 设计(基于 Spring MVC 或 WebFlux)、分层架构(Controller → Service → Repository)到数据访问(Spring Data JPA)、缓存(@Cacheable/@CacheEvict)、异步处理(@Async)以及结构化日志记录(SLF4J)等关键方面。技能强调最佳实践,如构造函数注入、事务管理(@Transactional)、统一异常处理(@ControllerAdvice)和分页排序。同时包含生产环境关键配置:通过 ForwardedHeaderFilter 安全地获取客户端 IP、基于 Bucket4j 的速率限制、重试机制以及可观测性(结构化日志、Micrometer 指标、分布式追踪)。此技能适合在开发或审查 Spring Boot 后端时使用,尤其注重代码的可维护性和可测试性。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/affaan-m/everything-claude-code/tree/main/skills/springboot-patterns

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

Spring Boot 开发模式

面向可扩展、生产级服务的 Spring Boot 架构和 API 模式。

何时激活

  • 使用 Spring MVC 或 WebFlux 构建 REST API
  • 组织 controller → service → repository 各层
  • 配置 Spring Data JPA、缓存或异步处理
  • 添加验证、异常处理或分页功能
  • 为开发/预发布/生产环境设置 Profile
  • 使用 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) {
    // 使用堆栈跟踪记录未预期的错误
    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) {
    // 发送电子邮件/短信
    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 {
      // 业务逻辑
    } 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 头部是不可信的,因为客户端可以伪造它。 仅在以下情况下使用转发的头部:

  1. 您的应用程序位于可信的反向代理(nginx、AWS ALB 等)之后
  2. 您已将 ForwardedHeaderFilter 注册为 Bean
  3. 您已在应用属性中配置了 server.forward-headers-strategy=NATIVE 或 FRAMEWORK
  4. 您的代理配置为覆盖(而非追加)X-Forwarded-For 头部

当 ForwardedHeaderFilter 正确配置后,request.getRemoteAddr() 将自动 从转发的头部返回正确的客户端 IP。如果没有此配置,请直接使用 request.getRemoteAddr() —— 它返回直接连接的 IP,这是唯一可信的值。

@Component
public class RateLimitFilter extends OncePerRequestFilter {
  private final Map<String, Bucket> buckets = new ConcurrentHashMap<>();

  /*
   * 安全:此过滤器使用 request.getRemoteAddr() 来识别客户端以进行速率限制。
   *
   * 如果您的应用程序位于反向代理(nginx、AWS ALB 等)之后,您必须配置
   * Spring 以正确处理转发头部,才能准确获取客户端 IP:
   *
   * 1. 在 application.properties/yaml 中设置 server.forward-headers-strategy=NATIVE(适用于云平台)
   *    或 FRAMEWORK
   * 2. 如果使用 FRAMEWORK 策略,请注册 ForwardedHeaderFilter:
   *
   *    @Bean
   *    ForwardedHeaderFilter forwardedHeaderFilter() {
   *        return new ForwardedHeaderFilter();
   *    }
   *
   * 3. 确保您的代理覆盖(而非追加) X-Forwarded-For 头部以防止欺骗
   * 4. 为您的容器配置 server.tomcat.remoteip.trusted-proxies 或等效设置
   *
   * 没有此配置时,request.getRemoteAddr() 将返回代理 IP,而非客户端 IP。
   * 不要直接读取 X-Forwarded-For——在未进行可信代理处理的情况下,它极易被伪造。
   */
  @Override
  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
      FilterChain filterChain) throws ServletException, IOException {
    // 使用 getRemoteAddr(),当配置了 ForwardedHeaderFilter 时返回正确的客户端 IP,
    // 否则返回直接连接的 IP。切勿在没有正确代理配置的情况下直接信任 X-Forwarded-For 头部。
    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
  • 链路追踪:Micrometer Tracing with OpenTelemetry 或 Brave 后端

生产环境默认设置

  • 优先使用构造函数注入,避免字段注入
  • 启用 spring.mvc.problemdetails.enabled=true 以支持 RFC 7807 错误响应(Spring Boot 3+)
  • 根据工作负载配置 HikariCP 连接池大小并设置超时
  • 对查询使用 @Transactional(readOnly = true)
  • 在适当的地方通过 @NonNull 和 Optional 强制执行空安全

记住:保持控制器精简、服务专注、仓库简单、错误集中处理。以可维护性和可测试性为优化目标。

Individual skills in this repo

This repo contains 20 individual skills — each has its own dedicated page.

accessibility

Design, implement, and audit inclusive digital products using WCAG 2.2 Level AA. Use when building or auditing UI that must meet WCAG 2.2 Level AA, or when reviewing a change for keyboard, contrast, or screen-reader support.

affaan-m/claude-api

Anthropic Claude API patterns for Python and TypeScript. Covers Messages API, streaming, tool use, vision, extended thinking, batches, prompt caching, and Claude Agent SDK. Use when building applications with the Claude API or Anthropic SDKs.

affaan-m/everything-claude-code

End-to-end marketing campaign planning and execution. Covers audience research, positioning, campaign angle definition, landing page copy, email sequences, social posts, ad copy, short-form video scripts, and content calendars. Use as the orchestration layer for multi-channel product launches. Use when planning or executing a multi-channel product launch, or producing landing page, email, social, or ad copy.

affaan-m/everything-claude-code

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/everything-claude-code-conventions

Development conventions and patterns for everything-claude-code. JavaScript project with conventional commits.

affaan-m/frontend-design

Create distinctive, production-grade frontend interfaces with high design quality. Use when the user asks to build web components, pages, or applications and the visual direction matters as much as the code quality.

affaan-m/gget

gget CLI and Python workflow for quick genomic database queries, sequence lookup, BLAST-style searches, enrichment checks, and reproducible bioinformatics evidence logs.

affaan-m/literature-review

Systematic literature-review workflow for academic, biomedical, technical, and scientific topics, including search planning, source screening, synthesis, citation checks, and evidence logging.

affaan-m/motion-ui

Production-ready UI motion system for React/Next.js. Use when implementing animations, transitions, or motion patterns.

affaan-m/project-guidelines-example

Example project-specific skill template based on a real production application.

affaan-m/pubmed-database

Direct PubMed and NCBI E-utilities search workflows for biomedical literature, MeSH queries, PMID lookup, citation retrieval, and API-backed literature monitoring.

affaan-m/scholar-evaluation

Structured scholarly-work evaluation for papers, proposals, literature reviews, methods sections, evidence quality, citation support, and research-writing feedback.

affaan-m/uspto-database

USPTO patent and trademark data workflow for official record lookup, PatentSearch queries, TSDR checks, assignment data, and reproducible IP research logs.

agent-architecture-audit

Full-stack diagnostic for agent and LLM applications. Audits the 12-layer agent stack for wrapper regression, memory pollution, tool discipline failures, hidden repair loops, and rendering corruption. Produces severity-ranked findings with code-first fixes. Essential for developers building agent applications, autonomous loops, or any LLM-powered feature. Use when an agent or LLM feature misbehaves and the failing layer is unknown, or before shipping an agent stack.

agent-eval

Head-to-head comparison of coding agents (Claude Code, Aider, Codex, etc.) on custom tasks with pass rate, cost, time, and consistency metrics. Use when choosing between coding agents, or when a change to an agent setup needs measured pass rate, cost, and time rather than an impression.

agent-harness-construction

Design and optimize AI agent action spaces, tool definitions, and observation formatting for higher completion rates. Use when defining or revising an agent

agentic-engineering

Operate as an agentic engineer using eval-first execution, decomposition, and cost-aware model routing. Use when planning or executing engineering work that agents will carry out end to end.

agentic-os

Build persistent multi-agent operating systems on Claude Code. Covers kernel architecture, specialist agents, slash commands, file-based memory, scheduled automation, and state management without external databases. Use when building a persistent multi-agent system on Claude Code with its own memory, commands, and scheduling.

agent-introspection-debugging

Structured self-debugging workflow for AI agent failures using capture, diagnosis, contained recovery, and introspection reports. Use when an agent run fails and you need a reproducible diagnosis instead of a retry.

agent-payment-x402

Add x402 payment execution to AI agents with per-task budgets, spending controls, and non-custodial wallets. Supports Base through agentwallet-sdk and X Layer through OKX Payments / OKX Agent Payments Protocol. Use when an agent must pay for something itself and needs per-task budgets, spending controls, and a non-custodial wallet.

相关技能