-
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๋จ๊ณ - ์ฆ๊ฒจ์ฐพ๊ธฐ ๊ธฐ๋ฅ ๊ตฌํ #352
base: epicarts
Are you sure you want to change the base?
Changes from all commits
43253c5
a7c0499
2528f56
44420ad
9797b80
3c347ac
17c2292
064a532
86b18b3
61ddba8
7a1b8ea
eb5f981
ae1d3df
3061cc5
3048959
fa2e694
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,57 @@ | ||
package nextstep.member.application; | ||
|
||
import java.util.List; | ||
import java.util.stream.Collectors; | ||
import nextstep.member.application.dto.FavoriteRequest; | ||
import nextstep.member.application.dto.FavoriteResponse; | ||
import nextstep.member.domain.Favorite; | ||
import nextstep.member.domain.FavoriteRepository; | ||
import nextstep.member.domain.LoginMember; | ||
import nextstep.member.domain.Member; | ||
import nextstep.subway.applicaion.StationService; | ||
import nextstep.subway.domain.Station; | ||
import org.springframework.stereotype.Service; | ||
|
||
@Service | ||
public class FavoriteService { | ||
private final MemberService memberService; | ||
private final StationService stationService; | ||
private final FavoriteRepository favoriteRepository; | ||
|
||
public FavoriteService(MemberService memberService, StationService stationService, | ||
FavoriteRepository favoriteRepository) { | ||
this.memberService = memberService; | ||
this.stationService = stationService; | ||
this.favoriteRepository = favoriteRepository; | ||
} | ||
|
||
public Long saveFavorite(LoginMember loginMember, FavoriteRequest favoriteRequest) { | ||
Member member = memberService.findByEmail(loginMember.getEmail()); | ||
|
||
Station source = stationService.findById(favoriteRequest.getSource()); | ||
Station target = stationService.findById(favoriteRequest.getTarget()); | ||
|
||
Favorite favorite = member.addFavorite(source, target); | ||
|
||
return favoriteRepository.save(favorite).getId(); | ||
} | ||
|
||
public List<FavoriteResponse> findFavoriteResponses(LoginMember loginMember) { | ||
Member member = memberService.findByEmail(loginMember.getEmail()); | ||
List<Favorite> favorites = member.getFavorites(); | ||
|
||
return favorites.stream() | ||
.map(it -> FavoriteResponse.of(it, it.getSource(), it.getTarget())) | ||
.collect(Collectors.toList()); | ||
} | ||
|
||
public void deleteFavorite(LoginMember loginMember, Long favoriteId) { | ||
Favorite favorite = favoriteRepository.findById(favoriteId) | ||
.orElseThrow(IllegalArgumentException::new); | ||
|
||
Member member = memberService.findByEmail(loginMember.getEmail()); | ||
member.removeFavorite(favorite); | ||
|
||
favoriteRepository.delete(favorite); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
package nextstep.member.application.dto; | ||
|
||
public class FavoriteRequest { | ||
private Long source; | ||
private Long target; | ||
|
||
public FavoriteRequest() { | ||
} | ||
|
||
public FavoriteRequest(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,37 @@ | ||
package nextstep.member.application.dto; | ||
|
||
import nextstep.member.domain.Favorite; | ||
import nextstep.subway.applicaion.dto.StationResponse; | ||
import nextstep.subway.domain.Station; | ||
|
||
public class FavoriteResponse { | ||
private Long id; | ||
private StationResponse source; | ||
private StationResponse target; | ||
|
||
|
||
public static FavoriteResponse of(Favorite favorite, Station source, Station target) { | ||
return new FavoriteResponse(favorite.getId(), StationResponse.of(source), StationResponse.of(target)); | ||
} | ||
|
||
public FavoriteResponse(Long id, StationResponse source, StationResponse target) { | ||
this.id = id; | ||
this.source = source; | ||
this.target = target; | ||
} | ||
|
||
public FavoriteResponse() { | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public StationResponse getSource() { | ||
return source; | ||
} | ||
|
||
public StationResponse getTarget() { | ||
return target; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
package nextstep.member.domain; | ||
|
||
import nextstep.member.domain.exception.FavoriteException; | ||
import nextstep.subway.domain.Station; | ||
|
||
import javax.persistence.*; | ||
|
||
import static nextstep.member.domain.exception.FavoriteException.SAME_SOURCE_AND_TARGET; | ||
|
||
@Entity | ||
public class Favorite { | ||
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 ์ ๋ํ ์ ๋ณด๋ Favorite ์์ ์ ์ ์๋ค๊ณ ๋ณด๋๋ฐ์! ํ
์คํธ์์ ๋์ค๋ ์ฟผ๋ฆฌ๋ฅผ ํ์ธํด๋ณธ ๊ฒฐ๊ณผ ๋ก ์
๋ฐ์ดํธ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ๊ณ ์๋๋ฐ์. favorite ์๋ memberId ๊ฐ ์์์๋ ์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ๊ณ ์์ต๋๋ค! |
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "source_id") | ||
private Station source; | ||
|
||
@ManyToOne | ||
@JoinColumn(name = "target_id") | ||
private Station target; | ||
|
||
protected Favorite() { | ||
} | ||
|
||
public Favorite(Station source, Station target) { | ||
if (source.isSame(target)) { | ||
throw new FavoriteException(SAME_SOURCE_AND_TARGET); | ||
} | ||
this.source = source; | ||
this.target = target; | ||
} | ||
|
||
public Long getId() { | ||
return id; | ||
} | ||
|
||
public Station getSource() { | ||
return source; | ||
} | ||
|
||
public Station getTarget() { | ||
return target; | ||
} | ||
|
||
public boolean hasDuplicateFavorite(Station target, Station source) { | ||
return this.target == target && this.source == source; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package nextstep.member.domain; | ||
|
||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface FavoriteRepository extends JpaRepository<Favorite, Long> { | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
package nextstep.member.domain; | ||
|
||
import nextstep.member.domain.exception.FavoriteException; | ||
import nextstep.subway.domain.Section; | ||
import nextstep.subway.domain.Station; | ||
|
||
import javax.persistence.CascadeType; | ||
import javax.persistence.Embeddable; | ||
import javax.persistence.JoinColumn; | ||
import javax.persistence.OneToMany; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import static nextstep.member.domain.exception.FavoriteException.DUPLICATION_FAVORITE; | ||
|
||
@Embeddable | ||
public class Favorites { | ||
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE}, orphanRemoval = true) | ||
@JoinColumn(name = "member_id") | ||
private List<Favorite> favorites = new ArrayList<>(); | ||
|
||
public List<Favorite> getFavorites() { | ||
return this.favorites; | ||
} | ||
|
||
public void add(Favorite favorite) { | ||
checkDuplicationFavorite(favorite); | ||
this.favorites.add(favorite); | ||
} | ||
|
||
public void delete(Favorite favorite) { | ||
this.favorites.remove(favorite); | ||
} | ||
|
||
private void checkDuplicationFavorite(Favorite favorite) { | ||
favorites.stream() | ||
.filter(it -> it.hasDuplicateFavorite(favorite.getTarget(), favorite.getSource())) | ||
.findFirst() | ||
.ifPresent(it -> { | ||
throw new FavoriteException(DUPLICATION_FAVORITE); | ||
}); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,17 @@ | ||
package nextstep.member.domain; | ||
|
||
import javax.persistence.*; | ||
import java.util.List; | ||
import javax.persistence.CollectionTable; | ||
import javax.persistence.Column; | ||
import javax.persistence.ElementCollection; | ||
import javax.persistence.Embedded; | ||
import javax.persistence.Entity; | ||
import javax.persistence.FetchType; | ||
import javax.persistence.GeneratedValue; | ||
import javax.persistence.GenerationType; | ||
import javax.persistence.Id; | ||
import javax.persistence.JoinColumn; | ||
import nextstep.subway.domain.Station; | ||
|
||
@Entity | ||
public class Member { | ||
|
@@ -11,6 +21,8 @@ public class Member { | |
private String email; | ||
private String password; | ||
private Integer age; | ||
@Embedded | ||
private Favorites favorites = new Favorites(); | ||
@ElementCollection(fetch = FetchType.EAGER) | ||
@CollectionTable( | ||
name = "MEMBER_ROLE", | ||
|
@@ -56,6 +68,22 @@ public List<String> getRoles() { | |
return roles; | ||
} | ||
|
||
public List<Favorite> getFavorites() { | ||
return favorites.getFavorites(); | ||
} | ||
|
||
public Favorite addFavorite(Station source, Station target) { | ||
Favorite favorite = new Favorite(source, target); | ||
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 domain ์์ Favorite ์์ฑ ์ญํ ์ ๊ฐ์ง๊ณ ์๋๊ฒ ๋ง์๊น์? ์ด๋ป๊ฒ ์๊ฐํ์๋์? ๐ |
||
|
||
favorites.add(favorite); | ||
|
||
return favorite; | ||
} | ||
|
||
public void removeFavorite(Favorite favorite) { | ||
favorites.delete(favorite); | ||
} | ||
|
||
public void update(Member member) { | ||
this.email = member.email; | ||
this.password = member.password; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package nextstep.member.domain.exception; | ||
|
||
public class FavoriteException extends IllegalArgumentException { | ||
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. Custom ์์ธ ๐ |
||
public static final String SAME_SOURCE_AND_TARGET = "์ฆ๊ฒจ์ฐพ๊ธฐ์ ์ถ๋ฐ์ ๊ณผ ๋์ฐฉ์ญ์ด ๊ฐ์ ์ ์์ต๋๋ค."; | ||
public static final String DUPLICATION_FAVORITE = "์ด๋ฏธ ๋ฑ๋ก๋์ด์๋ ์ฆ๊ฒจ์ฐพ๊ธฐ์ ๋๋ค."; | ||
|
||
public FavoriteException(String message) { | ||
super(message); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package nextstep.member.ui; | ||
|
||
import java.net.URI; | ||
import java.util.List; | ||
import nextstep.auth.authorization.AuthenticationPrincipal; | ||
import nextstep.auth.secured.Secured; | ||
import nextstep.member.application.FavoriteService; | ||
import nextstep.member.application.dto.FavoriteRequest; | ||
import nextstep.member.application.dto.FavoriteResponse; | ||
import nextstep.member.domain.LoginMember; | ||
import org.springframework.http.ResponseEntity; | ||
import org.springframework.web.bind.annotation.DeleteMapping; | ||
import org.springframework.web.bind.annotation.GetMapping; | ||
import org.springframework.web.bind.annotation.PathVariable; | ||
import org.springframework.web.bind.annotation.PostMapping; | ||
import org.springframework.web.bind.annotation.RequestBody; | ||
import org.springframework.web.bind.annotation.RequestMapping; | ||
import org.springframework.web.bind.annotation.RestController; | ||
|
||
@RestController | ||
@RequestMapping("/favorites") | ||
public class FavoriteController { | ||
private final FavoriteService favoriteService; | ||
|
||
public FavoriteController(FavoriteService favoriteService) { | ||
this.favoriteService = favoriteService; | ||
} | ||
|
||
@PostMapping | ||
@Secured("ROLE_MEMBER") | ||
public ResponseEntity<Void> createFavorite(@AuthenticationPrincipal LoginMember loginMember, | ||
@RequestBody FavoriteRequest favoriteRequest) { | ||
Long favoriteId = favoriteService.saveFavorite(loginMember, favoriteRequest); | ||
return ResponseEntity.created(URI.create("/favorites/" + favoriteId)).build(); | ||
} | ||
|
||
@GetMapping | ||
@Secured("ROLE_MEMBER") | ||
public ResponseEntity<List<FavoriteResponse>> showFavorites(@AuthenticationPrincipal LoginMember loginMember) { | ||
List<FavoriteResponse> responses = favoriteService.findFavoriteResponses(loginMember); | ||
return ResponseEntity.ok().body(responses); | ||
} | ||
|
||
@DeleteMapping("/{favoriteId}") | ||
@Secured("ROLE_MEMBER") | ||
public ResponseEntity<Void> deleteFavorite(@AuthenticationPrincipal LoginMember loginMember, | ||
@PathVariable Long favoriteId) { | ||
favoriteService.deleteFavorite(loginMember, favoriteId); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
} |
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.
member.removeFavorite(favorite); ํด์ฃผ์ จ๋๋ฐ์! ํ์ธํด๋ณด๋ favorites ์์ ์ต์ ์ด orphanRemoval = true ๋ก ๋์ด ์๋๊ฑธ ๋ดค์ต๋๋ค! ๊ณ ์๊ฐ์ฒด๊ฐ ๋ favorite ๋ ๊ฐ์ด delete ๋ ๊ฒ์ผ๋ก ์์ ๋๋๋ฐ์!
55 line ์ favoriteRepository.delete(favorite); ๋ถ๋ถ์ด ํ์ํ ๊น์? ๐ง