Ana içeriğe geç

1.4. Genel Yapı ve Paketler#

Framework instance projelerinin genel yapısı 4 temel bileşenden oluşmaktadır.

  • Client
  • Provider
  • Starter
  • Server

Project Structure

Client#

İstemci tarafından erişilecek feign uçlarını içeren pakettir. FeignRestService'ler bu katmanda tanımlanır.

Provider#

Veri sağlanan işlerin yapıldığı katmandır. Database, redis, integration vb. üzerinden veri alışverişi işlemleri bu katmanda yapılır.

Örnek olarak database-provider modüle ait aşağıdaki paketleri içerir;

  • Converter -> Java bean'lerin dönüşümünü sağlamak amacı ile code generator olarak MapStruct kullanılmaktadır.
  • Entity -> Veritabanı tablolarına persistence domain nesnesidir.
  • Generator -> Sorgu kriterlerinin oluşturulmasına yardımcı olan sınıflardır.
  • Logic -> Repository erişimlerinin ve entity-model dönüşümlerinin yapıldığı servisleri içerir.
  • Repository -> Veritabanı işleri için kullanılan arayüzlerdir.

Starter#

Domain ile ilgili logic barındıran katmandır.

Modüle ait aşağıdaki paketleri içerir;

  • Controller -> Rest service implementasyonlarının yapıldığı sınıflardır. RestController'lar bu paket içerisinde yer alır.
  • Logic -> Domain logic içeren servisleri barındırır.

Modül ile ilgili ekstra özelliklere ihtiyaç duyulduğunda customization yapılabilecek olan pakettir. Kullanımı ile ilgili ayrıntılı bilgiye starter üzerinden ulaşılabilir.

Server#

İlgili instance için server'ın ayağa kaldırılması gerekmektedir. Bütün paketleri bir araya getirerek uygulamaya dönüştüren katmandır. Instance'a ait konfigürasyonlar bu katmanda yapılır. Profil ve taranacak olan paketler belirlenir.

Paket Yapıları ve Kullanım Amaçları#

Oluşturulan paket yapıları bir dizi mantıksal ve bütünsel amaç taşımaktadır. Paket yapıları ve kullanım amaçları aşağıdaki gibidir:

package-structure.png

  • client.service rest servis işlemlerini gruplamak ve "Declarative Rest Interface" (Feign) tanımı için kullanılan pakettir. Oluşturlan rest servis uçlarının başka bir ugulama tarafından kullanılması gerekli ise, tanımlanan "Declarative Rest Interface" (Feign) interfaceleri ".jar" olarak bu yapı üzerinden API olarak sunulmalıdır.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Validated
@FeignClient(
        name = "ntfNotificationMessageOperationalRestService",
        path = "/notification-messages",
        url = "${hvl.notification.server.url}"
)
public interface HvlNtfNotificationMessageOperationalRestService {

    @PostMapping(
            consumes = MediaType.APPLICATION_JSON_VALUE,
            produces = MediaType.APPLICATION_JSON_VALUE
    )
    HvlResponse<Void> save(@NotNull @Valid @RequestBody HvlNtfNotificationMessageModel ntfNotificationMessageModel);

}
  • controller rest servis arabirimleri için uygulama paketidir. Bu paket altında yer alan @Controller komponentlerinde en az seviyede kod tutularak yetki ve swagger dokümantasyonu gibi yapıların buraya yazılması önerilir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@RestController
@RequestMapping("/notification-messages")
@HvlActuatorService(
        name = "hvl-ntf-notification-message-rest-controller",
        groupName = "hvl-ntf-notification-messages"
)
public class HvlNtfNotificationMessageRestController implements HvlNtfNotificationMessageOperationalRestService {

    private final HvlNtfNotificationMessageService ntfNotificationMessageService;

    public HvlNtfNotificationMessageRestController(HvlNtfNotificationMessageService ntfNotificationMessageService) {
        this.ntfNotificationMessageService = ntfNotificationMessageService;
    }

