[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6EH65CPXJ01KDFYY71KW6H8":3,"skill-same:01M6EH65CPXJ01KDFYY71KW6H8":78},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":28,"publishedAt":49,"linkOnly":50,"markdownContent":51,"markdownBody":52,"frontMatter":53,"refName":55,"commitSha":56,"skillDirectory":57,"forksCount":58,"repositoryHtmlUrl":59,"repositoryHomepageUrl":60,"ownerHtmlUrl":61,"ownerBlogUrl":6,"ownerDescription":62,"updatedAt":63,"install":64,"resources":77},"01M6EH65CPXJ01KDFYY71KW6H8","springboot-patterns",null,"Spring Boot architecture patterns, REST API design, layered services, data access, caching, async processing, and logging. Use for Java Spring Boot backend work.","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",67,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faffaan-m\u002Feverything-claude-code\u002Fspringboot-patterns\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000030","开发工程师","PROFESSION","适用职业",[29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48],"patterns","springboot patterns","spring boot architecture","design","processing","caching","java spring","async","use","work","spring","access","api","architecture patterns","data","spring boot","java","logging","boot","architecture","2026-11-10 10:12:30",false,"---\nname: springboot-patterns\ndescription: Spring Boot architecture patterns, REST API design, layered services, data access, caching, async processing, and logging. Use for Java Spring Boot backend work.\norigin: ECC\n---\n\n# Spring Boot Development Patterns\n\nSpring Boot architecture and API patterns for scalable, production-grade services.\n\n## When to Activate\n\n- Building REST APIs with Spring MVC or WebFlux\n- Structuring controller → service → repository layers\n- Configuring Spring Data JPA, caching, or async processing\n- Adding validation, exception handling, or pagination\n- Setting up profiles for dev\u002Fstaging\u002Fproduction environments\n- Implementing event-driven patterns with Spring Events or Kafka\n\n## REST API Structure\n\n```java\n@RestController\n@RequestMapping(\"\u002Fapi\u002Fmarkets\")\n@Validated\nclass MarketController {\n  private final MarketService marketService;\n\n  MarketController(MarketService marketService) {\n    this.marketService = marketService;\n  }\n\n  @GetMapping\n  ResponseEntity\u003CPage\u003CMarketResponse>> list(\n      @RequestParam(defaultValue = \"0\") int page,\n      @RequestParam(defaultValue = \"20\") int size) {\n    Page\u003CMarket> markets = marketService.list(PageRequest.of(page, size));\n    return ResponseEntity.ok(markets.map(MarketResponse::from));\n  }\n\n  @PostMapping\n  ResponseEntity\u003CMarketResponse> create(@Valid @RequestBody CreateMarketRequest request) {\n    Market market = marketService.create(request);\n    return ResponseEntity.status(HttpStatus.CREATED).body(MarketResponse.from(market));\n  }\n}\n```\n\n## Repository Pattern (Spring Data JPA)\n\n```java\npublic interface MarketRepository extends JpaRepository\u003CMarketEntity, Long> {\n  @Query(\"select m from MarketEntity m where m.status = :status order by m.volume desc\")\n  List\u003CMarketEntity> findActive(@Param(\"status\") MarketStatus status, Pageable pageable);\n}\n```\n\n## Service Layer with Transactions\n\n```java\n@Service\npublic class MarketService {\n  private final MarketRepository repo;\n\n  public MarketService(MarketRepository repo) {\n    this.repo = repo;\n  }\n\n  @Transactional\n  public Market create(CreateMarketRequest request) {\n    MarketEntity entity = MarketEntity.from(request);\n    MarketEntity saved = repo.save(entity);\n    return Market.from(saved);\n  }\n}\n```\n\n## DTOs and Validation\n\n```java\npublic record CreateMarketRequest(\n    @NotBlank @Size(max = 200) String name,\n    @NotBlank @Size(max = 2000) String description,\n    @NotNull @FutureOrPresent Instant endDate,\n    @NotEmpty List\u003C@NotBlank String> categories) {}\n\npublic record MarketResponse(Long id, String name, MarketStatus status) {\n  static MarketResponse from(Market market) {\n    return new MarketResponse(market.id(), market.name(), market.status());\n  }\n}\n```\n\n## Exception Handling\n\n```java\n@ControllerAdvice\nclass GlobalExceptionHandler {\n  @ExceptionHandler(MethodArgumentNotValidException.class)\n  ResponseEntity\u003CApiError> handleValidation(MethodArgumentNotValidException ex) {\n    String message = ex.getBindingResult().getFieldErrors().stream()\n        .map(e -> e.getField() + \": \" + e.getDefaultMessage())\n        .collect(Collectors.joining(\", \"));\n    return ResponseEntity.badRequest().body(ApiError.validation(message));\n  }\n\n  @ExceptionHandler(AccessDeniedException.class)\n  ResponseEntity\u003CApiError> handleAccessDenied() {\n    return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ApiError.of(\"Forbidden\"));\n  }\n\n  @ExceptionHandler(Exception.class)\n  ResponseEntity\u003CApiError> handleGeneric(Exception ex) {\n    \u002F\u002F Log unexpected errors with stack traces\n    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)\n        .body(ApiError.of(\"Internal server error\"));\n  }\n}\n```\n\n## Caching\n\nRequires `@EnableCaching` on a configuration class.\n\n```java\n@Service\npublic class MarketCacheService {\n  private final MarketRepository repo;\n\n  public MarketCacheService(MarketRepository repo) {\n    this.repo = repo;\n  }\n\n  @Cacheable(value = \"market\", key = \"#id\")\n  public Market getById(Long id) {\n    return repo.findById(id)\n        .map(Market::from)\n        .orElseThrow(() -> new EntityNotFoundException(\"Market not found\"));\n  }\n\n  @CacheEvict(value = \"market\", key = \"#id\")\n  public void evict(Long id) {}\n}\n```\n\n## Async Processing\n\nRequires `@EnableAsync` on a configuration class.\n\n```java\n@Service\npublic class NotificationService {\n  @Async\n  public CompletableFuture\u003CVoid> sendAsync(Notification notification) {\n    \u002F\u002F send email\u002FSMS\n    return CompletableFuture.completedFuture(null);\n  }\n}\n```\n\n## Logging (SLF4J)\n\n```java\n@Service\npublic class ReportService {\n  private static final Logger log = LoggerFactory.getLogger(ReportService.class);\n\n  public Report generate(Long marketId) {\n    log.info(\"generate_report marketId={}\", marketId);\n    try {\n      \u002F\u002F logic\n    } catch (Exception ex) {\n      log.error(\"generate_report_failed marketId={}\", marketId, ex);\n      throw ex;\n    }\n    return new Report();\n  }\n}\n```\n\n## Middleware \u002F Filters\n\n```java\n@Component\npublic class RequestLoggingFilter extends OncePerRequestFilter {\n  private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);\n\n  @Override\n  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n      FilterChain filterChain) throws ServletException, IOException {\n    long start = System.currentTimeMillis();\n    try {\n      filterChain.doFilter(request, response);\n    } finally {\n      long duration = System.currentTimeMillis() - start;\n      log.info(\"req method={} uri={} status={} durationMs={}\",\n          request.getMethod(), request.getRequestURI(), response.getStatus(), duration);\n    }\n  }\n}\n```\n\n## Pagination and Sorting\n\n```java\nPageRequest page = PageRequest.of(pageNumber, pageSize, Sort.by(\"createdAt\").descending());\nPage\u003CMarket> results = marketService.list(page);\n```\n\n## Error-Resilient External Calls\n\n```java\npublic \u003CT> T withRetry(Supplier\u003CT> supplier, int maxRetries) {\n  int attempts = 0;\n  while (true) {\n    try {\n      return supplier.get();\n    } catch (Exception ex) {\n      attempts++;\n      if (attempts >= maxRetries) {\n        throw ex;\n      }\n      try {\n        Thread.sleep((long) Math.pow(2, attempts) * 100L);\n      } catch (InterruptedException ie) {\n        Thread.currentThread().interrupt();\n        throw ex;\n      }\n    }\n  }\n}\n```\n\n## Rate Limiting (Filter + Bucket4j)\n\n**Security Note**: The `X-Forwarded-For` header is untrusted by default because clients can spoof it.\nOnly use forwarded headers when:\n1. Your app is behind a trusted reverse proxy (nginx, AWS ALB, etc.)\n2. You have registered `ForwardedHeaderFilter` as a bean\n3. You have configured `server.forward-headers-strategy=NATIVE` or `FRAMEWORK` in application properties\n4. Your proxy is configured to overwrite (not append to) the `X-Forwarded-For` header\n\nWhen `ForwardedHeaderFilter` is properly configured, `request.getRemoteAddr()` will automatically\nreturn the correct client IP from the forwarded headers. Without this configuration, use\n`request.getRemoteAddr()` directly—it returns the immediate connection IP, which is the only\ntrustworthy value.\n\n```java\n@Component\npublic class RateLimitFilter extends OncePerRequestFilter {\n  private final Map\u003CString, Bucket> buckets = new ConcurrentHashMap\u003C>();\n\n  \u002F*\n   * SECURITY: This filter uses request.getRemoteAddr() to identify clients for rate limiting.\n   *\n   * If your application is behind a reverse proxy (nginx, AWS ALB, etc.), you MUST configure\n   * Spring to handle forwarded headers properly for accurate client IP detection:\n   *\n   * 1. Set server.forward-headers-strategy=NATIVE (for cloud platforms) or FRAMEWORK in\n   *    application.properties\u002Fyaml\n   * 2. If using FRAMEWORK strategy, register ForwardedHeaderFilter:\n   *\n   *    @Bean\n   *    ForwardedHeaderFilter forwardedHeaderFilter() {\n   *        return new ForwardedHeaderFilter();\n   *    }\n   *\n   * 3. Ensure your proxy overwrites (not appends) the X-Forwarded-For header to prevent spoofing\n   * 4. Configure server.tomcat.remoteip.trusted-proxies or equivalent for your container\n   *\n   * Without this configuration, request.getRemoteAddr() returns the proxy IP, not the client IP.\n   * Do NOT read X-Forwarded-For directly—it is trivially spoofable without trusted proxy handling.\n   *\u002F\n  @Override\n  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n      FilterChain filterChain) throws ServletException, IOException {\n    \u002F\u002F Use getRemoteAddr() which returns the correct client IP when ForwardedHeaderFilter\n    \u002F\u002F is configured, or the direct connection IP otherwise. Never trust X-Forwarded-For\n    \u002F\u002F headers directly without proper proxy configuration.\n    String clientIp = request.getRemoteAddr();\n\n    Bucket bucket = buckets.computeIfAbsent(clientIp,\n        k -> Bucket.builder()\n            .addLimit(Bandwidth.classic(100, Refill.greedy(100, Duration.ofMinutes(1))))\n            .build());\n\n    if (bucket.tryConsume(1)) {\n      filterChain.doFilter(request, response);\n    } else {\n      response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());\n    }\n  }\n}\n```\n\n## Background Jobs\n\nUse Spring’s `@Scheduled` or integrate with queues (e.g., Kafka, SQS, RabbitMQ). Keep handlers idempotent and observable.\n\n## Observability\n\n- Structured logging (JSON) via Logback encoder\n- Metrics: Micrometer + Prometheus\u002FOTel\n- Tracing: Micrometer Tracing with OpenTelemetry or Brave backend\n\n## Production Defaults\n\n- Prefer constructor injection, avoid field injection\n- Enable `spring.mvc.problemdetails.enabled=true` for RFC 7807 errors (Spring Boot 3+)\n- Configure HikariCP pool sizes for workload, set timeouts\n- Use `@Transactional(readOnly = true)` for queries\n- Enforce null-safety via `@NonNull` and `Optional` where appropriate\n\n**Remember**: Keep controllers thin, services focused, repositories simple, and errors handled centrally. Optimize for maintainability and testability.\n\n","# Spring Boot Development Patterns\n\nSpring Boot architecture and API patterns for scalable, production-grade services.\n\n## When to Activate\n\n- Building REST APIs with Spring MVC or WebFlux\n- Structuring controller → service → repository layers\n- Configuring Spring Data JPA, caching, or async processing\n- Adding validation, exception handling, or pagination\n- Setting up profiles for dev\u002Fstaging\u002Fproduction environments\n- Implementing event-driven patterns with Spring Events or Kafka\n\n## REST API Structure\n\n```java\n@RestController\n@RequestMapping(\"\u002Fapi\u002Fmarkets\")\n@Validated\nclass MarketController {\n  private final MarketService marketService;\n\n  MarketController(MarketService marketService) {\n    this.marketService = marketService;\n  }\n\n  @GetMapping\n  ResponseEntity\u003CPage\u003CMarketResponse>> list(\n      @RequestParam(defaultValue = \"0\") int page,\n      @RequestParam(defaultValue = \"20\") int size) {\n    Page\u003CMarket> markets = marketService.list(PageRequest.of(page, size));\n    return ResponseEntity.ok(markets.map(MarketResponse::from));\n  }\n\n  @PostMapping\n  ResponseEntity\u003CMarketResponse> create(@Valid @RequestBody CreateMarketRequest request) {\n    Market market = marketService.create(request);\n    return ResponseEntity.status(HttpStatus.CREATED).body(MarketResponse.from(market));\n  }\n}\n```\n\n## Repository Pattern (Spring Data JPA)\n\n```java\npublic interface MarketRepository extends JpaRepository\u003CMarketEntity, Long> {\n  @Query(\"select m from MarketEntity m where m.status = :status order by m.volume desc\")\n  List\u003CMarketEntity> findActive(@Param(\"status\") MarketStatus status, Pageable pageable);\n}\n```\n\n## Service Layer with Transactions\n\n```java\n@Service\npublic class MarketService {\n  private final MarketRepository repo;\n\n  public MarketService(MarketRepository repo) {\n    this.repo = repo;\n  }\n\n  @Transactional\n  public Market create(CreateMarketRequest request) {\n    MarketEntity entity = MarketEntity.from(request);\n    MarketEntity saved = repo.save(entity);\n    return Market.from(saved);\n  }\n}\n```\n\n## DTOs and Validation\n\n```java\npublic record CreateMarketRequest(\n    @NotBlank @Size(max = 200) String name,\n    @NotBlank @Size(max = 2000) String description,\n    @NotNull @FutureOrPresent Instant endDate,\n    @NotEmpty List\u003C@NotBlank String> categories) {}\n\npublic record MarketResponse(Long id, String name, MarketStatus status) {\n  static MarketResponse from(Market market) {\n    return new MarketResponse(market.id(), market.name(), market.status());\n  }\n}\n```\n\n## Exception Handling\n\n```java\n@ControllerAdvice\nclass GlobalExceptionHandler {\n  @ExceptionHandler(MethodArgumentNotValidException.class)\n  ResponseEntity\u003CApiError> handleValidation(MethodArgumentNotValidException ex) {\n    String message = ex.getBindingResult().getFieldErrors().stream()\n        .map(e -> e.getField() + \": \" + e.getDefaultMessage())\n        .collect(Collectors.joining(\", \"));\n    return ResponseEntity.badRequest().body(ApiError.validation(message));\n  }\n\n  @ExceptionHandler(AccessDeniedException.class)\n  ResponseEntity\u003CApiError> handleAccessDenied() {\n    return ResponseEntity.status(HttpStatus.FORBIDDEN).body(ApiError.of(\"Forbidden\"));\n  }\n\n  @ExceptionHandler(Exception.class)\n  ResponseEntity\u003CApiError> handleGeneric(Exception ex) {\n    \u002F\u002F Log unexpected errors with stack traces\n    return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)\n        .body(ApiError.of(\"Internal server error\"));\n  }\n}\n```\n\n## Caching\n\nRequires `@EnableCaching` on a configuration class.\n\n```java\n@Service\npublic class MarketCacheService {\n  private final MarketRepository repo;\n\n  public MarketCacheService(MarketRepository repo) {\n    this.repo = repo;\n  }\n\n  @Cacheable(value = \"market\", key = \"#id\")\n  public Market getById(Long id) {\n    return repo.findById(id)\n        .map(Market::from)\n        .orElseThrow(() -> new EntityNotFoundException(\"Market not found\"));\n  }\n\n  @CacheEvict(value = \"market\", key = \"#id\")\n  public void evict(Long id) {}\n}\n```\n\n## Async Processing\n\nRequires `@EnableAsync` on a configuration class.\n\n```java\n@Service\npublic class NotificationService {\n  @Async\n  public CompletableFuture\u003CVoid> sendAsync(Notification notification) {\n    \u002F\u002F send email\u002FSMS\n    return CompletableFuture.completedFuture(null);\n  }\n}\n```\n\n## Logging (SLF4J)\n\n```java\n@Service\npublic class ReportService {\n  private static final Logger log = LoggerFactory.getLogger(ReportService.class);\n\n  public Report generate(Long marketId) {\n    log.info(\"generate_report marketId={}\", marketId);\n    try {\n      \u002F\u002F logic\n    } catch (Exception ex) {\n      log.error(\"generate_report_failed marketId={}\", marketId, ex);\n      throw ex;\n    }\n    return new Report();\n  }\n}\n```\n\n## Middleware \u002F Filters\n\n```java\n@Component\npublic class RequestLoggingFilter extends OncePerRequestFilter {\n  private static final Logger log = LoggerFactory.getLogger(RequestLoggingFilter.class);\n\n  @Override\n  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n      FilterChain filterChain) throws ServletException, IOException {\n    long start = System.currentTimeMillis();\n    try {\n      filterChain.doFilter(request, response);\n    } finally {\n      long duration = System.currentTimeMillis() - start;\n      log.info(\"req method={} uri={} status={} durationMs={}\",\n          request.getMethod(), request.getRequestURI(), response.getStatus(), duration);\n    }\n  }\n}\n```\n\n## Pagination and Sorting\n\n```java\nPageRequest page = PageRequest.of(pageNumber, pageSize, Sort.by(\"createdAt\").descending());\nPage\u003CMarket> results = marketService.list(page);\n```\n\n## Error-Resilient External Calls\n\n```java\npublic \u003CT> T withRetry(Supplier\u003CT> supplier, int maxRetries) {\n  int attempts = 0;\n  while (true) {\n    try {\n      return supplier.get();\n    } catch (Exception ex) {\n      attempts++;\n      if (attempts >= maxRetries) {\n        throw ex;\n      }\n      try {\n        Thread.sleep((long) Math.pow(2, attempts) * 100L);\n      } catch (InterruptedException ie) {\n        Thread.currentThread().interrupt();\n        throw ex;\n      }\n    }\n  }\n}\n```\n\n## Rate Limiting (Filter + Bucket4j)\n\n**Security Note**: The `X-Forwarded-For` header is untrusted by default because clients can spoof it.\nOnly use forwarded headers when:\n1. Your app is behind a trusted reverse proxy (nginx, AWS ALB, etc.)\n2. You have registered `ForwardedHeaderFilter` as a bean\n3. You have configured `server.forward-headers-strategy=NATIVE` or `FRAMEWORK` in application properties\n4. Your proxy is configured to overwrite (not append to) the `X-Forwarded-For` header\n\nWhen `ForwardedHeaderFilter` is properly configured, `request.getRemoteAddr()` will automatically\nreturn the correct client IP from the forwarded headers. Without this configuration, use\n`request.getRemoteAddr()` directly—it returns the immediate connection IP, which is the only\ntrustworthy value.\n\n```java\n@Component\npublic class RateLimitFilter extends OncePerRequestFilter {\n  private final Map\u003CString, Bucket> buckets = new ConcurrentHashMap\u003C>();\n\n  \u002F*\n   * SECURITY: This filter uses request.getRemoteAddr() to identify clients for rate limiting.\n   *\n   * If your application is behind a reverse proxy (nginx, AWS ALB, etc.), you MUST configure\n   * Spring to handle forwarded headers properly for accurate client IP detection:\n   *\n   * 1. Set server.forward-headers-strategy=NATIVE (for cloud platforms) or FRAMEWORK in\n   *    application.properties\u002Fyaml\n   * 2. If using FRAMEWORK strategy, register ForwardedHeaderFilter:\n   *\n   *    @Bean\n   *    ForwardedHeaderFilter forwardedHeaderFilter() {\n   *        return new ForwardedHeaderFilter();\n   *    }\n   *\n   * 3. Ensure your proxy overwrites (not appends) the X-Forwarded-For header to prevent spoofing\n   * 4. Configure server.tomcat.remoteip.trusted-proxies or equivalent for your container\n   *\n   * Without this configuration, request.getRemoteAddr() returns the proxy IP, not the client IP.\n   * Do NOT read X-Forwarded-For directly—it is trivially spoofable without trusted proxy handling.\n   *\u002F\n  @Override\n  protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,\n      FilterChain filterChain) throws ServletException, IOException {\n    \u002F\u002F Use getRemoteAddr() which returns the correct client IP when ForwardedHeaderFilter\n    \u002F\u002F is configured, or the direct connection IP otherwise. Never trust X-Forwarded-For\n    \u002F\u002F headers directly without proper proxy configuration.\n    String clientIp = request.getRemoteAddr();\n\n    Bucket bucket = buckets.computeIfAbsent(clientIp,\n        k -> Bucket.builder()\n            .addLimit(Bandwidth.classic(100, Refill.greedy(100, Duration.ofMinutes(1))))\n            .build());\n\n    if (bucket.tryConsume(1)) {\n      filterChain.doFilter(request, response);\n    } else {\n      response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());\n    }\n  }\n}\n```\n\n## Background Jobs\n\nUse Spring’s `@Scheduled` or integrate with queues (e.g., Kafka, SQS, RabbitMQ). Keep handlers idempotent and observable.\n\n## Observability\n\n- Structured logging (JSON) via Logback encoder\n- Metrics: Micrometer + Prometheus\u002FOTel\n- Tracing: Micrometer Tracing with OpenTelemetry or Brave backend\n\n## Production Defaults\n\n- Prefer constructor injection, avoid field injection\n- Enable `spring.mvc.problemdetails.enabled=true` for RFC 7807 errors (Spring Boot 3+)\n- Configure HikariCP pool sizes for workload, set timeouts\n- Use `@Transactional(readOnly = true)` for queries\n- Enforce null-safety via `@NonNull` and `Optional` where appropriate\n\n**Remember**: Keep controllers thin, services focused, repositories simple, and errors handled centrally. Optimize for maintainability and testability.\n\n",{"name":5,"origin":54,"description":7},"ECC","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Faffaan-m\u002Feverything-claude-code\u002Fspringboot-patterns",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":65,"prompt":75,"zipAvailable":76},[66,69,72],{"tool":67,"command":68},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill springboot-patterns",{"tool":70,"command":71},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill springboot-patterns",{"tool":73,"command":74},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill springboot-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Faffaan-m\u002Feverything-claude-code\u002Fspringboot-patterns\u002FSKILL.md",true,[],[79,91,101,110,116,123],{"skillNo":80,"name":81,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":82,"categories":83,"keywords":87,"publishedAt":49},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[84],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[88,89,90],"model","model hierarchy","model hierarchy skill",{"skillNo":92,"name":93,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":94,"categories":95,"keywords":97,"publishedAt":49},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[96],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},[98,99,100],"MCP","zoom","zoom mcp",{"skillNo":102,"name":103,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":106,"publishedAt":49},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[107,108,109,99],"sdk","zoom apps sdk","apps",{"skillNo":111,"name":112,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":113,"categories":114,"keywords":115,"publishedAt":49},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[112],{"skillNo":117,"name":118,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":119,"categories":120,"keywords":122,"publishedAt":49},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[121],{"categoryNo":85,"categoryName":86,"taxonomyType":21,"taxonomyTypeDesc":22},[118],{"skillNo":124,"name":125,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":126,"categories":127,"keywords":128,"publishedAt":49},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[125]]