Skills Plugins MCP Prompt Model 博客 我的中心

quarkus-patterns

Patrones de arquitectura Quarkus 3.x LTS con Camel para mensajería, diseño de API RESTful, servicios CDI, acceso a datos con Panache y procesamiento asíncrono.

DeepseekModel Curated skill Quality Excellent · 90 v1.0.0

Get

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-es-skills-quarkus-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 quarkus-patterns description Patrones de arquitectura Quarkus 3.x LTS con Camel para mensajería, diseño de API RESTful, servicios CDI, acceso a datos con Panache y procesamiento asíncrono. origin ECC Patrones de Desarrollo Quarkus Patrones de arquitectura y API de Quarkus 3.x para servicios cloud-native y orientados a eventos con Apache Camel. Cuándo Activar Construir APIs REST con JAX-RS o RESTEasy Reactive Estructurar capas resource → service → repository Implementar patrones orientados a eventos con Apache Camel y RabbitMQ Configurar Hibernate Panache, caché o streams reactivos Agregar validación, mapeo de excepciones o paginación Configurar perfiles para entornos dev/staging/producción (configuración YAML) Logging personalizado con LogContext y Logback/Logstash encoder Trabajar con CompletableFuture para operaciones asíncronas Implementar procesamiento condicional de flujos Trabajar con compilación nativa GraalVM Capa de Servicio con Múltiples Dependencias @Slf4j @ApplicationScoped @RequiredArgsConstructor public class OrderProcessingService { private final OrderValidator orderValidator; private final EventService eventService; private final OrderRepository orderRepository; private final FulfillmentPublisher fulfillmentPublisher; private final AuditPublisher auditPublisher; @Transactional public OrderReceipt process (CreateOrderCommand command) { ValidationResult validation = orderValidator.validate(command); if (!validation.valid()) { eventService.createErrorEvent(command, "ORDER_REJECTED" , validation.message()); throw new WebApplicationException (validation.message(), Response.Status.BAD_REQUEST); } Order order = Order.from(command); orderRepository.persist(order); OrderReceipt receipt = OrderReceipt.from(order); fulfillmentPublisher.publishAsync(receipt); auditPublisher.publish( "ORDER_ACCEPTED" , receipt); eventService.createSuccessEvent(receipt, "ORDER_ACCEPTED" ); log.info( "Orden procesada {}" , order.id); return receipt; } } Patrones Clave: @RequiredArgsConstructor para inyección por constructor mediante Lombok @Slf4j para logging con Logback @Transactional en métodos de servicio que escriben a través de Panache o repositorios Validar entrada antes de persistencia o publicación de mensajes Seguimiento de eventos para escenarios de éxito/error Publicación asíncrona de mensajes Camel Patrón de Contexto de Logging Personalizado (Logback) @ApplicationScoped public class ProcessingService { public void processDocument (Document doc) { LogContext logContext = CustomLog.getCurrentContext(); try ( SafeAutoCloseable ignored = CustomLog.startScope(logContext)) { logContext.put( "documentId" , doc.getId().toString()); logContext.put( "documentType" , doc.getType()); logContext.put( "userId" , SecurityContext.getUserId()); log.info( "Iniciando procesamiento de documento" ); processInternal(doc); log.info( "Procesamiento de documento completado" ); } catch (Exception e) { log.error( "Error en el procesamiento de documento" , e); throw e; } } } Configuración de Logback (logback.xml): < configuration > < appender name = "CONSOLE" class = "ch.qos.logback.core.ConsoleAppender" > < encoder class = "net.logstash.logback.encoder.LogstashEncoder" > < includeContext > true </ includeContext > < includeMdc > true </ includeMdc > </ encoder > </ appender > < logger name = "com.example" level = "INFO" /> < root level = "WARN" > < appender-ref ref = "CONSOLE" /> </ root > </ configuration > Patrón de Servicio de Eventos @Slf4j @ApplicationScoped @RequiredArgsConstructor public class EventService { private final EventRepository eventRepository; private final ObjectMapper objectMapper; public void createSuccessEvent (Object payload, String eventType) { Objects.requireNonNull(payload, "El payload no puede ser null" ); Event event = new Event (); event.setType(eventType); event.setStatus(EventStatus.SUCCESS); event.setPayload(serializePayload(payload)); event.setTimestamp(Instant.now()); eventRepository.persist(event); log.info( "Evento de éxito creado: {}" , eventType); } public void createErrorEvent (Object payload, String eventType, String errorMessage) { Objects.requireNonNull(payload, "El payload no puede ser null" ); if (errorMessage == null || errorMessage.isBlank()) { throw new IllegalArgumentException ( "El mensaje de error no puede estar en blanco" ); } Event event = new Event (); event.setType(eventType); event.setStatus(EventStatus.ERROR); event.setErrorMessage(errorMessage); event.setPayload(serializePayload(payload)); event.setTimestamp(Instant.now()); eventRepository.persist(event); log.error( "Evento de error creado: {} - {}" , eventType, errorMessage); } private String serializePayload (Object payload) { try { return objectMapper.writeValueAsString(payload); } catch (JsonProcessingException e) { throw new IllegalStateException ( "Error al serializar el payload del evento" , e); } } } Publicación de Mensajes Camel (RabbitMQ) @Slf4j @ApplicationScoped @RequiredArgsConstructor public class BusinessRulesPublisher { private final ProducerTemplate producerTemplate; public void publishSync (BusinessRulesPayload payload) { producerTemplate.sendBody( "direct:business-rules-publisher" , payload ); } } Configuración de Ruta Camel: @ApplicationScoped public class BusinessRulesRoute extends RouteBuilder { @ConfigProperty(name = "camel.rabbitmq.queue.business-rules") String businessRulesQueue; @ConfigProperty(name = "rabbitmq.host") String rabbitHost; @ConfigProperty(name = "rabbitmq.port") Integer rabbitPort; @Override public void configure () { from( "direct:business-rules-publisher" ) .routeId( "business-rules-publisher" ) .log( "Publicando mensaje en RabbitMQ: ${body}" ) .marshal().json(JsonLibrary.Jackson) .toF( "spring-rabbitmq:%s?hostname=%s&portNumber=%d" , businessRulesQueue, rabbitHost, rabbitPort); } } Rutas Camel Direct (En Memoria) @ApplicationScoped public class DocumentProcessingRoute extends RouteBuilder { @Override public void configure () { onException(ValidationException.class) .handled( true ) .to( "direct:validation-error-handler" ) .log( "Error de validación: ${exception.message}" ); from( "direct:process-document" ) .routeId( "document-processing" ) .log( "Procesando documento: ${header.documentId}" ) .bean(DocumentValidator.class, "validate" ) .bean(DocumentTransformer.class, "transform" ) .choice() . when (header( "documentType" ).isEqualTo( "INVOICE" )) .to( "direct:process-invoice" ) . when (header( "documentType" ).isEqualTo( "CREDIT_NOTE" )) .to( "direct:process-credit-note" ) .otherwise() .to( "direct:process-generic" ) .end(); } } Procesamiento de Archivos Camel @ApplicationScoped public class FileMonitoringRoute extends RouteBuilder { @ConfigProperty(name = "file.input.directory") String inputDirectory; @ConfigProperty(name = "file.processed.directory") String processedDirectory; @ConfigProperty(name = "file.error.directory") String errorDirectory; @Override public void configure () { from( "file:" + inputDirectory + "?move=" + processedDirectory + "&moveFailed=" + errorDirectory + "&delay=5000" ) .routeId( "file-monitor" ) .log( "Procesando archivo: ${header.CamelFileName}" ) .to( "direct:process-file" ); } } Estructura de API REST @Path("/api/documents") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @RequiredArgsConstructor public class DocumentResource { private final DocumentService documentService; @GET public Response list ( @QueryParam("page") @DefaultValue("0") int page, @QueryParam("size") @DefaultValue("20") int size) { List<Document> documents = documentService.list(page, size); return Response.ok(documents).build(); } @POST public Response create ( @Valid CreateDocumentRequest request, @Context UriInfo uriInfo) { Document document = documentService.create(request); URI location = uriInfo.getAbsolutePathBuilder() .path(String.valueOf(document.id)) .build(); return Response.created(location).entity(DocumentResponse.from(document)).build(); } @GET @Path("/{id}") public Response getById ( @PathParam("id") Long id) { return documentService.findById(id) .map(DocumentResponse::from) .map(Response::ok) .orElse(Response.status(Response.Status.NOT_FOUND)) .build(); } } Patrón de Repositorio (Panache Repository) @ApplicationScoped public class DocumentRepository implements PanacheRepository <Document> { public List<Document> findByStatus (DocumentStatus status, int page, int size) { return find( "status = ?1 order by createdAt desc" , status) .page(page, size) .list(); } public Optional<Document> findByReferenceNumber (String referenceNumber) { return find( "referenceNumber" , referenceNumber).firstResultOptional(); } } Capa de Servicio con Transacciones @ApplicationScoped @RequiredArgsConstructor public class DocumentService { private final DocumentRepository repo; private final EventService eventService; @Transactional public Document create (CreateDocumentRequest request) { Document document = new Document (); document.setReferenceNumber(request.referenceNumber()); document.setDescription(request.description()); document.setStatus(DocumentStatus.PENDING); document.setCreatedAt(Instant.now()); repo.persist(document); eventService.createSuccessEvent(document, "DOCUMENT_CREATED" ); return document; } } DTOs y Validación public record CreateDocumentRequest ( @NotBlank @Size(max = 200) String referenceNumber, @NotBlank @Size(max = 2000) String description, @NotNull @FutureOrPresent Instant validUntil, @NotEmpty List< @NotBlank String> categories) {} public record DocumentResponse (Long id, String referenceNumber, DocumentStatus status) { public static DocumentResponse from (Document document) { return new DocumentResponse (document.getId(), document.getReferenceNumber(), document.getStatus()); } } Mapeo de Excepciones @Provider public class ValidationExceptionMapper implements ExceptionMapper <ConstraintViolationException> { @Override public Response toResponse (ConstraintViolationException exception) { String message = exception.getConstraintViolations().stream() .map(cv -> cv.getPropertyPath() + ": " + cv.getMessage()) .collect(Collectors.joining( ", " )); return Response.status(Response.Status.BAD_REQUEST) .entity(Map.of( "error" , "validation_error" , "message" , message)) .build(); } } Operaciones Asíncronas con CompletableFuture @Slf4j @ApplicationScoped @RequiredArgsConstructor public class FileStorageService { private final S3Client s3Client; private final ExecutorService executorService; public CompletableFuture<StoredDocumentInfo> uploadOriginalFile ( InputStream inputStream, long size, LogContext logContext, InvoiceFormat format) { return CompletableFuture.supplyAsync(() -> { try ( SafeAutoCloseable ignored = CustomLog.startScope(logContext)) { String path = generateStoragePath(format); PutObjectRequest request = PutObjectRequest.builder() .bucket(bucketName) .key(path) .contentLength(size) .build(); s3Client.putObject(request, RequestBody.fromInputStream(inputStream, size)); return new StoredDocumentInfo (path, size, Instant.now()); } catch (Exception e) { log.error( "Error al subir archivo a S3" , e); throw new StorageException ( "Subida fallida" , e); } }, executorService); } } Caché @ApplicationScoped @RequiredArgsConstructor public class DocumentCacheService { private final DocumentRepository repo; @CacheResult(cacheName = "document-cache") public Optional<Document> getById ( @CacheKey Long id) { return repo.findByIdOptional(id); } @CacheInvalidate(cacheName = "document-cache") public void evict ( @CacheKey Long id) {} } Configuración como YAML # application.yml "%dev" : quarkus: datasource: jdbc: url: jdbc:postgresql://localhost:5432/dev_db username: dev_user password: ${DB_PASSWORD} "%test" : quarkus: datasource: jdbc: url: jdbc:h2:mem:test hibernate-orm: database: generation: drop-and-create "%prod" : quarkus: datasource: jdbc: url: ${DATABASE_URL} username: ${DB_USER} password: ${DB_PASSWORD} Health Checks @Readiness @ApplicationScoped @RequiredArgsConstructor public class DatabaseHealthCheck implements HealthCheck { private final AgroalDataSource dataSource; @Override public HealthCheckResponse call () { try ( Connection conn = dataSource.getConnection()) { boolean valid = conn.isValid( 2 ); return HealthCheckResponse.named( "Database connection" ) .status(valid) .build(); } catch (SQLException e) { return HealthCheckResponse.down( "Database connection" ); } } } Dependencias (Maven) < properties >
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 技能推荐。完全免费,持续更新。

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

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