Communitygithub.com

springboot-patterns

Spring Boot 架構模式、REST API 設計、分層服務、資料存取、快取、非同步處理與日誌記錄。適用於 Java Spring Boot 後端開發。

springboot-patterns 是什麼?

此技能提供一套全面的 Spring Boot 開發模式與架構最佳實踐,專為建構可擴展且適合生產環境的後端服務而設計。它涵蓋了從 REST API 結構(Spring MVC 或 WebFlux)、分層架構(Controller → Service → Repository)、Spring Data JPA 資料存取,到進階主題如快取機制(@Cacheable)、非同步處理(@Async)、SLF4J 日誌記錄與例外處理等核心元件。此外,技能還包含了安全性考量,例如在反向代理環境下正確處理用戶端 IP 以實現速率限制(Rate Limiting),並提供了使用 Bucket4j 的實作範例。此技能支援 Claude Code、Cursor 與 Codex 等平台,開發者可在建構或審查 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、快取或非同步處理
  • 加入驗證、例外處理或分頁功能
  • 為開發/測試/正式環境設定設定檔 (profiles)
  • 實作基於 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));
  }
}

Repository 模式 (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) {
    // 發送 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 {
      // 邏輯
    } 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)整合。保持處理器具有冪等性且可觀察。

可觀測性

  • 結構化日誌(JSON)透過 Logback encoder
  • 指標:Micrometer + Prometheus/OTel
  • 追蹤:Micrometer Tracing 搭配 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.

相關技能