api sample

This commit is contained in:
2025-11-17 09:39:18 +09:00
parent 74e1c6bb9c
commit 7d64ee897d
29 changed files with 918 additions and 126 deletions

View File

@@ -0,0 +1,34 @@
package com.kamco.cd.kamcoback.postgres;
import jakarta.persistence.Column;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreUpdate;
import java.time.ZonedDateTime;
import lombok.Getter;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
@Getter
@MappedSuperclass
public class CommonDateEntity {
@CreatedDate
@Column(name = "created_date", updatable = false, nullable = false)
private ZonedDateTime createdDate;
@LastModifiedDate
@Column(name = "modified_date", nullable = false)
private ZonedDateTime modifiedDate;
@PrePersist
protected void onPersist() {
this.createdDate = ZonedDateTime.now();
this.modifiedDate = ZonedDateTime.now();
}
@PreUpdate
protected void onUpdate() {
this.modifiedDate = ZonedDateTime.now();
}
}

View File

@@ -0,0 +1,19 @@
package com.kamco.cd.kamcoback.postgres;
import com.querydsl.jpa.impl.JPAQueryFactory;
import jakarta.persistence.EntityManager;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@RequiredArgsConstructor
@Configuration
public class QueryDslConfig {
private final EntityManager entityManager;
@Bean
public JPAQueryFactory jpaQueryFactory() {
return new JPAQueryFactory(entityManager);
}
}

View File

@@ -0,0 +1,68 @@
package com.kamco.cd.kamcoback.postgres.core;
import com.kamco.cd.kamcoback.common.service.BaseCoreService;
import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity;
import com.kamco.cd.kamcoback.postgres.repository.AnimalRepository;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto;
import jakarta.persistence.EntityNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AnimalCoreService
implements BaseCoreService<AnimalDto.Basic, Long, AnimalDto.SearchReq> {
private final AnimalRepository animalRepository;
@Transactional(readOnly = true)
public AnimalDto.Basic getDataByUuid(String uuid) {
AnimalEntity getZoo =
animalRepository
.getAnimalByUuid(uuid)
.orElseThrow(
() ->
new EntityNotFoundException(
"Zoo not found with uuid: " + uuid));
return getZoo.toDto();
}
// AddReq를 받는 추가 메서드
@Transactional
public AnimalDto.Basic create(AnimalDto.AddReq req) {
AnimalEntity entity = new AnimalEntity(req.getCategory(), req.getSpecies(), req.getName());
AnimalEntity saved = animalRepository.save(entity);
return saved.toDto();
}
@Override
@Transactional
public void remove(Long id) {
AnimalEntity getZoo =
animalRepository
.getAnimalByUid(id)
.orElseThrow(
() -> new EntityNotFoundException("Zoo not found with id: " + id));
getZoo.deleted();
}
@Override
public AnimalDto.Basic getOneById(Long id) {
AnimalEntity getZoo =
animalRepository
.getAnimalByUid(id)
.orElseThrow(
() -> new EntityNotFoundException("Zoo not found with id: " + id));
return getZoo.toDto();
}
@Override
public Page<AnimalDto.Basic> search(AnimalDto.SearchReq searchReq) {
Page<AnimalEntity> zooEntities = animalRepository.listAnimal(searchReq);
return zooEntities.map(AnimalEntity::toDto);
}
}

View File

@@ -0,0 +1,67 @@
package com.kamco.cd.kamcoback.postgres.entity;
import com.kamco.cd.kamcoback.postgres.CommonDateEntity;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import java.util.UUID;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
// 기본구조 관련
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "tb_animal")
public class AnimalEntity extends CommonDateEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long uid;
@Column(unique = true)
private UUID uuid;
@Enumerated(EnumType.STRING)
private Category category;
@Enumerated(EnumType.STRING)
private Species species;
private String name;
private Boolean isDeleted;
// Construct
public AnimalEntity(Category category, Species species, String name) {
this.uuid = UUID.randomUUID();
this.category = category;
this.species = species;
this.name = name;
this.isDeleted = false;
}
public AnimalDto.Basic toDto() {
return new AnimalDto.Basic(
this.uid,
this.uuid.toString(),
this.name,
this.category,
this.species,
super.getCreatedDate(),
super.getModifiedDate());
}
public void deleted() {
this.isDeleted = true;
}
}

