Ana içeriğe geç

1.1. Framework#

Uygulama geliştirilirken başta Spring olmak üzere third-party temel bileşenleri gereksinimlere göre özelleştirilmiş olarak hizmete sunan altyapı bileşenidir. Actuator, configuration, context, crypto, exception, initializer, service, swagger, util gibi temel bileşenleri içermektedir. Bu altyapı bileşeni ihtiyaçlar doğrultusunda genişletilebilmektedir.

Actuator#

import tr.com.havelsan.javarch.actuator.annotation.HvlActuatorService;

@HvlActuatorService(name = "hvlBpmnIntegrationRestService", groupName = "hvlBpmnIntegration")

Uygulamada rest uçların ve modellerin bilgilerinin dönülmesini sağlamaktadır. Bu bilgileri alabilmek için ilk olarak ip:port/actuator adresine istek atılmalıdır.

Servis bilgilerinin alınabilmesi için aşağıdaki uçların kullanılması gerekmektedir.

Service Endpoints

Model bilgilerinin alınabilmesi için aşağıdaki uçların kullanılması gerekmektedir.

Model Endpoints

TS-Generator ürünümüz type-script sınıflarını üretmek için yukaridaki uçları kullanmaktadır. Java temel annotation, model ve servis sınıflarının type-script'i üretilmektedir.


drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-management.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-actuator'

Actuator Environment Gizleyici#

/actuator/env pathi üzerinden görüntülenen, uygulamanın kullandığı ortam değişkenlerinde, şifre bilgileri gibi görünmesi istenmeyen kritik bilgi olabilir. Bu bilgileri gizlemek için EKSEN tarafından sağlanan konfigürasyonlar kullanılabilir. application-management.yml dosyasından sağlanan konfigürasyon bilgileri aşağıdaki gibidir.

hvl:
  management:
    endpoint:
      env:
        sanitizer:
          key-regexes:
            - .*[Pp]assword$
            - .*[Ss]ecret$
            - hvl.core.security.web.credentials

hvl.management.endpoint.env.sanitizer.key-regexes: Gizlenmek istenen uygulama konfigürasyonlarının regex olarak key bilgisidir. Varsayilan olarak password ve secret kelimeleri ilen biten key'leri gizlemektedir.

Örnek Çıktı:

"spring.datasource.url": {
"value": "jdbc:postgresql://hvlpostgresmultipledatabases:5432/hvl",
"origin": "Config Server file:/var/lib/config-server/framework/spring/application-database-datasource.yml:14:10"
},
"spring.datasource.username": {
"value": "hvl",
"origin": "Config Server file:/var/lib/config-server/framework/spring/application-database-datasource.yml:15:15"
},
"spring.datasource.password": {
"value": "******",
"origin": "Config Server file:/var/lib/config-server/framework/spring/application-database-datasource.yml:16:15"
},

Configuration#

import tr.com.havelsan.javarch.configuration.HvlBaseConfiguration;
import org.springframework.context.annotation.Configuration;

@Configuration
public class Configuration extends HvlBaseConfiguration {

}

Temel konfigurasyon sınıfı sunulmaktadır. Bu sınıftan türeyen sınıflar context'e dahil edildiğinde log atılmaktadır. Aynı zamanda tarama işlemlerinde sadece konfigurasyon taranması için ayraç olarak kullanılabilmektedir.

Profile bağlı tarama yapabilmek için sağlanan HvlProfileComponentScanFilter sınıfı bulunmaktadır. Bu sınıf kullanılarak sadece @Profile içeren konfigürasyon sınıfları taranabilmektedir.

@Configuration
@ComponentScan(basePackages = {HvlLogServerConfigurationConstant.BASE_PACKAGE},
        useDefaultFilters = false,
        includeFilters = {
                @ComponentScan.Filter(type = FilterType.CUSTOM, value = HvlProfileComponentScanFilter.class),
        }
)
public class HvlLogServerConfiguration extends HvlBaseConfiguration {
}

