Skip to content
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

[Step3] 즐겨찾기 기능 구현 리뷰 요청드립니다. #238

Open
wants to merge 6 commits into
base: misudev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nextstep.auth.authorization;

import nextstep.auth.authentication.AuthenticationException;
import nextstep.auth.context.Authentication;
import nextstep.auth.context.SecurityContextHolder;
import org.springframework.core.MethodParameter;
Expand All @@ -20,6 +21,10 @@ public boolean supportsParameter(MethodParameter parameter) {
@Override
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new AuthenticationException();
}

if (authentication.getPrincipal() instanceof Map) {
return extractPrincipal(parameter, authentication);
}
Expand Down
50 changes: 50 additions & 0 deletions src/main/java/nextstep/subway/applicaion/FavoriteService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package nextstep.subway.applicaion;

import java.util.List;
import java.util.stream.Collectors;
import nextstep.member.application.MemberService;
import nextstep.member.domain.LoginMember;
import nextstep.member.domain.MemberRepository;
import nextstep.subway.applicaion.dto.FavoriteRequest;
import nextstep.subway.applicaion.dto.FavoriteResponse;
import nextstep.subway.domain.Favorite;
import nextstep.subway.domain.FavoriteRepository;
import nextstep.subway.domain.Station;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class FavoriteService {
private final StationService stationService;
private final PathService pathService;
private final MemberRepository memberRepository;

Choose a reason for hiding this comment

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

memberRepository 를 사용하고 있지 않는데요,
즐겨찾기 생성, 조회, 삭제 시 유요한 memberId 인지 확인하지 않아도 될까요? 😄

private final FavoriteRepository favoriteRepository;

public FavoriteService(StationService stationService, PathService pathService,
MemberRepository memberRepository, FavoriteRepository favoriteRepository) {
this.stationService = stationService;
this.pathService = pathService;
this.memberRepository = memberRepository;
this.favoriteRepository = favoriteRepository;
}

public FavoriteResponse createFavorite(FavoriteRequest favoriteRequest, Long memberId) {
Station source = stationService.findById(favoriteRequest.getSource());
Station target = stationService.findById(favoriteRequest.getTarget());
pathService.findPath(source, target);
Favorite favorite = favoriteRepository.save(Favorite.of(memberId, source, target));
return FavoriteResponse.from(favorite);
}

@Transactional(readOnly = true)
public List<FavoriteResponse> findFavorites(Long memberId) {
List<Favorite> favorites = favoriteRepository.findAllByMemberId(memberId);
return favorites.stream().map(FavoriteResponse::from).collect(Collectors.toList());
}

public void deleteFavorite(Long favoriteId, Long memberId) {
Favorite favorite = favoriteRepository.getById(favoriteId);
favorite.hasPermission(memberId);
favoriteRepository.delete(favorite);
}
}
10 changes: 7 additions & 3 deletions src/main/java/nextstep/subway/applicaion/PathService.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,14 @@ public PathService(LineService lineService, StationService stationService) {
public PathResponse findPath(Long source, Long target) {
Station upStation = stationService.findById(source);
Station downStation = stationService.findById(target);
List<Line> lines = lineService.findLines();
SubwayMap subwayMap = new SubwayMap(lines);
Path path = subwayMap.findPath(upStation, downStation);
Path path = findPath(upStation, downStation);

return PathResponse.of(path);
}

Path findPath(Station upStation, Station downStation) {

Choose a reason for hiding this comment

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

접근제어자를 생략하신 이유가 있으신가요? 😄

List<Line> lines = lineService.findLines();
SubwayMap subwayMap = new SubwayMap(lines);
return subwayMap.findPath(upStation, downStation);
}
}
19 changes: 19 additions & 0 deletions src/main/java/nextstep/subway/applicaion/dto/FavoriteRequest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package nextstep.subway.applicaion.dto;

public class FavoriteRequest {
private Long source;
private Long target;

public FavoriteRequest(Long source, Long target) {
this.source = source;
this.target = target;
}

public Long getSource() {
return source;
}

public Long getTarget() {
return target;
}
}
39 changes: 39 additions & 0 deletions src/main/java/nextstep/subway/applicaion/dto/FavoriteResponse.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package nextstep.subway.applicaion.dto;

import nextstep.subway.domain.Favorite;