    @Override
    public HvlResponse<Void> save(@NotNull @Valid @RequestBody HvlNtfNotificationMessageModel ntfNotificationMessageModel) {
        ntfNotificationMessageService.save(ntfNotificationMessageModel);
        return new HvlResponse<>();
    }

}
  • converter model ve varlık (entity) dönüşümü için oluşturulan mapstruct komponentlerinin bu paket altında yer alması önerilir. Converter içeriği mapstruct plugin ile üretilmektedir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Mapper
public interface HvlNtfNotificationMessageMapper extends HvlGenericMapStructMapper<HvlNtfNotificationMessageModel, HvlNtfNotificationMessage> {
}
  • entity Varlık (entity) tanımı için kullanılan pakettir. Varlık tanımlarında altyapıdan sunulan data hizmetlerinin kullanımı için HvlHardDeleteEntity / HvlSoftDeleteEntity kullanımı önem arz etmektedir.

Paket altında yer alan varlık yapısı örneği aşağıdaki gibidir.

@Entity
@Table(
        name = TABLE_NAME,
        schema = SCHEMA_NAME
)
public class HvlNtfNotificationMessage extends HvlHardDeleteEntity {

    //**********************************************************
    //* Table Name
    //**********************************************************

    public static final String TABLE_NAME = "NTF_NOTIFICATION_MESSAGE";

    public static final String SCHEMA_NAME = "NOTIF_SYS";

    //**********************************************************
    //* Columns
    //**********************************************************

    public static final String NOTIFICATION_TYPE_ID_FIELD_COLUMN = "NOTIFICATION_TYPE_ID";

    public static final String SEVERITY_LEVEL_FIELD_COLUMN = "SEVERITY_LEVEL";

    public static final String MESSAGE_CONTENT_FIELD_COLUMN = "MESSAGE_CONTENT";

    @Column(name = NOTIFICATION_TYPE_ID_FIELD_COLUMN, nullable = false)
    private Long notificationTypeId;

    @Column(name = SEVERITY_LEVEL_FIELD_COLUMN, nullable = false)
    private Integer severityLevel;

    @Column(name = MESSAGE_CONTENT_FIELD_COLUMN)
    private String messageContent;

    public HvlNtfNotificationMessage() {
        super();
    }

    public Long getNotificationTypeId() {
        return this.notificationTypeId;
    }

    public void setNotificationTypeId(Long notificationTypeId) {
        this.notificationTypeId = notificationTypeId;
    }

    public Integer getSeverityLevel() {
        return this.severityLevel;
    }

    public void setSeverityLevel(Integer severityLevel) {
        this.severityLevel = severityLevel;
    }

    public String getMessageContent() {
        return this.messageContent;
    }

    public void setMessageContent(String messageContent) {
        this.messageContent = messageContent;
    }

    @Override
    public boolean equals(Object o) {
        return super.equals(o);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode());
    }

}
  • generator Manager katmanında kullanılacak QueryDSL predicate ve sub-query tanımları bu paket altında tanımlanması önerilir. Generator bileşenleri sorgu parçalarının tekrar tekrar kullanılabilirliği açısından önem arz etmektedir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Component
public class HvlNtfNotificationMessageQueryGenerator extends HvlEntityQueryGenerator<HvlNtfNotificationMessageQueryModel, HvlNtfNotificationMessageQuery> {

    private static final HvlNtfNotificationTypeQuery hvlNtfNotificationTypeQuery = HvlNtfNotificationTypeQuery.hvlNtfNotificationType;