Yaml veya properties dosyalarından konfigurasyonlarını ayrıştırmak için HvlPropertyParser sınıfı kullanılmaktadır. Bu sınıf sayesinde iç içe konfigurasyon verilmesi sağlanmaktadır.

service:
  url: ${service.url:${default.url}}


Konfigurasyonları jasypt kütüphanesi ile şifreleme yeteneği bulunmaktadır. Şifreleme yeteneği sağlanan algoritma türleri: HvlConfigurationEncryptorType

  • PBES
  • STANDART_PBES
  • POOLED_PBES
  • ASYMETRIC

NOT: Şifreleme işlemi StringEncryptor ile yapılmaktadır. Jasypt standartları ile şifreleme işlemi yapmak isterseniz StringEncryptor sınıfı kullanılabilir.


drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-instance.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-configuration'
group: 'tr.com.havelsan.framework', name: 'hvl-configuration-encryptor'

Context#

Uygulama içeriğinde Bean, Environment ve System enviroment'a ulaşmayı sağlamaktadır.

2 şekilde kullanılabilmektedir:

  • DI (Dependency Injection) ile kullanılabilir.
import org.springframework.stereotype.Component;
import tr.com.havelsan.javarch.context.HvlApplicationContext;

@Component
public class SampleService {

    private final HvlApplicationContext applicationContext;

    public SampleService(HvlApplicationContext applicationContext) {
        this.applicationContext = applicationContext;
    }

    public void test() {
        applicationContext.getBean(SampleService.class);
        applicationContext.getEnvironment();
        applicationContext.getSystemLocale();
    }

}
  • Bean olmayan sınıflar statik olarak Holder üzerinden kullanılabilir.
import tr.com.havelsan.javarch.context.holder.HvlApplicationContextHolder;

import java.util.Objects;

public final class SampleService {

    public static SampleService INSTANCE;

    public static SampleService getInstance() {
        if (Objects.isNull(INSTANCE)) {
            INSTANCE = new SampleService();
        }
        return INSTANCE;
    }

    public static void test() {
        HvlApplicationContextHolder.getBean(SampleService.class);
        HvlApplicationContextHolder.getEnvironment();
        HvlApplicationContextHolder.getSystemLocale();
    }
}

Uygulama içerisinde Bean'ler arası event mekanizmasına destek sağlamaktadır. Bunun için HvlApplicationEventListener ve HvlApplicationEventPublisher sınıfları kullanılmaktadır.


drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-hvl-context.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-context'

Crypto#

Uygulamada şifreleme işlemlerinde kullanılmaktadır. (Örneğin veritabanı kolonlarında şifreleme vb.) Güncel sürümde AES destek verilmektedir.

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.context.holder.HvlApplicationContextHolder;
import tr.com.havelsan.javarch.crypto.data.HvlCryptoType;
import tr.com.havelsan.javarch.crypto.service.HvlCryptoServiceBuilder;

/**
 * @author javarch
 */
@SpringBootApplication
public class HvlSampleApplication {


    public static void main(String[] args) {
        SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);

        final HvlCryptoService aesCryptoService =
                HvlCryptoServiceBuilder.create(HvlCryptoType.AES).setKey("mySecretKey").build();
        final String encryptText = aesCryptoService.encrypt("test");
        final String decryptText = aesCryptoService.decrypt(encryptText);
    }
}

drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-crypto'

Exception#

Altyapıdan checked ve unchecked exception kullanımı sağlanmaktadır. Bu sınıflar HvlCheckedException ve HvlUncheckedException sınıflarıdır.

Exception sınıfları içerisinde HvlErrorDetail nesnesi bulunmaktadır. Bir isteğin yaşam döngüsü boyunca hata alması durumunda HvlErrorDetail alanı vasıtası ile bilgi dönülmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-exception'

Initializer#

Uygulamaya ilklendirme özelliği kazandırmaktadır. İlklendirme belirli bir path üzerindeki script dosyaları ile yapılabildiği gibi aynı zamanda git üzerinden de script dosyalarını okuyup ilklendirme yapılabilmeyi sağlamaktadır.


drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-hvl-data.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-initializer'

Bağımlılık eklendikten sonra git ilklendirmesi için HvlInitializerGitProperties sınıfından extend edip propertyler bağlanarak kullanıma hazır hale getirilebilir.

@ConfigurationProperties(prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX)
public class HvlRToolReportInitializerGitProperties extends HvlInitializerGitProperties {
}

Git kullanmadan yalnızca path üzerinden ilklendirme özelliği kazandırılmak isteniyorsa aşağıdaki örnekteki gibi HvlInitializerProperties sınıfı exten edilip propertyler bağlanabilir.

@ConfigurationProperties(prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX)
public class HvlRToolReportInitializerProperties extends HvlInitializerProperties {
}

Sonrasında aşağıdaki gibi HvlInitializerGitServiceImpl sınıfından extend eden bir ilklendirme komponenti ile ilklendirme süreci tamamlanabilir.

@Component
@ConditionalOnProperty(
        prefix = HvlEnableRToolConfigurationConstant.REPORT_INITIALIZER_PROPERTIES_PREFIX,
        name = HvlRToolReportInitializerProperties.ENABLED_PROPERTY_NAME,
        havingValue = BooleanUtils.TRUE
)
public class HvlRToolReportInitializer
        extends HvlInitializerGitServiceImpl implements InitializingBean {

    private final HvlRToolReportInitializerProperties reportInitializerProperties;

    private final HvlRToolBatchedReportImportProcessor batchedReportImportProcessor;

    public HvlRToolReportInitializer(
            HvlRToolReportInitializerGitProperties reportInitializerGitProperties,
            HvlRToolReportInitializerProperties reportInitializerProperties,
            HvlRToolBatchedReportImportProcessor batchedReportImportProcessor) {
        super(reportInitializerGitProperties);
        this.reportInitializerProperties = reportInitializerProperties;
        this.batchedReportImportProcessor = batchedReportImportProcessor;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        initialize();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected void doInit(String path) {
        final Path batchedReportImportFilePath = Path.of(path)
                .resolve(this.reportInitializerProperties.getBatchedReportImportFilePath());
        batchedReportImportProcessor.importReportTemplatesFrom(batchedReportImportFilePath)
                .block();
    }
}

Service#

Uygulamadan dışarıya açılan servis uçları (Rest Controller) buradan konfigure edilmektedir. (Örneğin serialization kuralları, gzip, cors, cookie vb.)

HvlHttpHeader sınıfında altyapının isteklerde (Http request) ve cevaplarda (Http response) kullandığı özel 'header' alanları bulunmaktadır.

Uygulamada istekle (Http request) ilgili bilgilere anlık ulaşabilmek için HvlServiceContext ve HvlServiceContextHolder sınıfları bulunmaktadır.

HvlServiceContextHolder kullanım örneği:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import tr.com.havelsan.javarch.service.context.holder.HvlServiceContextHolder;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author javarch
 */
@SpringBootApplication
public class HvlSampleApplication {

    public static void main(String[] args) {
        SpringApplication.run(new Class[]{HvlSampleApplication.class}, args);

        final HttpServletRequest servletRequest = HvlServiceContextHolder.getServletRequest();
        final HttpServletResponse servletResponse = HvlServiceContextHolder.getServletResponse();
    }

}

HvlServiceContext kullanım örneği:

import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.service.context.HvlServiceContext;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Service
public class SampleService {

    private final HvlServiceContext serviceContext;

    public SampleService(HvlServiceContext serviceContext) {
        this.serviceContext = serviceContext;
    }

    public void test() {
        final HttpServletRequest servletRequest = serviceContext.getServletRequest();
        final HttpServletResponse servletResponse = serviceContext.getServletResponse();
    }

}

Uygulamadan dışarıya açılan servis uçlarının (Rest Controller) döneceği verileri standartlaştırmak için HvlResponse ve HvlResponseEntity sınıfları bulunmaktadır. Bu sınıflar sayesinde payload, header, errorDetail gibi alanlar istemciye standart olarak dönülmektedir. HvlResponseEntity objelerin byte array gibi yapılarda geriye dönülmesinin istendiği durumlarda kullanılmaktadır.

import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tr.com.havelsan.javarch.service.data.HvlResponse;
import tr.com.havelsan.javarch.service.data.HvlResponseEntity;

@RestController
@RequestMapping("/sample")
public class SampleController {

    @GetMapping(path = "/response", produces = MediaType.APPLICATION_JSON_VALUE)
    public HvlResponse<String> response() {
        return new HvlResponse<>("Response sample");
    }

    @GetMapping(path = "/response-entity", produces = MediaType.APPLICATION_JSON_VALUE)
    public HvlResponseEntity<String> responseEntıty() {
        return new HvlResponseEntity<>("Response entity sample");
    }

}

Uygulamadan dışarıya açılan servis uçlarının (Rest Controller) hata fırlatması (throw) durumunda hataya özgü HttpStatus bilgisini cevaba (Http response) eklemeyi sağlayan yapı bulunmaktadır. Bu yetenek @HvlExceptionHttpStatus anotasyonu ile sağlanmaktadır.

import org.springframework.http.HttpStatus;
import tr.com.havelsan.javarch.exception.HvlCheckedException;
import tr.com.havelsan.javarch.exception.model.HvlErrorDetail;
import tr.com.havelsan.javarch.service.annotation.HvlExceptionHttpStatus;

@HvlExceptionHttpStatus(code = HttpStatus.BAD_REQUEST)
public class SampleInvalidRequestException extends HvlCheckedException {

    public static final String ERROR_CODE = "code";

    public static final String ERROR_MESSAGE = "message";

    public SampleInvalidRequestException() {
        super(ERROR_MESSAGE, new HvlErrorDetail(ERROR_CODE, ERROR_MESSAGE));
    }

    public SampleInvalidRequestException(HvlErrorDetail errorDetail) {
        super(errorDetail);
    }

}

HvlRestExceptionHandler sınıfı ile sistemde handle edilen veya edilmeyen hatalar filtrelenip gerekli standartlara göre istemciye dönülmektedir. (HvlResponse ve HvlResponseEntity olarak) Burada geliştirici tarafında yutulan hatalar ele alınmamaktadır.

HvlCookieUtil sınıfı ile 'cookie' ile ilgili hizmetler sunulmaktadır. Örnek kullanım:

import org.springframework.stereotype.Service;
import tr.com.havelsan.javarch.service.configuration.properties.HvlCookieProperties;
import tr.com.havelsan.javarch.service.context.HvlServiceContext;
import tr.com.havelsan.javarch.service.util.HvlCookieUtil;

@Service
public class SampleService {

    private final HvlServiceContext serviceContext;

    public SampleService(HvlServiceContext serviceContext) {
        this.serviceContext = serviceContext;
    }

    public void test() {
        HvlCookieUtil.addCookie(serviceContext.getServletResponse(),
                "cookieName",
                "cookieValue",
                new HvlCookieProperties());
    }

}

ÖNERİ: Bean kullanımlarında servis arayüz sınıflarında @Validated ve @Valid annotationları kullanılmalıdır. Arayüz içerisindeki metotlara da gerekli validasyon annotationları konulmalıdır. Böylece metot içerisindeki iş mantığı çalışmadan ve kaynak tüketmeden önce validasyondan geri döner.

import org.springframework.validation.annotation.Validated;
import tr.com.havelsan.javarch.data.commons.pageable.HvlPage;
import tr.com.havelsan.javarch.samples.jpa.data.entity.HvlJpaSample;
import tr.com.havelsan.javarch.samples.jpa.data.model.HvlJpaSampleModel;
import tr.com.havelsan.javarch.samples.jpa.data.model.query.HvlJpaSampleQueryModel;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;
import java.util.List;

@Validated
public interface HvlSampleService {

    HvlJpaSampleModel save(@Valid @NotNull HvlJpaSampleModel sampleModel);

    HvlJpaSampleModel update(@Valid @NotNull HvlJpaSampleModel sampleModel);

    void deleteById(@NotNull @Positive Long id);

    List<HvlJpaSampleModel> getList();

    List<HvlJpaSampleModel> queryList(HvlJpaSampleQueryModel sampleQueryModel);

    List<HvlJpaSampleModel> queryList(HvlJpaSampleQueryModel queryModel, String locale);

    HvlPage<HvlJpaSampleModel> queryPage(HvlJpaSampleQueryModel sampleQueryModel);

    List<HvlJpaSample> getAllSample();

    void saveAll();

    void updateAll();

    void deleteAll(List<HvlJpaSample> entities);
}

drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-hvl-service.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-service'

Request Loglama#

Eksen, backend uygulamasına gelen isteklerin kafka, fluentd, elasticsearch pipeline'ı ile depolanmasını sağlar.

Bunu yaparken aşağıdaki başlıca istatistikler toplanabilir:

  • İsteğin UI üzerinde hangi ekrandan geldiği
  • İsteğin gerçekleşme süresi
  • Ip adresi
  • Backend uygulamasının jvm istatistikleri
  • Oturumdaki kullanıcı adı
  • Thread bilgileri

Konfigürasyonlar yapılarak toplanan bilgiler arttırılabilir, bu durumda performans kayıpları göz önünde bulundurulmalıdır.

application-hvl-service.yml içerisinden config-server vasıtasıyla varsayılan olarak gelen ayarlar aşağıdaki gibidir.

hvl:
  request-logger:
    enabled: ${REQUEST_LOGGER_ENABLED:false}
    source-url-request-header: ${REQUEST_LOGGER_SOURCE_URL_HEADER:Hvl-Source-Request-Path}
    logger-text: ${REQUEST_LOGGER_LOGGER_TEXT:log}
    application-name: ${REQUEST_LOGGER_APP_NAME:eksen}
    application-type: ${REQUEST_LOGGER_APP_TYPE:tomcat}
    include-list: ${REQUEST_LOGGER_INCLUDE_LIST:""}
    context-name: ${REQUEST_LOGGER_CONTEXT_NAME:""}
    pool-name: ${REQUEST_LOGGER_POOL_NAME:eksen}

hvl.request-logger.enabled: Request loglamanın devreye girmesini sağlar.

hvl.request-logger.source-url-request-header: UI tarafından hangi ekranda işlem yapıldığının gönderildiği header bilgisidir.

hvl.request-logger.logger-text: Loglanan verilerdeki log ismidir.

hvl.request-logger.application-name: Loglanan verilerdeki uygulama adı bilgisidir.

hvl.request-logger.application-type: Loglanan verilerdeki uygulama tipi bilgisidir.

hvl.request-logger.include-list: Loglanacak sistemsel verileri loglama dahil etmek için kullanılır. Her bir değerin metrik toplamak için performans düşüreceği göz önünde bulundurulmalıdır. Alabileceği değerler: class, gc, memory, os, jvmProps, thread, hikari, env, tomcat, unix, disk

hvl.request-logger.context-name: Loglanan verilerdeki context adı bilgisidir.

hvl.request-logger.pool-name: Loglanan verilerdeki pool adı bilgisidir.

Loglanacak request'ler kafka üzerinden elasticsearch'e gönderildiği için uygulamanın log4j2.yml dosyalarına aşağıdaki gibi eklemeler yapılmalıdır.

Appenders altına Kafka appender'i eklenmelidir.

Configuration:
  appenders:
    Kafka:
      name: Kafka-true
      topic: javalt-request-logs
      syncSend: false
      JsonLayout:
        charset: UTF-8
        properties: true
        KeyValuePair:
          - key: indexName
            value: request-logs-\${spring:spring.application.name}
      property:
        - name: "bootstrap.servers"
          value: \${spring:spring.kafka.bootstrap-servers}

Dikkat

Eğer uygulamanın herhangi bir veritabanı bağımlılığı yoksa aşağıdaki şekilde HibernateJpaAutoConfiguration ve DataSourceAutoConfiguration sınıfları exclude edilmelidir.

spring:
  autoconfigure:
    exclude:
      - org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration
      - org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration

Uyarı

Kafka appender'i eklendiğinde uygulama kafka'ya bağımlı halecektir. Kafka appender kullanılmak istenmediği durumlarda loglar fluentd'ye farklı bir yöntem ile iletilmelidir.

Appender eklendikten sonra request loglarının kafkaya gönderilmesini sağlamak için loggers altına aşağıdaki ekleme yapılmalıdır.

Loggers:
  logger:
    - name: log
      level: info
      additivity: false
      AppenderRef:
        - ref: Console
        - ref: RollingFile
        - ref: Kafka-\${spring:hvl.core.kafka.support.enabled}

Yukarıdaki örnekte name: log kısmı önemlidir ve değiştirilmemelidir.

  • Request loglaması yapılan sınıfta kullanılan logger name değeri log'dur.
  • ref: Kafka-\${spring:hvl.core.kafka.support.enabled} kısmı ise, yukarıda tanımladığımız Kafka-true appender'ının kullanılacağını gösterir. Böylece loglanacak request'ler kafka'ya yazılmış olacaktır. Uygulama konfigürasyonlarından gelen hvl.core.kafka.support.enabled değerine göre kafkaya gönderim sağlanmaktadır. Bu değer false gelirse request logları kafkaya yazılmayacaktır.

Authorization için kullanılan log4j2 konfigürasyonuna buradan ulaşılabilir.

Yukarıdaki konfigürasyonlar yapıldıktan sonra Kafka appender içerisindeki topic'e loglar gönderilmeye başlayacaktır. hvl-infra içerisindeki fluentd uygulaması, varsayılan olarak javalt-request-logs topic'ini dinleyecek ve sonrasında elasticsearch'e gönderecek şekilde konfigüre edilmiştir. Kafka appender içerisindeki indexName bilgisine göre elasticsearch üzerinde index oluşacaktır.

UI'dan gelen header bilgisi hvl.request-logger.source-url-request-header alanındaki değer ile (varsayılan değer Hvl-Source-Request-Path) eşleştiği takdirde, elasticsearch üzerinde contextMap.requestedClientUrl alanına basılacaktır.

Kibana örneği aşağıdaki gibidir:

Kibana

Uygulama Mesaj Context#

UI'dan atılan istekler sonucunda backend tarafında yapılan işlemlerin toplu bir şekilde HvlResponse içerisinde dönülmesi sağlanmaktadır.

Örneğin; UI üzerinden rest ile A servisi çağırıldığını varsayalım, A servisi içerisinde yapılan işlemler için mesaj context'ine mesajlar eklendi ve rest ile B servisi çağırıldı. B servisi de aynı şekilde kendi işlemleri için mesaj context'ine mesajlarını ekledi. Bu işlemler sonucunda UI'a dönen HvlResponse nesnesi içerisinde messageMap alanında hem A hem de B servisinden eklenen mesajlar bulunacaktır.

Kullanım için EKSEN altyapısından sağlanan HvlWebMessageEmitter sınıfı inject edilerek kullanılmalıdır.

Uyarı

HvlWebMessageEmitter sınıfı RequestScope olarak çalışmaktadır.

Uyarı

HvlWebMessageEmitter'a eklenen mesajlar ve HvlResponse arasındaki işlemler EKSEN tarafından sağlanan message converterlar ve feign decoder'lar üzerinden yapıldığı için, RestClient veya RestTemplate gibi yapılarla manuel istek atıldığı durumlarda message converter olarak HvlMappingJackson2HttpMessageConverter kullanılmalıdır.

Aşağıdaki şekillerde mesaj context'ine ekleme yapılabilir.

webMessageEmitter.addMessages(Level.INFO, List.of("test message", "test message 2", "test message 3"));
webMessageEmitter.addMessage(Level.DEBUG, "test message debug 1");
webMessageEmitter.addMessage(Level.DEBUG, "test message debug 2");
webMessageEmitter.addMessage(Level.ERROR, "test error 1");
webMessageEmitter.addMessage(Level.ERROR, "custom_key", "test error with custom key");

Aşağıda örnek bir servis sınıfı bulunmaktadır.

/**
 * @author javarch
 */
@Service
@HvlTransactionalRollbackForCheckedException
public class HvlBookServiceImpl implements HvlBookService {

    private final HvlBookOperationalManager bookOperationalManager;

    private final HvlBookManager bookManager;

    private final HvlWebMessageEmitter webMessageEmitter;

    public HvlBookServiceImpl(
            HvlBookOperationalManager bookOperationalManager,
            HvlBookManager bookManager,
            HvlWebMessageEmitter webMessageEmitter) {
        this.bookOperationalManager = bookOperationalManager;
        this.bookManager = bookManager;
        this.webMessageEmitter = webMessageEmitter;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void save(@NotNull @Valid HvlBookModel bookModel) {
        bookOperationalManager.save(bookModel);
        webMessageEmitter.addMessage(Level.INFO, "Kayıt eklendi.");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    @Validated(value = {HvlConstraintGroups.ModifyingOperation.class})
    public void update(@NotNull @Valid HvlBookModel bookModel) {
        bookOperationalManager.update(bookModel);
        webMessageEmitter.addMessage(Level.INFO, "Kayıt güncellendi.");
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void deleteByUuid(
            @NotBlank
            @Size(max = HvlPersistableDataConstraint.UUID_SIZE, min = HvlPersistableDataConstraint.UUID_SIZE) String uuid) {
        bookOperationalManager.deleteByUuid(uuid);
        webMessageEmitter.addMessage(Level.INFO, "Kayıt silindi.");
    }

}

Swagger#

Uygulamaya swagger yeteneği kazandırmak için kullanılmaktadır. Cloud ve Boot için destek sağlanmaktadır.


drawing Nasıl konfigüre edilir?

hvl-infra altında bulunan 'application-swagger.yml' dosyasıyla konfigure edilebilmektedir.


drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-swagger'

Util#

Uygulama geliştirirken genel destek sınıfları sunulmaktadır. Destek sınıfları:

  • Dil ve ortak kullanılacak sabitler için HvlCommonConstant, HvlLanguageConstant
  • Sertifika işlemleri için HvlCertificateUtil
  • Cron işlemleri için HvlCronUtil
  • IP ayrıştırma işlemleri için HvlIPUtil
  • String işlemleri için HvlStringUtil

drawing Uygulamaya nasıl eklenir?
group: 'tr.com.havelsan.framework', name: 'hvl-util'

NOT: EKSEN altyapısı kullanılan projelerde bu kütüphaneyi ayrıca sisteme dahil etmeye gerek yoktur. EKSEN altyapısı hvl-util kütüphanesini otomatik olarak sisteme dahil etmektedir.


Ayrıca hvl-util kütüphanesi projeye eklendiğinde aşağıdaki kütüphaneleri de sisteme otomatik olarak ekleyecektir. Bundan dolayı hvl-util, EKSEN altyapısını kullanan projelerin aşağıdaki kütüphaneleri tekrar eklemesine gerek olmayacaktır.

commonsIOVersion=2.15.0
apacheCommonsCollections4Version=4.4
googleGuavaVersion=32.0.1-jre

api(
    [group: 'commons-io', name: 'commons-io', version: commonsIOVersion],
    [group: 'org.apache.commons', name: 'commons-collections4', version: apacheCommonsCollections4Version],
    [group: 'org.apache.commons', name: 'commons-lang3'],
    [group: 'com.google.guava', name: 'guava', version: googleGuavaVersion],
    [group: 'commons-codec', name: 'commons-codec'],
    [group: 'jakarta.servlet', name: 'jakarta.servlet-api'],
    [group: 'org.apache.httpcomponents.client5', name: 'httpclient5'],
)