Skills Plugins MCP Prompt Model 博客 我的中心

springboot-patterns

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

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-zh-cn-skills-springboot-patterns-skill-md&format=skill
Download .skill Standard format with system_prompt and model_config, ready for any agent framework
The actual content of the system_prompt field in the .skill file.
name springboot-patterns description Spring Boot架构模式、REST API设计、分层服务、数据访问、缓存、异步处理和日志记录。用于Java Spring Boot后端工作。 origin ECC 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 强制执行空值安全 记住 :保持控制器精简、服务专注、仓库简单,并集中处理错误。为可维护性和可测试性进行优化。
Keywords that activate this skill. Click one to copy it.

This skill does not provide trigger words.

The downloaded .skill package contains the following fields.
Field Description
formatFormat tag (skill/v1)
skill_idUnique skill ID
nameSkill name
versionVersion
descriptionDescription
categoryCategories (array)
trigger_wordsTrigger words
tagsTags
sourceSource
source_urlSource URL (this page)
exported_atExported at (set per download)
system_promptSystem prompt body
model_configModel config: provider / model / temperature / max_tokens / top_p
examplesExamples
install_guideImport guide for Coze / Dify / Claude / custom frameworks
The same skill can be exported in different platform formats.
.skill Standard format with system_prompt and model_config, ready for any agent framework Download
.skillpro Enhanced format with scripts, tools, dependencies and hooks Download
.json Plain JSON export with system_prompt and model parameters only Download
Coze Markdown with frontmatter, for Coze platform import Download
Dify Dify DSL, import directly after creating an app Download

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。