quarkus-patterns
Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing. Use for Java Quarkus backend work with event-driven architectures.
DeepseekModel
キュレーション済みスキル
品質 優秀 · 90
v1.0.0
取得
https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-tr-skills-quarkus-patterns-skill-md&format=skill
ダウンロード .skill
標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name quarkus-patterns description Quarkus 3.x LTS architecture patterns with Camel for messaging, RESTful API design, CDI services, data access with Panache, and async processing. Use for Java Quarkus backend work with event-driven architectures. origin ECC Quarkus Geliştirme Desenleri Apache Camel ile bulut-native, event-driven servisler için Quarkus 3.x mimari ve API desenleri. When to Use JAX-RS veya RESTEasy Reactive ile REST API'leri oluşturma Resource → service → repository katmanlarını yapılandırma Apache Camel ve RabbitMQ ile event-driven desenler uygulama Hibernate Panache, caching veya reaktif akışları yapılandırma Validation, exception mapping veya sayfalama ekleme Dev/staging/production ortamları için profiller kurma (YAML yapılandırma) LogContext ve Logback/Logstash encoder ile özel loglama Async işlemler için CompletableFuture ile çalışma Koşullu akış işleme uygulama GraalVM native derleme ile çalışma How It Works Quarkus servislerinde Resource -> service -> repository akışını CDI scope'ları, @Transactional sınırları, Panache/Hibernate veri erişimi ve Camel/RabbitMQ entegrasyonlarıyla birlikte uygulayın. Aşağıdaki örnekler event üretimi, dosya işleme, özel logging context ve async yayınlama için kopyalanabilir başlangıç noktaları sağlar. Examples Birden Fazla Bağımlılıklı Service Katmanı (Lombok) @Slf4j @ApplicationScoped @RequiredArgsConstructor public class As2ProcessingService { private final InvoiceFlowValidator invoiceFlowValidator; private final EventService eventService; private final DocumentJobService documentJobService; private final BusinessRulesPublisher businessRulesPublisher; private final FileStorageService fileStorageService; public void processFile (Path filePath) throws Exception { LogContext logContext = CustomLog.getCurrentContext(); try ( SafeAutoCloseable ignored = CustomLog.startScope(logContext)) { String structureIdPartner = logContext.get(As2Constants.STRUCTURE_ID); // Koşullu akış mantığı boolean isChorusFlow = Boolean.parseBoolean(logContext.get(As2Constants.CHORUS_FLOW)); log.info( "Is CHORUS_FLOW message: {}" , isChorusFlow); ValidationFlowConfig validationFlowConfig = isChorusFlow ? ValidationFlowConfig.xsdOnly() : ValidationFlowConfig.allValidations(); InvoiceValidationResult invoiceValidationResult = this .invoiceFlowValidator .validateFlowWithConfig(filePath, validationFlowConfig, EInvoiceSyntaxFormat.UBL, logContext); FlowProfile flowProfile = isChorusFlow ? FlowProfile.EXTENDED_CTC_FR : this .invoiceFlowValidator.computeFlowProfile(invoiceValidationResult, invoiceValidationResult.getInvoiceDetails().invoiceFormat().getProfile()); log.info( "Invoice validation completed. Message is valid" ); // CompletableFuture async işlemi try ( InputStream inputStream = Files.newInputStream(filePath)) { CompletableFuture<StoredDocumentInfo> documentInfoCompletableFuture = fileStorageService.uploadOriginalFile(inputStream, invoiceValidationResult.getSize(), logContext, invoiceValidationResult.getInvoiceFormat()); StoredDocumentInfo documentInfo = documentInfoCompletableFuture.join(); log.info( "File uploaded successfully: {}" , documentInfo.getPath()); if (StringUtils.isBlank(documentInfo.getPath())) { String errorMsg = "File path is empty after upload" ; log.error(errorMsg); this .eventService.createErrorEvent(documentInfo, "FILE_UPLOAD_FAILED" , errorMsg); throw new As2ServerProcessingException (errorMsg); } this .eventService.createSuccessEvent(documentInfo, "PERSISTENCE_BLOB_EVENT_TYPE" ); String originalFileName = documentInfo.getOriginalFileName(); BusinessRulesPayload payload = this .documentJobService.createDocumentAndJobEntities( documentInfo, originalFileName, structureIdPartner, flowProfile, invoiceValidationResult.getDocumentHash()); // Async Camel yayınlama businessRulesPublisher.publishAsync(payload); this .eventService.createSuccessEvent(payload, "BUSINESS_RULES_MESSAGE_SENT" ); } } } } Temel Desenler: Constructor injection için Lombok üzerinden @RequiredArgsConstructor Logback loglama için @Slf4j try-with-resources ile kapsamlı LogContext Runtime parametrelerine dayalı koşullu akış mantığı Async işlemler için .join() ile CompletableFuture Başarı/hata senaryoları için event takibi Async Camel mesaj yayınlama Özel Loglama Bağlamı Deseni (Logback) @ApplicationScoped public class ProcessingService { public void processDocument (Document doc) { LogContext logContext = CustomLog.getCurrentContext(); try ( SafeAutoCloseable ignored = CustomLog.startScope(logContext)) { // Tüm log ifadelerine bağlam ekle logContext.put( "documentId" , doc.getId().toString()); logContext.put( "documentType" , doc.getType()); logContext.put( "userId" , SecurityContext.getUserId()); log.info( "Starting document processing" ); // Bu kapsam içindeki tüm loglar bağlamı devralır processInternal(doc); log.info( "Document processing completed" ); } catch (Exception e) { log.error( "Document processing failed" , e); throw e; } } } Logback Yapılandırması (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 > Event Service Deseni @Slf4j @ApplicationScoped @RequiredArgsConstructor public class EventService { private final EventRepository eventRepository; private final ObjectMapper objectMapper; public void createSuccessEvent (Object payload, String eventType) { Objects.requireNonNull(payload, "Payload cannot be 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( "Success event created: {}" , eventType); } public void createErrorEvent (Object payload, String eventType, String errorMessage) { Objects.requireNonNull(payload, "Payload cannot be null" ); if (errorMessage == null || errorMessage.isBlank()) { throw new IllegalArgumentException ( "Error message cannot be blank" ); } 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( "Error event created: {} - {}" , eventType, errorMessage); } private String serializePayload (Object payload) { try { return objectMapper.writeValueAsString(payload); } catch (JsonProcessingException e) { throw new IllegalStateException ( "Failed to serialize event payload" , e); } } } Camel Mesaj Yayınlama (RabbitMQ) @ApplicationScoped @RequiredArgsConstructor public class BusinessRulesPublisher { private final ProducerTemplate producerTemplate; @ConfigProperty(name = "camel.rabbitmq.queue.business-rules") String businessRulesQueue; public void publishAsync (BusinessRulesPayload payload) { producerTemplate.asyncSendBody( "direct:business-rules-publisher" , payload ); log.info( "Message published to business rules queue: {}" , payload.getDocumentId()); } public void publishSync (BusinessRulesPayload payload) { producerTemplate.sendBody( "direct:business-rules-publisher" , payload ); } } Camel Route Yapılandırması: @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( "Publishing message to RabbitMQ: ${body}" ) .marshal().json(JsonLibrary.Jackson) .toF( "spring-rabbitmq:%s?hostname=%s&portNumber=%d" , businessRulesQueue, rabbitHost, rabbitPort); } } Camel Direct Route'ları (Bellek İçi) @ApplicationScoped public class DocumentProcessingRoute extends RouteBuilder { @Override public void configure () { // Hata yönetimi onException(ValidationException.class) .handled( true ) .to( "direct:validation-error-handler" ) .log( "Validation error: ${exception.message}" ); // Ana işleme route'u from( "direct:process-document" ) .routeId( "document-processing" ) .log( "Processing document: ${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(); from( "direct:validation-error-handler" ) .bean(EventService.class, "createErrorEvent" ) .log( "Validation error handled" ); } } Camel Dosya İşleme @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( "Processing file: ${header.CamelFileName}" ) .to( "direct:process-file" ); from( "direct:process-file" ) .bean(As2ProcessingService.class, "processFile" ) .log( "File processing completed" ); } } Camel Bean Çağrısı @ApplicationScoped public class InvoiceRoute extends RouteBuilder { @Override public void configure () { from( "direct:invoice-validation" ) .bean(InvoiceFlowValidator.class, "validateFlowWithConfig" ) .log( "Validation result: ${body}" ); from( "direct:persist-and-publish" ) .bean(DocumentJobService.class, "createDocumentAndJobEntities" ) .bean(BusinessRulesPublisher.class, "publishAsync" ) .bean(EventService.class, "createSuccessEvent(${body}, 'PUBLISHED')" ); } } REST API Yapısı @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(); } } Repository Deseni (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(); } public long countByStatusAndDate (DocumentStatus status, LocalDate date) { return count( "status = ?1 and createdAt >= ?2" , status, date.atStartOfDay()); } } Transaction'lı Service Katmanı @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; } public Optional<Document> findById (Long id) { return repo.findByIdOptional(id); } public List<Document> list ( int page, int size) { return repo.findAll() .page(page, size) .list(); } } DTO'lar ve Validation 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()); } } Exception Eşleme
このスキルを起動するキーワード。クリックでコピーできます。
このスキルにはトリガーワードがありません。
ダウンロードした .skill に含まれるフィールド。
| フィールド | 説明 |
|---|---|
| format | フォーマット識別子(skill/v1) |
| skill_id | スキル固有 ID |
| name | スキル名 |
| version | バージョン |
| description | 説明 |
| category | カテゴリ(配列) |
| trigger_words | トリガーワード |
| tags | タグ |
| source | ソース |
| source_url | ソース URL(本ページ) |
| exported_at | エクスポート日時(ダウンロード毎) |
| system_prompt | システムプロンプト本文 |
| model_config | モデル設定:provider / model / temperature / max_tokens / top_p |
| examples | サンプル |
| install_guide | 各プラットフォームの導入説明(Coze / Dify / Claude / カスタム) |