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

[학성] 지하철 정보 관리 - 인수 테스트 미션 제출합니다. #2

Merged
merged 48 commits into from
May 14, 2020
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
47db1b3
[feat] create 기능 구현
joseph415 May 6, 2020
39c8edf
[feat] 인수테스트를 위한 기능 구현
joseph415 May 6, 2020
de22f86
[feat] resource file 추가
joseph415 May 6, 2020
26e2c48
[refactor] gitIgnore 추가, controller annotation 수정
joseph415 May 6, 2020
20cb2f2
[feat] 1단계 구현 완료
joseph415 May 7, 2020
94998ed
[feat] 2단계 구현 delete 구현
joseph415 May 7, 2020
d177ba0
[feat] LINE에 bgColor 필드 추가
joseph415 May 7, 2020
ab5323f
[feat] 2단계 조회 구현
joseph415 May 7, 2020
c958b4a
[refactor] id를 통해 테이터를 접근하도록 변경
joseph415 May 7, 2020
e32749c
[feat] 2단계 update 구현
joseph415 May 7, 2020
5c29b66
[feat] edit 하는 기능과 info 기능 구현
joseph415 May 8, 2020
986a35c
[feat] 3 단계 구현
joseph415 May 8, 2020
04f4b56
[feat] Line.getLineStationsId
joseph415 May 8, 2020
28e0b35
[feat] 4단계 add기능 구현
joseph415 May 8, 2020
6086bcc
feat : 역 삽입, 삭제추가
ordinCode May 8, 2020
054b237
feat : 4단계 완성
ordinCode May 8, 2020
5c017ff
feat : navbar 링크 url 수정
ordinCode May 8, 2020
b7330f7
feat : 구간추가 구현
ordinCode May 9, 2020
2776b45
refactor : LineService.findLineWithStationsById
ordinCode May 9, 2020
505db8e
feat : 프론트에서 구간 삭제기능 추가
ordinCode May 9, 2020
caf2bbb
refactor : LineController 분리
ordinCode May 9, 2020
4cf5d4a
refactor : LineStation
ordinCode May 9, 2020
e4b8c64
style
ordinCode May 9, 2020
c20cb95
feat : 취소 버튼 클릭시 정보 초기화 추가
ordinCode May 9, 2020
c01a32b
feat : 구간 추가시 각 호선의 아이디에 접근 못하던 문제 수정
ordinCode May 9, 2020
f256963
style
ordinCode May 9, 2020
5a0f382
refactor : LineService.validateTitle
ordinCode May 9, 2020
0a62468
refactor : LineController
ordinCode May 11, 2020
18da087
refactor : url 수정
ordinCode May 11, 2020
3c39990
refactor : LineResponse
ordinCode May 11, 2020
c0f1664
feat : AdminStation.js
ordinCode May 11, 2020
9f48090
feat : AdminStation.js
ordinCode May 11, 2020
d4be836
refactor : LineStationAcceptanceTest
ordinCode May 11, 2020
e1cbe31
refactor : StationController
ordinCode May 11, 2020
6320b00
refactor : LineController
ordinCode May 11, 2020
0ea08bc
refactor : LineStation
ordinCode May 11, 2020
9b14281
refactor : AdminEdge.js
ordinCode May 11, 2020
d1f7cd5
refactor : test 실패하던 것 수정
ordinCode May 11, 2020
18d9f0f
refactor : LineController.addStation
ordinCode May 11, 2020
3f03bfb
refactor : LineRequest.toLine 추가
ordinCode May 11, 2020
c8d8503
feat : NotFoundLineException
ordinCode May 11, 2020
c162c16
refactor : ResponseEntity 제네릭타입 지정
ordinCode May 11, 2020
049690e
refactor : LineService.getStationsByLine
ordinCode May 11, 2020
61945e8
refactor : AdminEdge.js
ordinCode May 11, 2020
5670163
refactor : LineService
ordinCode May 14, 2020
fd4f285
refactor : DuplicationNameException
ordinCode May 14, 2020
f1b5254
feat : StationResponse.listOf 추가
ordinCode May 14, 2020
8d0d32b
feat : ExceptionController 추가
ordinCode May 14, 2020
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ out/

