-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: MapStruct 적용 #38
Changes from all commits
dd674c4
f8eb504
e3e11b8
43d5f46
9705653
a64232f
d1c5770
36f4378
4f9d598
54ee145
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package com.ordertogether.team14_be.spot.dto.controllerdto; | ||
|
||
import java.math.BigDecimal; | ||
|
||
public record SpotCreationRequest( | ||
Long id, | ||
BigDecimal lat, | ||
BigDecimal lng, | ||
String storeName, | ||
Integer minimumOrderAmount, | ||
String togetherOrderLink, | ||
String pickUpLocation) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.ordertogether.team14_be.spot.dto.controllerdto; | ||
|
||
import com.ordertogether.team14_be.spot.enums.Category; | ||
|
||
public record SpotCreationResponse( | ||
Long id, | ||
Category category, | ||
String storeName, | ||
Integer minimumOrderAmount, | ||
String pickUpLocation) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package com.ordertogether.team14_be.spot.dto.controllerdto; | ||
|
||
import com.ordertogether.team14_be.spot.enums.Category; | ||
|
||
public record SpotDetailResponse( | ||
Category category, | ||
String storeName, | ||
Integer minimumOrderAmount, | ||
String pickUpLocation, | ||
String deliveryStatus) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
package com.ordertogether.team14_be.spot.dto.controllerdto; | ||
|
||
public record SpotModifyRequest( | ||
Long id, String storeName, Integer minimumOrderAmount, String pickUpLocation) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package com.ordertogether.team14_be.spot.dto.controllerdto; | ||
|
||
import com.ordertogether.team14_be.spot.enums.Category; | ||
|
||
public record SpotViewedResponse( | ||
Category category, String storeName, Integer minimumOrderAmount, String pickUpLocation) {} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.ordertogether.team14_be.spot.mapper; | ||
|
||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotCreationRequest; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotCreationResponse; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotDetailResponse; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotViewedResponse; | ||
import com.ordertogether.team14_be.spot.dto.servicedto.SpotDto; | ||
import com.ordertogether.team14_be.spot.entity.Spot; | ||
import org.mapstruct.Mapper; | ||
import org.mapstruct.MappingTarget; | ||
import org.mapstruct.ReportingPolicy; | ||
import org.mapstruct.factory.Mappers; | ||
|
||
@Mapper( | ||
componentModel = "spring", | ||
unmappedTargetPolicy = ReportingPolicy.IGNORE) // Spring Bean으로 등록 | ||
public interface SpotMapper { | ||
SpotMapper INSTANCE = Mappers.getMapper(SpotMapper.class); // 객체 생성해서 INSTANCE에 할당 | ||
|
||
SpotDto toDto(Spot spot); | ||
|
||
SpotDto toSpotDto(SpotCreationRequest spotCreationRequest); | ||
|
||
Spot toEntity(SpotDto spotDto); | ||
|
||
Spot toEntity(SpotDto spotDto, @MappingTarget Spot spot); // 생성 또는 수정할 때 사용 | ||
|
||
SpotCreationResponse toSpotCreationResponse(SpotDto spotDto); | ||
|
||
SpotDetailResponse toSpotDetailResponse(SpotDto spotDto); | ||
|
||
SpotViewedResponse toSpotViewedResponse(SpotDto spotDto); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.ordertogether.team14_be.spot.repository; | ||
|
||
import com.ordertogether.team14_be.spot.entity.Spot; | ||
import java.math.BigDecimal; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface SimpleSpotRepository extends JpaRepository<Spot, Long> { | ||
List<Spot> findByLatAndLngAndIsDeletedFalse(BigDecimal lat, BigDecimal lng); | ||
|
||
Optional<Spot> findByIdAndIsDeletedFalse(Long id); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,42 @@ | ||
package com.ordertogether.team14_be.spot.repository; | ||
|
||
import com.ordertogether.team14_be.spot.dto.servicedto.SpotDto; | ||
import com.ordertogether.team14_be.spot.entity.Spot; | ||
import com.ordertogether.team14_be.spot.mapper.SpotMapper; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import java.math.BigDecimal; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
public interface SpotRepository extends JpaRepository<Spot, Long> { | ||
List<Spot> findByLatAndLngAndIsDeletedFalse(BigDecimal lat, BigDecimal lng); | ||
@RequiredArgsConstructor | ||
public class SpotRepository { | ||
|
||
Optional<Spot> findByIdAndIsDeletedFalse(Long id); | ||
private final SimpleSpotRepository simpleSpotRepository; | ||
|
||
public SpotDto save(Spot spot) { | ||
return SpotMapper.INSTANCE.toDto(simpleSpotRepository.save(spot)); | ||
} | ||
|
||
public SpotDto findByIdAndIsDeletedFalse(Long id) { | ||
return SpotMapper.INSTANCE.toDto( | ||
simpleSpotRepository | ||
.findByIdAndIsDeletedFalse(id) | ||
.orElseThrow(() -> new EntityNotFoundException(id + "에 해당하는 Spot을 찾을 수 없습니다."))); | ||
} | ||
|
||
public List<SpotDto> findByLatAndLngAndIsDeletedFalse(BigDecimal lat, BigDecimal lng) { | ||
return simpleSpotRepository.findByLatAndLngAndIsDeletedFalse(lat, lng).stream() | ||
.map(SpotMapper.INSTANCE::toDto) | ||
.toList(); | ||
} | ||
|
||
public void delete(Long id) { | ||
Spot spot = | ||
simpleSpotRepository | ||
.findByIdAndIsDeletedFalse(id) | ||
.orElseThrow(() -> new EntityNotFoundException(id + "에 해당하는 Spot을 찾을 수 없습니다.")); | ||
spot.delete(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,79 +1,57 @@ | ||
package com.ordertogether.team14_be.spot.service; | ||
|
||
import com.ordertogether.team14_be.spot.dto.SpotDto; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotCreationResponse; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotDetailResponse; | ||
import com.ordertogether.team14_be.spot.dto.controllerdto.SpotViewedResponse; | ||
import com.ordertogether.team14_be.spot.dto.servicedto.SpotDto; | ||
import com.ordertogether.team14_be.spot.entity.Spot; | ||
import com.ordertogether.team14_be.spot.mapper.SpotMapper; | ||
import com.ordertogether.team14_be.spot.repository.SpotRepository; | ||
import jakarta.persistence.EntityNotFoundException; | ||
import jakarta.transaction.Transactional; | ||
import java.math.BigDecimal; | ||
import java.util.List; | ||
import java.util.Optional; | ||
import java.util.stream.Collectors; | ||
import org.springframework.beans.factory.annotation.Autowired; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
@Service | ||
@RequiredArgsConstructor | ||
public class SpotService { | ||
|
||
private final SpotRepository spotRepository; | ||
|
||
@Autowired | ||
public SpotService(SpotRepository spotRepository) { | ||
this.spotRepository = spotRepository; | ||
} | ||
|
||
// Spot 전체 조회하기 | ||
public List<SpotDto> getSpot(BigDecimal lat, BigDecimal lng) { | ||
@Transactional(readOnly = true) | ||
public List<SpotViewedResponse> getSpot(BigDecimal lat, BigDecimal lng) { | ||
return spotRepository.findByLatAndLngAndIsDeletedFalse(lat, lng).stream() | ||
.map(this::toDto) | ||
.collect(Collectors.toList()); | ||
.map(SpotMapper.INSTANCE::toSpotViewedResponse) | ||
.toList(); | ||
} | ||
|
||
@Transactional | ||
public SpotDto createSpot(SpotDto spotDto) { | ||
Spot spot = spotDto.toEntity(); | ||
return toDto(spotRepository.save(spot)); | ||
public SpotCreationResponse createSpot(SpotDto spotDto) { | ||
Spot spot = SpotMapper.INSTANCE.toEntity(spotDto, new Spot()); | ||
return SpotMapper.INSTANCE.toSpotCreationResponse(spotRepository.save(spot)); | ||
} | ||
|
||
// Spot 상세 조회하기 | ||
public SpotDto getSpot(Long id) { | ||
Spot spot = | ||
spotRepository | ||
.findById(id) | ||
.orElseThrow(() -> new EntityNotFoundException("Spot을 찾을 수 없습니다.")); | ||
return toDto(spot); | ||
@Transactional(readOnly = true) | ||
public SpotDetailResponse getSpot(Long id) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 전체적으로 조회만 수행하는 메서드에 대해서 트랜잭션 어노테이션을 명시하지 않은 이유가 있을까요? 공부하고 댓글로 알려주면 유익할 것 같습니다 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
SpotDto spotDto = spotRepository.findByIdAndIsDeletedFalse(id); | ||
return SpotMapper.INSTANCE.toSpotDetailResponse(spotDto); | ||
} | ||
|
||
@Transactional | ||
public SpotDto updateSpot(SpotDto spotDto) { | ||
Spot spot = spotRepository.save(spotDto.toEntity()); | ||
return toDto(spot); | ||
Spot spot = | ||
SpotMapper.INSTANCE.toEntity( | ||
spotDto, | ||
SpotMapper.INSTANCE.toEntity( | ||
spotRepository.findByIdAndIsDeletedFalse(spotDto.getId()))); | ||
return SpotMapper.INSTANCE.toDto(spot); | ||
} | ||
|
||
@Transactional | ||
public void deleteSpot(Long id) { | ||
Optional<Spot> spotToDelete = spotRepository.findByIdAndIsDeletedFalse(id); | ||
spotToDelete.ifPresent(Spot::delete); | ||
} | ||
|
||
// Service Layer에서 toDto만들어서 매핑시키기 | ||
public SpotDto toDto(Spot spotInStream) { | ||
Spot spot = | ||
spotRepository | ||
.findById(spotInStream.getId()) | ||
.orElseThrow(() -> new EntityNotFoundException("Spot을 찾을 수 없습니다.")); | ||
|
||
return SpotDto.builder() | ||
.id(spot.getId()) | ||
.lat(spot.getLat()) | ||
.lng(spot.getLng()) | ||
.category(spot.getCategory()) | ||
.storeName(spot.getStoreName()) | ||
.minimumOrderAmount(spot.getMinimumOrderAmount()) | ||
.togetherOrderLink(spot.getTogetherOrderLink()) | ||
.pickUpLocation(spot.getPickUpLocation()) | ||
.deliveryStatus(spot.getDeliveryStatus()) | ||
.isDeleted(spot.getIsDeleted()) | ||
.build(); | ||
spotRepository.delete(id); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Mapper
의componentModel
,unmappedTargetPolicy
각 옵션들은 무슨 역할을 수행하나요?그리고 MapStruct 를 사용한 이유가 궁금합니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
componentModel = "spring"을 통해서 Spring bean으로 관리합니다. unmappedTargetPolicy = ReportingPolicy.IGNORE은 매핑되지 않는 필드에 대해 null처리를 하거나 무시합니다. createdAt이나 id 필드는 dto에서 값을 받아오는 것이 아니기 때문에 Controller dto에서 Service dto로 매핑할 때 null 처리를 해놓고 Spot 엔티티를 새로 생성하거나 업데이트할 때 null이 아닌 dto의 값만 활용할 수 있게 한 것입니다.
MapStruct는 Mapper 클래스나 Mapping을 직접 코딩할 필요 없이 자동으로 매핑해주기 때문에 확장에 용이하다고 생각해서 적용해봤습니다!