-
Notifications
You must be signed in to change notification settings - Fork 240
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
⭐️3단계 - 즐겨찾기 기능 구현 #462
base: boradol
Are you sure you want to change the base?
⭐️3단계 - 즐겨찾기 기능 구현 #462
Changes from all commits
b4ae7fd
3ed9cd7
7a972ae
deecd63
d770a3f
daae3c5
08ba1c0
d03413e
93c9393
e73a7bd
6bcdad3
9ffbf49
be18627
6b9ad26
6741d4f
cea33b0
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,11 @@ | ||
package nextstep.exception; | ||
|
||
import org.springframework.http.HttpStatus; | ||
import org.springframework.web.bind.annotation.ResponseStatus; | ||
|
||
@ResponseStatus(HttpStatus.BAD_REQUEST) | ||
public class SubwayIllegalArgumentException extends IllegalArgumentException { | ||
public SubwayIllegalArgumentException(String message){ | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package nextstep.favorite; | ||
|
||
import nextstep.favorite.application.FavoriteService; | ||
import nextstep.favorite.domain.Favorite; | ||
import nextstep.favorite.dto.FavoriteRequestDto; | ||
import nextstep.favorite.dto.FavoriteResponseDto; | ||
import nextstep.filter.PreAuthorize; | ||
import nextstep.member.application.dto.MemberResponse; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.*; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
|
||
@RestController | ||
@RequestMapping("/favorites") | ||
public class FavoriteController { | ||
private final FavoriteService favoriteService; | ||
|
||
public FavoriteController(FavoriteService favoriteService) { | ||
this.favoriteService = favoriteService; | ||
} | ||
|
||
@PostMapping | ||
@ResponseStatus(HttpStatus.CREATED) | ||
public ResponseEntity<Void> createFavorite(@PreAuthorize MemberResponse member, @RequestBody FavoriteRequestDto favoriteRequestDto) { | ||
Favorite favorite = favoriteService.create(member.getEmail(), favoriteRequestDto); | ||
return ResponseEntity | ||
.created(URI.create("/favorites/" + favorite.getId())) | ||
.build(); | ||
} | ||
|
||
@GetMapping | ||
public ResponseEntity<List<FavoriteResponseDto>> getListFavorite(@PreAuthorize MemberResponse member) { | ||
List<FavoriteResponseDto> favorites = favoriteService.getList(member.getEmail()) | ||
.stream() | ||
.map(FavoriteResponseDto::of) | ||
.collect(Collectors.toUnmodifiableList()); | ||
return ResponseEntity.ok(favorites); | ||
} | ||
|
||
@DeleteMapping("/{id}") | ||
@ResponseStatus(HttpStatus.NO_CONTENT) | ||
public ResponseEntity<Void> deleteFavorite(@PreAuthorize MemberResponse member, @PathVariable Long id) { | ||
favoriteService.deleteById(member.getEmail(), id); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
package nextstep.favorite.application; | ||
|
||
import nextstep.favorite.domain.Favorite; | ||
import nextstep.favorite.domain.FavoriteRepository; | ||
import nextstep.favorite.dto.FavoriteRequestDto; | ||
import nextstep.member.application.MemberService; | ||
import nextstep.member.domain.Member; | ||
import nextstep.subway.applicaion.StationService; | ||
import nextstep.subway.domain.Station; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import java.util.List; | ||
|
||
@Service | ||
public class FavoriteService { | ||
private final FavoriteRepository favoriteRepository; | ||
private final MemberService memberService; | ||
private final StationService stationService; | ||
|
||
public FavoriteService(FavoriteRepository favoriteRepository, MemberService memberService, StationService stationService) { | ||
this.favoriteRepository = favoriteRepository; | ||
this.memberService = memberService; | ||
this.stationService = stationService; | ||
} | ||
|
||
@Transactional | ||
public Favorite create(String email, FavoriteRequestDto favoriteRequestDto) { | ||
Member member = findMember(email); | ||
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. 인증이 된 member를 전달한다면 findMember가 없어도 되지 않을까요? 🤔 |
||
Station sourceStation = stationService.findById(favoriteRequestDto.getSource()); | ||
Station targetStation = stationService.findById(favoriteRequestDto.getTarget()); | ||
Favorite favorite = new Favorite(member, sourceStation, targetStation); | ||
return favoriteRepository.save(favorite); | ||
} | ||
|
||
@Transactional(readOnly = true) | ||
public List<Favorite> getList(String email) { | ||
Member member = findMember(email); | ||
return favoriteRepository.findAllByMember(member); | ||
} | ||
|
||
private Member findMember(String email) { | ||
return memberService.findByEmail(email); | ||
} | ||
|
||
@Transactional | ||
public void deleteById(String email, Long id) { | ||
Member member = findMember(email); | ||
if(existsByIdAndMember(id, member)){ | ||
favoriteRepository.deleteById(id); | ||
} | ||
} | ||
|
||
private boolean existsByIdAndMember(Long id, Member member) { | ||
return favoriteRepository.existsByIdAndMember(id, member); | ||
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. exist가 아닌 findById를 통하여 favorite을 찾고, 찾는 favorite의 memberId가 같은지 틀린지 validation을 해주는 건 어떨까요? |
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package nextstep.favorite.domain; | ||
|
||
import nextstep.exception.SubwayIllegalArgumentException; | ||
import nextstep.member.domain.Member; | ||
import nextstep.subway.domain.Station; | ||
|
||
import javax.persistence.*; | ||
|
||
@Entity | ||
public class Favorite { | ||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "member_id") | ||
private Member member; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "source_id") | ||
private Station source; | ||
|
||
@ManyToOne(fetch = FetchType.LAZY) | ||
@JoinColumn(name = "target_id") | ||
private Station target; | ||
Comment on lines
+15
to
+25
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. 직접 참조가 아닌 간접 참조로 변경해볼까요? 변경해보고 차이점을 알려주세요! |
||
|
||
public Favorite() { | ||
} | ||
|
||
public Favorite(Member member, Station source, Station target) { | ||
validateStation(source, target); | ||
validateEqualStartAndDestination(source, target); | ||
this.member = member; | ||
this.source = source; | ||
this.target = target; | ||
} | ||
|
||
private void validateEqualStartAndDestination(Station source, Station target) { | ||
if (source == target) { | ||
throw new SubwayIllegalArgumentException("출발역과 도착역이 같을 수 없습니다."); | ||
} | ||
} | ||
|
||
private void validateStation(Station source, Station target) { | ||
if (source == null || target == null) { | ||
throw new SubwayIllegalArgumentException("출발역과, 도착역 둘다 입력해줘야 합니다."); | ||
} | ||
} | ||
|
||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public Member getMember() { | ||
return member; | ||
} | ||
|
||
public Station getSource() { | ||
return source; | ||
} | ||
|
||
public Station getTarget() { | ||
return target; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package nextstep.favorite.domain; | ||
|
||
|
||
import nextstep.member.domain.Member; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.List; | ||
|
||
public interface FavoriteRepository extends JpaRepository<Favorite, Long> { | ||
List<Favorite> findAllByMember(Member member); | ||
boolean existsByIdAndMember(Long id, Member member); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package nextstep.favorite.dto; | ||
|
||
public class FavoriteRequestDto { | ||
private final Long source; | ||
private final Long target; | ||
|
||
public FavoriteRequestDto(Long source, Long target) { | ||
this.source = source; | ||
this.target = target; | ||
} | ||
|
||
public Long getSource() { | ||
return source; | ||
} | ||
|
||
public Long getTarget() { | ||
return target; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package nextstep.favorite.dto; | ||
|
||
import nextstep.favorite.domain.Favorite; | ||
import nextstep.subway.applicaion.dto.StationResponse; | ||
|
||
public class FavoriteResponseDto { | ||
private Long id; | ||
private StationResponse source; | ||
private StationResponse target; | ||
|
||
protected FavoriteResponseDto() { | ||
} | ||
|
||
public FavoriteResponseDto(Long id, StationResponse source, StationResponse target) { | ||
this.id = id; | ||
this.source = source; | ||
this.target = target; | ||
} | ||
|
||
public static FavoriteResponseDto of(Favorite favorite) { | ||
return new FavoriteResponseDto( | ||
favorite.getId(), | ||
StationResponse.of(favorite.getSource()), | ||
StationResponse.of(favorite.getTarget()) | ||
); | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public StationResponse getSource() { | ||
return source; | ||
} | ||
|
||
public StationResponse getTarget() { | ||
return target; | ||
} | ||
} |
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.
요구사항 정리 👍