View File

@@ -0,0 +1,7 @@
package com.kamco.cd.kamcoback.postgres.repository;
import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AnimalRepository
extends JpaRepository<AnimalEntity, Long>, AnimalRepositoryCustom {}

View File

@@ -0,0 +1,15 @@
package com.kamco.cd.kamcoback.postgres.repository;
import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto;
import java.util.Optional;
import org.springframework.data.domain.Page;
public interface AnimalRepositoryCustom {
Optional<AnimalEntity> getAnimalByUid(Long uid);
Optional<AnimalEntity> getAnimalByUuid(String uuid);
Page<AnimalEntity> listAnimal(AnimalDto.SearchReq req);
}

View File

@@ -0,0 +1,99 @@
package com.kamco.cd.kamcoback.postgres.repository;
import com.kamco.cd.kamcoback.postgres.entity.AnimalEntity;
import com.kamco.cd.kamcoback.postgres.entity.QAnimalEntity;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Category;
import com.kamco.cd.kamcoback.zoo.dto.AnimalDto.Species;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.jpa.impl.JPAQueryFactory;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.support.QuerydslRepositorySupport;
public class AnimalRepositoryImpl extends QuerydslRepositorySupport
implements AnimalRepositoryCustom {
private final JPAQueryFactory queryFactory;
public AnimalRepositoryImpl(JPAQueryFactory queryFactory) {
super(AnimalEntity.class);
this.queryFactory = queryFactory;
}
public Optional<AnimalEntity> getAnimalByUid(Long uid) {
QAnimalEntity animal = QAnimalEntity.animalEntity;
return Optional.ofNullable(
queryFactory.selectFrom(animal).where(animal.uid.eq(uid)).fetchFirst());
}
public Optional<AnimalEntity> getAnimalByUuid(String uuid) {
QAnimalEntity animal = QAnimalEntity.animalEntity;
return Optional.ofNullable(
queryFactory
.selectFrom(animal)
.where(animal.uuid.eq(UUID.fromString(uuid)))
.fetchFirst());
}
@Override
public Page<AnimalEntity> listAnimal(AnimalDto.SearchReq req) {
QAnimalEntity animal = QAnimalEntity.animalEntity;
Pageable pageable = req.toPageable();
List<AnimalEntity> content =
queryFactory
.selectFrom(animal)
.where(
animal.isDeleted.eq(false),
eqCategory(animal, req.getCategory()),
eqSpecies(animal, req.getSpecies()),
likeName(animal, req.getName()))
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.orderBy(animal.createdDate.desc())
.fetch();
// count 쿼리
Long total =
queryFactory
.select(animal.count())
.from(animal)
.where(
animal.isDeleted.eq(false),
eqCategory(animal, req.getCategory()),
eqSpecies(animal, req.getSpecies()),
likeName(animal, req.getName()))
.fetchOne();
return new PageImpl<>(content, pageable, total);
}
private BooleanExpression likeName(QAnimalEntity animal, String nameStr) {
if (nameStr == null || nameStr.isEmpty()) {
return null;
}
return animal.name.containsIgnoreCase(nameStr.trim());
}
private BooleanExpression eqCategory(QAnimalEntity animal, Category category) {
if (category == null) {
return null;
}
return animal.category.eq(category);
}
private BooleanExpression eqSpecies(QAnimalEntity animal, Species species) {
if (species == null) {
return null;
}
return animal.species.eq(species);
}
}