    @Override
    protected void preparePredicate(
            BooleanBuilder expressionBuilder,
            HvlNtfNotificationMessageQueryModel ntfNotificationMessageQueryModel,
            HvlNtfNotificationMessageQuery ntfNotificationMessageQuery) {
        final Set<Long> idAndEq = ntfNotificationMessageQueryModel.getIdAndEq();
        if (CollectionUtils.isNotEmpty(idAndEq)) {
            expressionBuilder.and(ntfNotificationMessageQuery.id.in(idAndEq));
        }

        final Set<Long> notificationTypeIdAndEq = ntfNotificationMessageQueryModel.getNotificationTypeIdAndEq();
        if (CollectionUtils.isNotEmpty(notificationTypeIdAndEq)) {
            expressionBuilder.and(ntfNotificationMessageQuery.notificationTypeId.in(notificationTypeIdAndEq));
        }

        final Set<Integer> severityLevelAndEq = ntfNotificationMessageQueryModel.getSeverityLevelAndEq();
        if (CollectionUtils.isNotEmpty(severityLevelAndEq)) {
            expressionBuilder.and(ntfNotificationMessageQuery.severityLevel.in(severityLevelAndEq));
        }

        doPrepareHvlNtfNotificationTypePredicate(expressionBuilder, ntfNotificationMessageQueryModel, ntfNotificationMessageQuery);
    }

    @Override
    protected void prepareFilterPredicate(
            BooleanBuilder expressionBuilder,
            Map<String, Object> filters,
            HvlNtfNotificationMessageQuery ntfNotificationMessageQuery) {
        filters.forEach((key, value) -> {
            if (value instanceof String stringValue) {
                addContainsIgnoreCase(expressionBuilder, key, stringValue);
            }
        });
    }

    private void doPrepareHvlNtfNotificationTypePredicate(
            BooleanBuilder expressionBuilder,
            HvlNtfNotificationMessageQueryModel ntfNotificationMessageQueryModel,
            HvlNtfNotificationMessageQuery ntfNotificationMessageQuery) {
        final Set<String> hvlNtfNotificationTypeTypeKeyAndEq = ntfNotificationMessageQueryModel.getHvlNtfNotificationTypeTypeKeyAndEq();
        if (CollectionUtils.isNotEmpty(hvlNtfNotificationTypeTypeKeyAndEq)) {
            expressionBuilder.and(hvlNtfNotificationTypeQuery.typeKey.in(hvlNtfNotificationTypeTypeKeyAndEq));
        }

        final Set<String> hvlNtfNotificationTypeTypeNameAndEq = ntfNotificationMessageQueryModel.getHvlNtfNotificationTypeTypeNameAndEq();
        if (CollectionUtils.isNotEmpty(hvlNtfNotificationTypeTypeNameAndEq)) {
            expressionBuilder.and(hvlNtfNotificationTypeQuery.typeName.in(hvlNtfNotificationTypeTypeNameAndEq));
        }

    }

}
  • logic Kalıcılık katmanı haricinde iş mantığı ile ilgili kodlamaların tamamı bu paket altında yer alması önerilir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Validated
public interface HvlNtfNotificationMessageService {

    void save(@NotNull @Valid HvlNtfNotificationMessageModel ntfNotificationMessageModel);

    HvlNtfNotificationMessageModel getByUuid(
            @NotBlank
            @Size(max = HvlPersistableDataConstraint.UUID_SIZE, min = HvlPersistableDataConstraint.UUID_SIZE) String uuid);
}

@Service
@HvlTransactionalRollbackForCheckedException
public class HvlNtfNotificationMessageServiceImpl implements HvlNtfNotificationMessageService {

    private final HvlNtfNotificationMessageOperationalManager ntfNotificationMessageOperationalManager;

    private final HvlNtfNotificationMessageManager ntfNotificationMessageManager;

    public HvlNtfNotificationMessageServiceImpl(
            HvlNtfNotificationMessageOperationalManager ntfNotificationMessageOperationalManager,
            HvlNtfNotificationMessageManager ntfNotificationMessageManager) {
        this.ntfNotificationMessageOperationalManager = ntfNotificationMessageOperationalManager;
        this.ntfNotificationMessageManager = ntfNotificationMessageManager;
    }

