Skip to content
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.kilometer.backend.controller;

import com.kilometer.domain.archive.ArchiveService;
import com.kilometer.domain.archive.request.ArchiveCreateRequest;
import com.kilometer.domain.archive.service.ArchiveService;
import com.kilometer.domain.archive.dto.ArchiveDeleteResponse;
import com.kilometer.domain.archive.dto.ArchiveDetailResponse;
import com.kilometer.domain.archive.dto.ArchiveInfo;
Expand Down Expand Up @@ -60,7 +61,7 @@ public ArchiveDetailResponse archive(
@PostMapping(ApiUrlUtils.ARCHIVE_ROOT)
@ApiOperation(value = "신규 아카이브 등록")
public ArchiveInfo saveArchive(
@ApiParam(value = "등록할 아카이브 데이터", required = true) @RequestBody ArchiveRequest request) {
@ApiParam(value = "등록할 아카이브 데이터", required = true) @RequestBody ArchiveCreateRequest request) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Create 붙여준거 조아요~

long userId = getLoginUserId();
return archiveService.save(userId, request);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@
import com.kilometer.domain.archive.dto.ItemArchiveDto;
import com.kilometer.domain.archive.dto.MyArchiveDto;
import com.kilometer.domain.archive.dto.MyArchiveInfo;
import com.kilometer.domain.archive.like.dto.ArchiveLike;
import com.kilometer.domain.archive.like.dto.ArchiveLikeGenerator;
import com.kilometer.domain.archive.userVisitPlace.UserVisitPlaceEntity;
import com.kilometer.domain.badge.ItemBadge;
import com.kilometer.domain.badge.ItemBadgeGenerator;
import com.kilometer.domain.item.dto.ItemSummary;
import com.kilometer.domain.item.enumType.ExhibitionType;
import com.kilometer.domain.archive.like.dto.ArchiveLike;
import com.kilometer.domain.archive.like.dto.ArchiveLikeGenerator;
import com.kilometer.domain.linkInfo.LinkInfo;
import com.kilometer.domain.user.dto.UserResponse;
import com.kilometer.domain.user.User;
import com.kilometer.domain.util.ApiUrlUtils;
import com.kilometer.domain.util.FrontUrlUtils;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

Expand All @@ -35,7 +33,8 @@ public class ArchiveAggregateConverter {
private final ItemBadgeGenerator itemBadgeGenerator;

public ArchiveInfo convertArchiveInfo(ItemArchiveDto itemArchiveDto,
List<ArchiveImageEntity> archiveImageEntities, List<UserVisitPlaceEntity> userVisitPlaceEntities) {
List<ArchiveImageEntity> archiveImageEntities,
List<UserVisitPlaceEntity> userVisitPlaceEntities) {

Map<PlaceType, String> placeTypes = convertFoodAndCafe(userVisitPlaceEntities);

Expand Down Expand Up @@ -86,20 +85,21 @@ public ArchiveInfo convertArchiveInfo(ArchiveEntity archiveEntity,
.build();
}

public ArchiveInfo convertArchiveInfo(ArchiveEntity archiveEntity, UserResponse userResponse,
List<ArchiveImageEntity> archiveImageEntities, List<UserVisitPlaceEntity> userVisitPlaceEntities) {
public ArchiveInfo convertArchiveInfo(ArchiveEntity archiveEntity) {

Map<PlaceType, String> placeTypes = convertFoodAndCafe(userVisitPlaceEntities);
Map<PlaceType, String> placeTypes = convertFoodAndCafe(archiveEntity.getUserVisitPlaces());

ArchiveLike archiveLike = archiveLikeGenerator.generateArchiveLike(archiveEntity.getId());

List<String> photoUrls = archiveImageEntities.stream()
List<String> photoUrls = archiveEntity.getArchiveImages().stream()
.map(ArchiveImageEntity::getImageUrl)
.collect(Collectors.toList());
User user = archiveEntity.getUser();

return ArchiveInfo.builder()
.id(archiveEntity.getId())
.userProfileUrl(userResponse.getImageUrl())
.userName(userResponse.getName())
.userProfileUrl(user.getImageUrl())
.userName(user.getName())
.updatedAt(archiveEntity.getUpdatedAt())
.starRating(archiveEntity.getStarRating())
.likeCount(archiveEntity.getLikeCount())
Expand All @@ -112,7 +112,7 @@ public ArchiveInfo convertArchiveInfo(ArchiveEntity archiveEntity, UserResponse
}

public MyArchiveInfo convertMyArchiveInfo(MyArchiveDto myArchiveDto,
boolean existImages, List<UserVisitPlaceEntity> userVisitPlaceEntities) {
boolean existImages, List<UserVisitPlaceEntity> userVisitPlaceEntities) {

ItemBadge itemBadge = itemBadgeGenerator.generateTypeItemBadge(ExhibitionType.EXHIBITION);

Expand All @@ -129,7 +129,8 @@ public MyArchiveInfo convertMyArchiveInfo(MyArchiveDto myArchiveDto,
}

public ArchiveDetailResponse convertArchiveDetail(ArchiveDetailDto archiveDetailDto,
List<UserVisitPlaceEntity> visitPlaces, List<ArchiveImageEntity> archiveImageEntities) {
List<UserVisitPlaceEntity> visitPlaces,
List<ArchiveImageEntity> archiveImageEntities) {
ItemBadge itemBadge = itemBadgeGenerator.generateTypeItemBadge(
archiveDetailDto.getItemExhibitionType());
Map<PlaceType, String> placeTypes = convertFoodAndCafe(visitPlaces);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package com.kilometer.domain.archive;

import com.kilometer.domain.archive.archiveImage.ArchiveImageEntity;
import com.kilometer.domain.archive.request.ArchiveRequest;
import com.kilometer.domain.archive.userVisitPlace.UserVisitPlaceEntity;
import com.kilometer.domain.item.ItemEntity;
import com.kilometer.domain.user.User;
import java.time.LocalDateTime;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
Expand All @@ -12,6 +16,7 @@
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
Expand Down Expand Up @@ -65,6 +70,22 @@ public class ArchiveEntity {
@JoinColumn(name = "item")
private ItemEntity item;

@OneToMany(mappedBy = "archiveEntity", cascade = CascadeType.PERSIST)
private List<ArchiveImageEntity> archiveImages;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

흠 PERSIST가 맞을까요? 이걸로 하신 이유가 있을까요?

Copy link
Contributor Author

@gudonghee2000 gudonghee2000 Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 부분은 다대일 양방향 매핑을 사용하면서 발생한 영속성전이 부분이예요.
Archive와 ArchiveImage 중 연관관계 주인이 ArchiveImage가 되면서 양방향 매핑을 위해 @OneToManymappedBy 옵션이 붙게 되었어요

하지만 mappedBy는 읽기 전용이기 때문에 쓰기가 불가능해요.
그래서 CaseCade.Persist 옵션을 주어 Archive를 DB에 영속시킬때 영속성 전이를 통해 ArchiveImages를 같이 영속화 시킴을 명시해주어야 해요

만약, 위와 같이 구성하지 않게되면
ArchiveRepository.save(), ArchiveImageRepository.save() 로직이 두번 발생하게되는데요.
ArchiveImage는 Archive에 생명주기가 종속적인 Entity이기 때문에 영속성 전이를 사용했어요!


@OneToMany(mappedBy = "archiveEntity", cascade = CascadeType.PERSIST)
private List<UserVisitPlaceEntity> userVisitPlaces;

public void addArchiveImages(final List<ArchiveImageEntity> archiveImages) {
this.archiveImages = archiveImages;
archiveImages.forEach(archiveImage -> archiveImage.initArchiveEntity(this));
}

public void addUserVisitPlaces(final List<UserVisitPlaceEntity> userVisitPlaces) {
this.userVisitPlaces = userVisitPlaces;
userVisitPlaces.forEach(userVisitPlace -> userVisitPlace.initArchiveEntity(this));
}

public void setUser(User user) {
this.user = user;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public class ArchiveImageEntity {
@JoinColumn(name = "archive")
private ArchiveEntity archiveEntity;

public void setArchiveEntity(ArchiveEntity archiveEntity) {
public void initArchiveEntity(ArchiveEntity archiveEntity) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 이름이 set이 아닌 init으로 바꾼이유가 뭘까용?

Copy link
Contributor Author

@gudonghee2000 gudonghee2000 Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

개인적으로 set이라는 네이밍을 좋아하지 않아서 변경해보았어요~

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

장단점이 뭘까요? 왜 set이라는 네이밍을 좋아하지 않으신가용?

this.archiveEntity = archiveEntity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public List<ArchiveImageEntity> saveAll(List<ArchiveImageEntity> archiveImageEnt
return List.of();
}
ArchiveEntity archiveEntity = ArchiveEntity.builder().id(archiveId).build();
archiveImageEntities.forEach(archiveImage -> archiveImage.setArchiveEntity(archiveEntity));
archiveImageEntities.forEach(archiveImage -> archiveImage.initArchiveEntity(archiveEntity));
return archiveImageRepository.saveAll(archiveImageEntities);
}
@Transactional
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package com.kilometer.domain.archive.domain;

import com.kilometer.domain.archive.ArchiveEntity;
import com.kilometer.domain.archive.archiveImage.ArchiveImageEntity;
import com.kilometer.domain.archive.domain.archiveFilter.ArchiveFilter;
import com.kilometer.domain.archive.domain.userVisitPlace.UserVisitPlace;
import com.kilometer.domain.archive.exception.ArchiveValidationException;
import com.kilometer.domain.archive.userVisitPlace.UserVisitPlaceEntity;
import com.kilometer.domain.item.ItemEntity;
import com.kilometer.domain.user.User;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.Getter;

@Getter
Expand Down Expand Up @@ -51,4 +57,26 @@ private static void validateStarRating(final int starRating) {
throw new ArchiveValidationException("별점은 0~5 사이의 양수이어야 합니다.");
}
}

public ArchiveEntity toEntity(final User user, final ItemEntity itemEntity) {
return ArchiveEntity.builder()
.comment(this.getComment())
.starRating(this.getStarRating())
.isVisibleAtItem(this.isVisibleAtItem())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 이름이 왜 isVisibleAtItem이에요? 무슨 뜻인가용?

Copy link
Contributor Author

@gudonghee2000 gudonghee2000 Feb 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 필드명이 isVisibleAtItem이예요.
기존에 설정되어 있던 네이밍인데요. 아카이브 공개설정에 대한 옵션인것 같아요~
지금 보면 네이밍에 item이 붙어있어 헷갈리기도 하네요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AtItem부터는 빼도 되지 않을까 싶긴하네요~

.user(user)
.item(itemEntity)
.build();
}

public List<ArchiveImageEntity> createArchiveImageEntities() {
return this.archiveImages.stream()
.map(ArchiveImage::toEntity)
.collect(Collectors.toList());
}

public List<UserVisitPlaceEntity> createUserVisitPlaceEntities() {
return this.userVisitPlaces.stream()
.map(UserVisitPlace::toEntity)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.kilometer.domain.archive.domain;

import com.kilometer.domain.archive.archiveImage.ArchiveImageEntity;
import com.kilometer.domain.archive.exception.ArchiveValidationException;
import lombok.Getter;
import org.junit.platform.commons.util.StringUtils;
Expand All @@ -23,4 +24,10 @@ private static void validateImageUrl(final String imageUrl) {
throw new ArchiveValidationException("이미지 링크가 없습니다.");
}
}

public ArchiveImageEntity toEntity() {
return ArchiveImageEntity.builder()
.imageUrl(this.imageUrl)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.kilometer.domain.archive.domain.userVisitPlace;

import com.kilometer.domain.archive.exception.ArchiveValidationException;
import com.kilometer.domain.archive.userVisitPlace.UserVisitPlaceEntity;
import lombok.Getter;
import org.junit.platform.commons.util.StringUtils;

Expand Down Expand Up @@ -37,4 +38,13 @@ private static void validate(final String placeName, final String address, final
throw new ArchiveValidationException("입력된 도로명 주소가 없습니다.");
}
}

public UserVisitPlaceEntity toEntity() {
return UserVisitPlaceEntity.builder()
.placeType(this.placeType)
.placeName(this.placeName)
.address(this.address)
.roadAddress(this.roadAddress)
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.kilometer.domain.archive.request;

import com.kilometer.domain.archive.domain.Archive;
import com.kilometer.domain.archive.domain.ArchiveImage;
import com.kilometer.domain.archive.domain.userVisitPlace.UserVisitPlace;
import com.kilometer.domain.archive.dto.PlaceInfo;
import java.util.List;
import java.util.stream.Collectors;
import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@AllArgsConstructor
public class ArchiveCreateRequest {

private Long itemId;
private String comment;
private int starRating;
private boolean isVisibleAtItem;
private List<String> photoUrls;
private List<PlaceInfo> placeInfos;

public Archive toDomain() {
return Archive.createArchive(
this.comment, this.starRating, this.isVisibleAtItem, toArchiveImages(), toUserVisitPlace());
}

public List<ArchiveImage> toArchiveImages() {
return this.photoUrls.stream()
.map(ArchiveImage::createArchiveImage)
.collect(Collectors.toList());
}

public List<UserVisitPlace> toUserVisitPlace() {
return this.placeInfos.stream()
.map(PlaceInfo::toDomain)
.collect(Collectors.toList());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.kilometer.domain.archive.service;

import com.kilometer.domain.archive.ArchiveEntity;
import com.kilometer.domain.archive.domain.Archive;
import com.kilometer.domain.archive.request.ArchiveCreateRequest;
import com.kilometer.domain.item.ItemEntity;
import com.kilometer.domain.item.ItemRepository;
import com.kilometer.domain.item.exception.ItemNotFoundException;
import com.kilometer.domain.user.User;
import com.kilometer.domain.user.UserRepository;
import com.kilometer.domain.user.exception.UserNotFoundException;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class ArchiveEntityMapper {

private final UserRepository userRepository;
private final ItemRepository itemRepository;

public ArchiveEntity mapToArchiveEntity(final Long userId, final ArchiveCreateRequest request) {
Archive archive = request.toDomain();

ArchiveEntity archiveEntity = createArchiveEntity(userId, request.getItemId(), archive);
archiveEntity.addArchiveImages(archive.createArchiveImageEntities());
archiveEntity.addUserVisitPlaces(archive.createUserVisitPlaceEntities());
return archiveEntity;
}

private ArchiveEntity createArchiveEntity(final Long userId, final Long itemId, final Archive archive) {
User user = getUser(userId);
ItemEntity itemEntity = getItem(itemId);
return archive.toEntity(user, itemEntity);
}

private User getUser(final Long userId) {
return userRepository.findById(userId)
.orElseThrow(() -> new UserNotFoundException("저장되지 않은 사용자 입니다."));
}

private ItemEntity getItem(final Long itemId) {
ItemEntity itemEntity = itemRepository.findById(itemId)
.orElseThrow(() -> new ItemNotFoundException("저장되지 않은 아이템 입니다."));
itemEntity.validateExposureTypeIsOn();
return itemEntity;
}
}
Loading