public class FavoriteResponse {
private Long id;
private Long memberId;

Choose a reason for hiding this comment

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

요구사항에 memberId 는 없네요!
요구사항을 확인해주세요 😄

private StationResponse source;
private StationResponse target;

private FavoriteResponse(Long id, Long memberId,
StationResponse source, StationResponse target) {
this.id = id;
this.memberId = memberId;
this.source = source;
this.target = target;
}

public static FavoriteResponse from(Favorite favorite) {
return new FavoriteResponse(favorite.getId(), favorite.getMemberId(),
StationResponse.of(favorite.getSource()), StationResponse.of(favorite.getTarget()));
}

public Long getId() {
return id;
}

public Long getMemberId() {
return memberId;
}

public StationResponse getSource() {
return source;
}

public StationResponse getTarget() {
return target;
}
}
61 changes: 61 additions & 0 deletions src/main/java/nextstep/subway/domain/Favorite.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package nextstep.subway.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

@Entity
public class Favorite {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@Column(name = "member_id")
private Long memberId;

@JoinColumn(name = "source_id")
@ManyToOne
private Station source;

@JoinColumn(name = "target_id")
@ManyToOne
private Station target;

private Favorite(Long memberId, Station source, Station target) {
this.memberId = memberId;
this.source = source;
this.target = target;
}

protected Favorite() {

}

public static Favorite of(Long memberId, Station source, Station target) {
return new Favorite(memberId, source, target);
}

public Long getId() {
return id;
}

public Long getMemberId() {
return memberId;
}

public Station getSource() {
return source;
}

public Station getTarget() {
return target;
}

public boolean hasPermission(Long memberId) {
return this.memberId.equals(memberId);
}
}
8 changes: 8 additions & 0 deletions src/main/java/nextstep/subway/domain/FavoriteRepository.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package nextstep.subway.domain;

import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;

public interface FavoriteRepository extends JpaRepository<Favorite, Long> {
List<Favorite> findAllByMemberId(Long memberId);
}
6 changes: 6 additions & 0 deletions src/main/java/nextstep/subway/domain/SubwayMap.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package nextstep.subway.domain;

import java.util.Optional;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
Expand All @@ -22,6 +23,11 @@ public Path findPath(Station source, Station target) {
DijkstraShortestPath<Station, SectionEdge> dijkstraShortestPath = new DijkstraShortestPath<>(graph);
GraphPath<Station, SectionEdge> result = dijkstraShortestPath.getPath(source, target);

Optional.ofNullable(result)
.orElseThrow(() -> {
throw new IllegalArgumentException("출발역과 도착역이 연결되어 있지 않습니다.");
});

Comment on lines +26 to +30

Choose a reason for hiding this comment

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

Optional 을 사용하신 이유가 있으신가요?
어떠한 이점이 있나요? 😄

Suggested change
Optional.ofNullable(result)
.orElseThrow(() -> {
throw new IllegalArgumentException("출발역과 도착역이 연결되어 있지 않습니다.");
});
if (Objects.isNull(result)) {
throw new IllegalArgumentException("출발역과 도착역이 연결되어 있지 않습니다.");
}

List<Section> sections = result.getEdgeList().stream()
.map(it -> it.getSection())
.collect(Collectors.toList());
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/nextstep/subway/ui/FavoriteController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package nextstep.subway.ui;

import java.net.URI;
import java.util.List;
import nextstep.auth.authorization.AuthenticationPrincipal;
import nextstep.member.domain.LoginMember;
import nextstep.subway.applicaion.FavoriteService;
import nextstep.subway.applicaion.dto.FavoriteRequest;
import nextstep.subway.applicaion.dto.FavoriteResponse;
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
public ResponseEntity<FavoriteResponse> createFavorite(

Choose a reason for hiding this comment

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

즐겨찾기 생성 후 반환값에 대한 요구사항을 확인해주세요! 😄
스크린샷 2022-02-22 오후 7 58 34

@AuthenticationPrincipal LoginMember loginMember,
@RequestBody FavoriteRequest favoriteRequest) {
FavoriteResponse favoriteResponse = favoriteService.createFavorite(favoriteRequest, loginMember.getId());
return ResponseEntity.created(URI.create("/favorites/" + favoriteResponse.getId())).body(favoriteResponse);
}

@GetMapping
public ResponseEntity<List<FavoriteResponse>> getFavorites(@AuthenticationPrincipal LoginMember loginMember) {
List<FavoriteResponse> favoriteResponses = favoriteService.findFavorites(loginMember.getId());
return ResponseEntity.ok(favoriteResponses);
}

@DeleteMapping("/{favoriteId}")
public ResponseEntity<Void> deleteFavorite(@AuthenticationPrincipal LoginMember loginMember, @PathVariable Long favoriteId) {
favoriteService.deleteFavorite(favoriteId, loginMember.getId());
return ResponseEntity.noContent().build();
}

}
Loading