    @Override
    public void save(@NotNull @Valid HvlNtfNotificationMessageModel ntfNotificationMessageModel) {
        ntfNotificationMessageOperationalManager.save(ntfNotificationMessageModel);
    }

    @Override
    @HvlTransactionalReadOnly
    public HvlNtfNotificationMessageModel getByUuid(
            @NotBlank
            @Size(max = HvlPersistableDataConstraint.UUID_SIZE, min = HvlPersistableDataConstraint.UUID_SIZE) String uuid) {
        return ntfNotificationMessageManager.getByUuid(uuid);
    }

}
  • manager Kalıcılık katmanı ile ilgili tüm işlemler ve QueryDSL sorgulamaları bu paket altında yer alması önerilir. Varlık (entity) yapıları manager katmanı dışına çıkartılmaması ve gerekli olması durumunda model dönüşümü yapılarak çıkartılması önerilektedir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Validated
public interface HvlNtfNotificationMessageOperationalManager {

    void save(@NotNull @Valid HvlNtfNotificationMessageModel ntfNotificationMessageModel);

}

@Component
@HvlTransactionalRollbackForCheckedException
public class HvlNtfNotificationMessageOperationalManagerImpl implements HvlNtfNotificationMessageOperationalManager {

    private final HvlNtfNotificationMessageRepository ntfNotificationMessageRepository;

    private final HvlNtfNotificationMessageMapper ntfNotificationMessageMapper;

    public HvlNtfNotificationMessageOperationalManagerImpl(
            HvlNtfNotificationMessageRepository ntfNotificationMessageRepository,
            HvlNtfNotificationMessageMapper ntfNotificationMessageMapper) {
        this.ntfNotificationMessageRepository = ntfNotificationMessageRepository;
        this.ntfNotificationMessageMapper = ntfNotificationMessageMapper;
    }

    @Override
    public void save(@NotNull @Valid HvlNtfNotificationMessageModel ntfNotificationMessageModel) {
        ntfNotificationMessageRepository.save(
                ntfNotificationMessageMapper.convertToEntity(ntfNotificationMessageModel)
        );
    }

}
  • model Veri transfer nesne (DTO) yapılarının bu paket altında tanımlanması önerilir. Tanımlanan nesneler kullanım amaçlarına göre projection, query, predicate gibi alt paket bölümlerine ayrılabilir.

Paket altında yer alan veri transfer nesne yapısı örneği aşağıdaki gibidir.

public class HvlNtfNotificationMessageModel extends HvlModel {

    @NotNull
    private Long notificationTypeId;

    @NotNull
    private Integer severityLevel;

    private String messageContent;

    public HvlNtfNotificationMessageModel() {
        super();
    }

    public Long getNotificationTypeId() {
        return notificationTypeId;
    }

    public void setNotificationTypeId(Long notificationTypeId) {
        this.notificationTypeId = notificationTypeId;
    }

    public Integer getSeverityLevel() {
        return severityLevel;
    }

    public void setSeverityLevel(Integer severityLevel) {
        this.severityLevel = severityLevel;
    }

    public String getMessageContent() {
        return messageContent;
    }

    public void setMessageContent(String messageContent) {
        this.messageContent = messageContent;
    }

    @Override
    public boolean equals(Object o) {
        return super.equals(o);
    }

    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode());
    }

}
  • repository "Declarative Repository" tanımlamaları bu paket altında yapılması önerilir. Tanımlanan repository bişenlerinin HvlJpaRepository sınıfından kalıtım alınıp kullanılması, altyapıdan sağlanan veri sorgulama ve entity işlemleri için önemlidir.

Paket altında yer alan bileşen yapısı örneği aşağıdaki gibidir.

@Repository
public interface HvlNtfNotificationMessageRepository extends HvlJpaRepository<HvlNtfNotificationMessage> {
}