### VS Code ###
.vscode/
.DS_Store
27 changes: 14 additions & 13 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
plugins {
id 'org.springframework.boot' version '2.2.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
id 'org.springframework.boot' version '2.2.5.RELEASE'
id 'io.spring.dependency-management' version '1.0.9.RELEASE'
id 'java'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'

repositories {
mavenCentral()
mavenCentral()
}

dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
testImplementation 'io.rest-assured:rest-assured:3.3.0'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
runtimeOnly 'com.h2database:h2'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-data-jdbc'
implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
implementation 'pl.allegro.tech.boot:handlebars-spring-boot-starter:0.3.1'
testImplementation 'io.rest-assured:rest-assured:3.3.0'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
runtimeOnly 'com.h2database:h2'
}

test {
useJUnitPlatform()
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@
@SpringBootApplication
public class SubwayAdminApplication {

public static void main(String[] args) {
SpringApplication.run(SubwayAdminApplication.class, args);
}
public static void main(String[] args) {
SpringApplication.run(SubwayAdminApplication.class, args);
}

}
105 changes: 105 additions & 0 deletions src/main/java/wooteco/subway/admin/controller/LineController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package wooteco.subway.admin.controller;

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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import wooteco.subway.admin.domain.Line;
import wooteco.subway.admin.domain.Station;
import wooteco.subway.admin.dto.LineRequest;
import wooteco.subway.admin.dto.LineResponse;
import wooteco.subway.admin.dto.LineStationCreateRequest;
import wooteco.subway.admin.service.LineService;
import wooteco.subway.admin.service.StationService;

import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/lines")
public class LineController {
private final LineService lineService;
private final StationService stationService;

public LineController(final LineService lineService, final StationService stationService) {
this.lineService = lineService;
this.stationService = stationService;
}

@PostMapping
public ResponseEntity createLine(@RequestBody LineRequest lineRequest) {
Copy link

Choose a reason for hiding this comment

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

한번에 많이 모든 곳을 처리하려 하지 말고 한번 여기에 한해서 예외 처리를 시도해보죠.

이름이 중복되면 IllegalArgumentException이 발생하는데 try-catch로 아래 형태로 응답해보세요.

return ResponseEntity.badRequest().body("message");

ResponseEntity 에 메시지를 담는 방법을 시도해봤는데 잘 되지 않네요.

사실 위의 방법도 시도해보셨을 수도 있을 것 같은데 조금 더 구체적으로 시도해보신 방법을 아는게 좋을 것 같아요. 여차하면 실패한 방법을 적용해서 push 해주시는 것도 좋을 것 같습니다.

lineService.validateTitle(lineRequest);
Line line = new Line(
lineRequest.getTitle(),
lineRequest.getStartTime(),
lineRequest.getEndTime(),
lineRequest.getIntervalTime(),
lineRequest.getBgColor()
);
Line savedLine = lineService.save(line);
return ResponseEntity.created(URI.create("/lines/" + savedLine.getId())).body(savedLine);
}

@GetMapping
public ResponseEntity findAllLine() {
List<LineResponse> lineResponses = lineService.findAll().stream()
.map(line -> lineService.findLineWithStationsById(line.getId()))
.collect(Collectors.toList());
return ResponseEntity.ok(lineResponses);
}

@GetMapping("/{id}")
public ResponseEntity findLine(@PathVariable Long id) {
return ResponseEntity.ok(lineService.findLineWithStationsById(id));
}

@PutMapping("/{id}")
public ResponseEntity updateLine(@PathVariable Long id, @RequestBody LineRequest lineRequest) {
lineService.validateTitleWhenUpdateInfo(id, lineRequest);
Copy link

Choose a reason for hiding this comment

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

컨트롤러에서 validateTitleWhenUpdateInfo 후 update하지 말고 lineService.updateLine에서 검증하는건 어떨까요?
검증과 update가 별도로 존재하면 다른 사람이 혹은 나중에 lineService.updateLine를 사용 할 때 validateTitleWhenUpdateInfo를 별도 호출하는 걸 빠트릴 수 있습니다.

Copy link

Choose a reason for hiding this comment

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

마찬가지로 Post /lines의 validateTitle도 컨트롤러에서 별도 호출이 아니라 저장 할 때 꼭 확인 해야할 로직으로 보입니다!

Copy link
Author

@ordinCode ordinCode May 11, 2020

Choose a reason for hiding this comment

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

감사합니다. 말씀하신부분은 제가 미처 생각을 하지 못했네요.
한가지 확실히 알았으면 하는 부분이 있습니다.

저는 controller 와 service 의 역할 구분을 "작업 흐름,전처리 vs 실질적인 작업 수행" 로 생각을 하였고, 그래서 controller 에서 유효성 검사를 하였습니다.
그런데 위와 같은 상황을 생각해보니 service 에서 하는게 맞는 것도 같네요.
그러면 결과적으로 대부분의 유효성 검사는 service 에서 하는게 맞다고 생각하면 될까요?
현업에서는 어떻게 하는지 궁금합니다

Copy link

Choose a reason for hiding this comment

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

눈으로만 그냥 가볍게 볼만한 자료는 안보이네요 😿
단순히 요청에 잘 못 된 값이 왔는지 정도는 앞서 말씀 드린 Map을 제가 비선호하는 이유중 하나인데 Request의 필드들에 특정 애노테이션을 붙이는 걸로도 검증을 할 수 있습니다.

https://jojoldu.tistory.com/129 에서 보면 @NotBlank(message = "이름을 작성해주세요.") 과 같은 애노테이션입니다. 일단 눈으로만 보시고 지금 이 방법은 적용하시지 말길 바랍니다. 이유는 지금 학습 단계가 스프링등 편히 쓸 수 있는 기능을 적극적으로 활용하는 단계는 아니고 스프링의 기본적인 사용에 익숙해지는 단계로 보입니다.
여러 기능을 사용하면 더 쉽고 편하게 사용 할 수는 있지만 기본적인 동작 원리를 놓칠 수 있기 때문에 아직 학습 단계에 나오지 않았고, 검증에 대한 깐깐함이 요구되는 상황도 아니라 현재는 곁가지에 해당 하는 해당 기능을 적극 사용할 필요는 없다고 보입니다.

유효성 검사는 service에서 주로 한다기보다는 앞서 말씀 드린 애노테이션으로 request에서 요청 데이터들에 대해서 검증 할 테고, 도메인에서도 생성 시 문제가 없는지 검증, 노선 이름이 중복되는지 여부에 대해서는 db를 통해야 하기 때문에 service에서 이뤄지겠네요.

Line line = new Line(
lineRequest.getTitle(),
lineRequest.getStartTime(),
lineRequest.getEndTime(),
lineRequest.getIntervalTime(),
lineRequest.getBgColor()
);
Copy link

Choose a reason for hiding this comment

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

lineRequest.toLine()을 통해서 line으로 변환해 줄 수 있을 것 같네요. 😉

Copy link

Choose a reason for hiding this comment

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

앗! 리뷰중 수정해주신 거 확인 했는데 LineStation을 보니 도메인 모델에서 of로 변환을 하시는데 도메인 모델에서 변환을 하시면 나중에 dto의 변경이 생길 때마다 도메인 모델도 변경을 해줘야 합니다.

Copy link
Author

Choose a reason for hiding this comment

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

아 그렇겠네요! 감사합니다

lineService.updateLine(id, line);
return ResponseEntity.ok().build();
}

@DeleteMapping("/{id:\\d+}")
Copy link

Choose a reason for hiding this comment

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

Suggested change
@DeleteMapping("/{id:\\d+}")
@DeleteMapping("/{id}")

public ResponseEntity deleteLine(@PathVariable Long id) {
lineService.deleteLineById(id);
return ResponseEntity.ok().build();
}

@PostMapping("/addStation/{id}")
Copy link

Choose a reason for hiding this comment

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

Line, Station, LineStation 중 어떤 Id인지 구분이 안됩니다. 특정 노선에 지하철 역을 추가한다는 걸 알 수 있게
/lines/{id}/stations 로 표현해주시는게 좋을 것 같습니다.
또한 post 요청에 이미 생성의 의미를 가지고 있기 때문에 add를 포함시킬 필요는 없습니다.

그리고 REST API 제대로 알고 사용하기4-2. URI 설계 시 주의할 점 > 5) URI 경로에는 소문자가 적합하다. 참고해주세요!

public ResponseEntity addStation(@PathVariable Long id,
@RequestBody HashMap<String, String> map) {
Copy link

Choose a reason for hiding this comment

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

이 부분은 코멘트에 남긴 것 처럼 map이 아니라 LineStationCreateRequest로 받아보세요.

Long preStationId = stationService.findStationId(map.get("preStationName"));
Station inputStation = stationService.save(map.get("stationName"));
Copy link

Choose a reason for hiding this comment

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

이 부분은 피드백을 드리기 전에 먼저 문의를 드리는게 좋을 것 같네요.

이전역은 저장되어 있는 역 중에서 조회를 하고, 대상역은 신규 생성을 하는 걸로 보이는데 요구사항에는 노선에 추가할 때의 지하철 역 존재 여부에 대한 내용이 보이진 않는 걸로 보여서 이 부분은 학성님이 어떻게 처리하고자 했는지 궁금하네요.

일단 지금 고려해 볼 수 있는 부분 중 하나는 이전역이 존재하지 않는 경우, 대상역이 중복되는 경우겠네요.

Copy link

Choose a reason for hiding this comment

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

혹시 지하철 존재여부에 대해서 고민하셨다면 해볼 수 있는 방법 중 하나는 구간 추가 화면에서 이전/대상역을 지하철 역을 조회 후 저장되어 있는 역만 셀렉 박스로 제공 할 수 있을 것 같습니다.
(이전/대상역이 없을 수 있으니 없음 같은 값도 추가가 필요하겠네요.)
방법 중 하나 일 뿐 꼭 이렇게 구현할 필요는 없습니다. 그래서 먼저 어떤 방향으로 고려를 하셨는지 여쭤보는 겁니다. 😉

Copy link

Choose a reason for hiding this comment

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

+ 기존에는 request 모델을 사용한 걸로 보이는데 map으로 바꾸신 이유가 있을까요?

Copy link
Author

@ordinCode ordinCode May 11, 2020

Choose a reason for hiding this comment

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

이부분은 착오가 있었네요.
이미 등록되어있는 역을 가지고 어느 라인, 어느 역 다음에 연결할 지 서로 mapping 시켜주는 로직인데 생성까지 했던 것은 제 실수였습니다.

그래서 이 다음 리뷰와 관련해서 생성되어 있는 지하철역들을 연결지켜주는 로직으로 변경하였습니다.
또한 휴가 말씀하신대로 구간 추가 화면에서 저장되어 있는 역을 셀렉박스로 제공하는 것도 좋은 방법으로 생각되네요. 시간관계 상 리뷰요청을 보낸뒤에 한번 시도해보겠습니다.

Copy link
Author

Choose a reason for hiding this comment

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

그리고 위에 말씀하신부분이 이 부분이 맞는지는 모르겠지만 처음에는

@PostMapping("/{id}/stations")
    public ResponseEntity addStation(@PathVariable Long id,
                                     @RequestBody String preStationName,
                                     @RequestBody String stationName,
                                     @RequestBody String distance,
                                     @RequestBody String duration) {

이렇게 했었는데 인식이 안되길래 map으로 바꾸었습니다.

map은 잘 쓰지 않는 방법인가요?

Copy link

Choose a reason for hiding this comment

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

map 많이 쓴다면 많이 쓰고 아니라면 아닙니다.
map<String, Object> -> Object에 또다른 map<String, Object> -> Object에 또다른 map<String, Object> 이 들어가 있는 지옥같은 환경일 수도 있습니다. 🙀

Request에 대한 관리가 안된다는 측면에서 저는 map의 사용은 비추합니다. 그리고 차후에 배우겠지만(아마도 빠르면 즐겨찾기에서 문서자동화 부분) request모델을 사용하면 좀더 쉽게 추가 기능들을 붙일 수 있답니다.

올려주신 코드가 안되신 이유는 http를 다시 한번 생각해보면 하나의 Request에는 하나의 body밖에는 존재하지 않습니다! 그렇기 때문에 여러개의 ReqeustBody는 사용이 불가합니다.
필요한 데이터를 xxRequest라는 이름의 Data Transfer Object로 받아아 주시면 됩니다.


LineStationCreateRequest lineStationCreateRequest =
new LineStationCreateRequest(
preStationId,
inputStation.getId(),
Integer.parseInt(map.get("distance")),
Integer.parseInt(map.get("duration")));

lineService.addLineStation(id, lineStationCreateRequest);
return ResponseEntity.ok().build();
}

@DeleteMapping("/station/{lineId}/{stationId}")
Copy link

Choose a reason for hiding this comment

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

lines/{lineId}/stations/{stationId}가 되어야 할 것 같네요.
실제 사용 될때를 생각해보시면 쉽답니다.
/lines/station/2/3
/lines/2/stations/3

public ResponseEntity deleteStation(@PathVariable Long lineId, @PathVariable Long stationId) {
lineService.removeLineStation(lineId, stationId);
return ResponseEntity.ok().build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package wooteco.subway.admin.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import wooteco.subway.admin.service.LineService;

@RestController
public class LineStationController {
private final LineService lineService;

public LineStationController(final LineService lineService) {
this.lineService = lineService;
}

@GetMapping("/lineStations/{lineId}")
public ResponseEntity findAllLineStations(@PathVariable Long lineId) {
return ResponseEntity.ok(lineService.findLineStationByLineId(lineId));
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
package wooteco.subway.admin.controller;

import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
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.RestController;
import wooteco.subway.admin.domain.Station;
import wooteco.subway.admin.dto.StationCreateRequest;
import wooteco.subway.admin.dto.StationResponse;
Expand All @@ -20,11 +25,19 @@ public StationController(StationRepository stationRepository) {
@PostMapping("/stations")
public ResponseEntity createStation(@RequestBody StationCreateRequest view) {
Station station = view.toStation();
Station persistStation = stationRepository.save(station);
validateName(station.getName());

Station persistStation = stationRepository.save(station);
Copy link

Choose a reason for hiding this comment

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

Service가 아닌 Controller에서 repository를 직접 사용하고 계시네요.
stationService.save에서도 이름에 대한 검증이 필요할 것 같아요.

return ResponseEntity
.created(URI.create("/stations/" + persistStation.getId()))
.body(StationResponse.of(persistStation));
.created(URI.create("/stations/" + persistStation.getId()))
.body(StationResponse.of(persistStation));
}

private void validateName(final String stationName) {
stationRepository.findByName(stationName)
.ifPresent(station -> {
throw new IllegalArgumentException("존재하는 역 이름입니다");
});
}

@GetMapping("/stations")
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/wooteco/subway/admin/controller/WebController.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package wooteco.subway.admin.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller
public class WebController {
@GetMapping("/")
public String index() {
return "index";
}

@GetMapping("/admin-line")
public String adminLine() {
return "admin-line";
}

@GetMapping("/admin-edge")
public String adminEdge() {
return "admin-edge";
}

@GetMapping("/admin-station")
public String adminStation() {
return "admin-station";
}
}
89 changes: 74 additions & 15 deletions src/main/java/wooteco/subway/admin/domain/Line.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,41 +4,48 @@

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class Line {
@Id
private Long id;
private String name;
private String title;
private LocalTime startTime;
private LocalTime endTime;
private int intervalTime;
private Set<LineStation> stations;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
private String bgColor;

public Line() {
}

public Line(Long id, String name, LocalTime startTime, LocalTime endTime, int intervalTime) {
this.name = name;
public Line(Long id, String title, LocalTime startTime, LocalTime endTime, int intervalTime, String bgColor) {
this.title = title;
this.startTime = startTime;
this.endTime = endTime;
this.intervalTime = intervalTime;
this.createdAt = LocalDateTime.now();
this.updatedAt = LocalDateTime.now();
this.bgColor = bgColor;
this.stations = new LinkedHashSet<>();
}

public Line(String name, LocalTime startTime, LocalTime endTime, int intervalTime) {
this(null, name, startTime, endTime, intervalTime);
public Line(String title, LocalTime startTime, LocalTime endTime, int intervalTime, String bgColor) {
this(null, title, startTime, endTime, intervalTime, bgColor);
}

public Long getId() {
return id;
}

public String getName() {
return name;
public String getTitle() {
return title;
}

public LocalTime getStartTime() {
Expand All @@ -65,9 +72,13 @@ public LocalDateTime getUpdatedAt() {
return updatedAt;
}

public String getBgColor() {
return bgColor;
}

public void update(Line line) {
if (line.getName() != null) {
this.name = line.getName();
if (line.getTitle() != null) {
this.title = line.getTitle();
}
if (line.getStartTime() != null) {
this.startTime = line.getStartTime();
Expand All @@ -78,20 +89,68 @@ public void update(Line line) {
if (line.getIntervalTime() != 0) {
this.intervalTime = line.getIntervalTime();
}
if (line.getBgColor() != null) {
this.bgColor = line.getBgColor();
}

this.updatedAt = LocalDateTime.now();
}

public void addLineStation(LineStation lineStation) {
// TODO: 구현
this.stations.add(lineStation);
}

public void removeLineStationById(Long stationId) {
// TODO: 구현
public void removeLineStationById(Long id) {
this.stations.stream()
.filter(x -> x.isStationIdEquals(id))
.findAny()
.ifPresent(target -> {
this.stations.remove(target);
});
}

public List<Long> getLineStationsId() {
// TODO: 구현
return new ArrayList<>();
List<LineStation> result = new ArrayList<>();
stations.stream()
.filter(x -> x.isPreStationIdEquals(LineStation.NULL_PRE_STATION_VALUE))
.findAny()
.ifPresent(result::add);

for (int i = 0; i < stations.size() - 1; i++) {
result.add(findNextLineStation(result.get(i)));
}
return result.stream()
.map(LineStation::getStationId)
.collect(Collectors.toList());
}

private LineStation findNextLineStation(final LineStation preStation) {
return stations.stream()
.filter(x -> x.isPreStationIdEquals(preStation.getStationId()))
.findAny().orElseThrow(IllegalArgumentException::new);
}

public void updatePreStationWhenAdd(final LineStation toInput) {
stations.stream()
.filter(x -> x.isPreStationIdEquals(toInput.getPreStationId()))
.findAny().ifPresent(lineStation -> {
lineStation.updatePreLineStation(toInput.getStationId());
});
}

public void updatePreStationWhenRemove(final Long toRemoveId) {
LineStation removeStation =
stations.stream().filter(x -> x.isStationIdEquals(toRemoveId))
.findAny().orElseThrow(IllegalArgumentException::new);

stations.stream()
.filter(x -> x.isPreStationIdEquals(toRemoveId))
.findAny().ifPresent(lineStation -> {
lineStation.updatePreLineStation(removeStation.getPreStationId());
});
}

public boolean isTitleEquals(final String title) {
return this.title.equals(title);
}
}
Loading