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

[1단계 - 지하철 정보 관리 기능] 제이(이재윤) 미션 제출합니다. #41

Merged
merged 86 commits into from
May 14, 2023
Merged
Show file tree
Hide file tree
Changes from 64 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
badecaf
docs: 기능 구현 목록 작성
sosow0212 May 9, 2023
88217f6
feat: 테이블 DDL 추가 및 h2-console 설정
sosow0212 May 9, 2023
46a9c44
test: 기존 API 테스트
sosow0212 May 9, 2023
09c700d
style: 패키지 이동
sosow0212 May 9, 2023
747193d
refactor: 스키마 변경
sosow0212 May 9, 2023
ede015a
docs: 기능 구현 목록 수정
sosow0212 May 9, 2023
620d623
refactor: 스키마 변경
sosow0212 May 10, 2023
b478b1f
refactor: Line을 Domain과 Entity로 분리
sosow0212 May 10, 2023
ba43111
refactor: Station을 Domain과 Entity로 분리
sosow0212 May 10, 2023
2823a89
feat: Section과 이를 관리하는 Sections Domain 생성
sosow0212 May 10, 2023
17d9e76
refactor: 구조를 바꿈에 따라 임시 리팩토링 진행
sosow0212 May 10, 2023
3a87057
feat: Section(구간) 추가 기능 구현
sosow0212 May 10, 2023
630b5ae
refactor: 스키마 수정
sosow0212 May 10, 2023
043efa8
refactor: lineNumber 추가 (추후에 노선 구분 및 조회시 편리함을 위해서)
sosow0212 May 10, 2023
8b81494
feat: 지하철 노선도 검색 기능 추가
sosow0212 May 10, 2023
4519200
feat: 목데이터 추가
sosow0212 May 10, 2023
094b824
feat: 지하철 노선에서 역 삭제 기능 구현
sosow0212 May 10, 2023
bee59be
style: 컨벤션 적용 및 final 키워드 통일, 개행 통일
sosow0212 May 10, 2023
fbfcc8e
feat: Repository 계층 추가 및 Dao 연결
sosow0212 May 11, 2023
22e02c0
refactor: Repository 추가함에 따라 리팩토링 진행
sosow0212 May 11, 2023
a7447e2
refactor: Repository 추가 및 로직 도메인으로 이동
sosow0212 May 11, 2023
31de918
style: 디렉토리 명 변경 및 이동
sosow0212 May 11, 2023
719eb95
refactor: Repository 계층 추가로 리팩토링 진행
sosow0212 May 11, 2023
868dfaf
chore: Valid 종속성 추가
sosow0212 May 11, 2023
6b575d1
feat: 사용자 입력에 대한 예외 검증 기능 추가
sosow0212 May 11, 2023
52de9b1
feat: 예외 핸들러 추가
sosow0212 May 11, 2023
5215a13
fix: DAO 오타로 인한 문제 발생 로직 수정
sosow0212 May 11, 2023
3b1f5a2
refactor: 반환 값 void로 변경
sosow0212 May 11, 2023
25ee9ed
test: Line E2E 테스트 작성
sosow0212 May 11, 2023
0e193f6
test: Station E2E 테스트 작성
sosow0212 May 11, 2023
d7a8c9e
test: Section E2E 테스트
sosow0212 May 11, 2023
762c8a9
refactor: 테스트 격리
sosow0212 May 11, 2023
a3c2874
refactor: Transactional 추가
sosow0212 May 11, 2023
831f8ba
refactor: 사용하지 않는 메서드 제거
sosow0212 May 12, 2023
5bc6bff
refactor: if문 로직 변경
sosow0212 May 12, 2023
5a557b8
refactor: 불필요한 Enum 제거 및 예외 메시지 명확하게 변경
sosow0212 May 12, 2023
75f6b06
refactor: 메서드 분리 및 방어적 복사로 sections를 반환하도록 변경
sosow0212 May 12, 2023
9a62543
refactor: dto이름이 더욱 명확하도록 변경
sosow0212 May 12, 2023
15eaed7
style: 도메인 디렉토리 이동
sosow0212 May 12, 2023
ef596e4
feat: 원시값 포장 및 내부에서도 예외 처리하도록 진행
sosow0212 May 12, 2023
a795bc5
fix: 잘못된 예외 메시지 및 메서드명 수정
sosow0212 May 12, 2023
b3934eb
test: sections 테스트 작성
sosow0212 May 12, 2023
17c7d6d
test: LineMap 테스트 작성
sosow0212 May 12, 2023
fccd980
refactor: 불필요한 래퍼 클래스 사용 제거
sosow0212 May 12, 2023
3887c88
test: LineService의 통합 및 Mock을 이용한 단위테스트 작성
sosow0212 May 12, 2023
01262c3
test: StationService 통합 및 Mock을 이용한 단위테스트 작성
sosow0212 May 12, 2023
6f99eb0
test: SectionService 통합 및 Mock을 이용한 단위테스트 작성
sosow0212 May 12, 2023
7dd6ffc
test: SubwayMapService 통합 및 Mock을 이용한 단위테스트 작성
sosow0212 May 12, 2023
b6742e7
refactor: 안쓰는 예외 클래스 제거
sosow0212 May 12, 2023
a3ffab2
chore: slf4j 종속성 추가
sosow0212 May 13, 2023
738afac
refactor: 500에러에 대해 로그 출력 및 사용자에게는 관리자 문의 메시지로 변경
sosow0212 May 13, 2023
92558c8
refactor: 사용하지 않는 메서드 제거
sosow0212 May 13, 2023
f19a4fe
refactor: 불필요한 래퍼 클래스 제거
sosow0212 May 13, 2023
d18c340
refactor: Section에 id 필드 추가
sosow0212 May 13, 2023
a19a101
refactor: dfs 호출시마다 visited를 초기화하도록 변경
sosow0212 May 13, 2023
e3017d1
refactor: bfs로 변경 및 반환을 void에서 자료형으로 변경
sosow0212 May 13, 2023
7d2ec8d
refactor: 메서드명을 직관적으로 변경
sosow0212 May 13, 2023
89f1c0b
refactor: 메서드명 및 클래스명을 해당하는 객체에 맞게 직관적으로 변경
sosow0212 May 13, 2023
214c841
refactor: 메서드 분리 및 중복 메서드 제거
sosow0212 May 13, 2023
a31806d
refactor: 예외 클래스명 변경 및 더욱 명확한 설명 추가
sosow0212 May 13, 2023
c3bb697
style: Test Fixture 클래스의 네이밍 변경 (factory -> fixture)
sosow0212 May 13, 2023
d27dc18
test: SectionService의 예외 케이스 테스트 추가
sosow0212 May 13, 2023
8bbc1e6
test: StationService의 예외 케이스 테스트 추가
sosow0212 May 13, 2023
0ce53f5
refactor: 불필요한 래퍼클래스 제거
sosow0212 May 13, 2023
a29045b
refactor: 사용하지 않는 메서드, import 제거
sosow0212 May 14, 2023
eda8980
refactor: DAO에서 반환하는 id값의 타입 변경
sosow0212 May 14, 2023
70f61ad
refactor: Section 매핑해주는 메서드 분리
sosow0212 May 14, 2023
69bd5c3
refactor: 불필요한 필드를 메서드 내부로 변경
sosow0212 May 14, 2023
2980cdf
refactor: 유연한 객체 생성을 위해 정적 팩토리 메서드로 리팩토링 진행
sosow0212 May 14, 2023
076bf24
style: 통일성을 위해 단위 테스트 클래스 네이밍 변경 Mock -> Unit
sosow0212 May 14, 2023
c823aa1
refactor: 갈래길이 생기는 검증 로직을 distance에서 section으로 이전
sosow0212 May 14, 2023
3499c05
refactor: Station의 분기 파악을 위해 검증 로직을 insert로직 안으로 리팩토링 진행
sosow0212 May 14, 2023
e6742c1
refactor: 컨트롤러 반환값을 Entity에서 DTO로 변경
sosow0212 May 14, 2023
61977a3
refactor: 반환은 long, 조회는 Long 타입으로 변경
sosow0212 May 14, 2023
df6c90d
refactor: 메서드명 변경
sosow0212 May 14, 2023
c0817ed
feat: 라인 수정 기능 추가
sosow0212 May 14, 2023
83806ac
refactor: 메서드 명 변경
sosow0212 May 14, 2023
649520c
feat: 역 수정 기능 추가
sosow0212 May 14, 2023
e60ccaa
docs: http-request.http 추가 (Postman 역할)
sosow0212 May 14, 2023
7cc9a68
docs: 기능 구현 목록 수정
sosow0212 May 14, 2023
831dff5
test: StationController 단위 테스트 작성
sosow0212 May 14, 2023
a291e44
test: LineController 단위 테스트 작성
sosow0212 May 14, 2023
a769412
test: SectionController 단위 테스트 작성
sosow0212 May 14, 2023
0dc0df6
test: 추가 응답코드 테스트 작성
sosow0212 May 14, 2023
745dd58
test: 추가 응답코드 테스트 작성
sosow0212 May 14, 2023
1798814
style: 주석 수정
sosow0212 May 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
239 changes: 238 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,238 @@
# jwp-subway-path
# jwp-subway-path

---

## 기능 구현 목록

- [x] 테이블 설계
- [x] station(station_id, name)
- [x] line(line_id, color, name)
- [x] section(section_id, sectionA_id, sectionB_id)
- [x] station_in_line(station_point_id, section_id, line_id)
- [x] station_end_point (id, upStation_id, downStation_id)

- [ ] 테스트 작성
- [ ] 통합 테스트로 전체 플로우 테스트
- [ ] TDD 단위 테스트
- [ ] 계층 통합 테스트

- [ ] 도메인 로직 구현
- [ ] Graph 구현

## API 명세서

## Line Controller

### POST(/lines)

지하철 노선을 만든다.

**request**

```json
{
"name": "name",
"color": "color"
}
```

**response**

```json
{
"id": 1,
"name": "name",
"color": "color"
}
```

---

### GET(/lines)

지하철 전체 노선을 가져온다.

**request**

x

**response**

```json
[
{
"id": 1,
"name": "name",
"color": "color"
},
{
"id": 2,
"name": "name2",
"color": "color2"
}
]
```

---

### GET(/lines/{id})

id값에 해당하는 노선을 가져온다.

**request**

param : “id”

**response**

```json
{
"id": 1,
"name": "name",
"color": "color"
}
```

---

### PUT(/lines/{id})

id값에 해당하는 노선을 수정한다.

**request**

param : “id”

LineRequest

```json
{
"name": "nameEdit",
"color": "colorEdit"
}
```

**response**

x

---

### DELETE(/lines/{id})

id값에 해당하는 노선을 삭제한다.

**request**

param : “id”

**response**

x

---

---

## Station Controller

### POST(/stations)

지하철 역을 만든다.

**request**

```json
{
"name": "name"
}
```

**response**

```json
{
"id": 1,
"name": "name"
}
```

---

### GET(/stations)

지하철 전체 역을 가져온다.

**request**

x

**response**

```json
[
{
"id": 1,
"name": "name"
},
{
"id": 2,
"name": "name2"
}
]
```

---

### GET(/stations/{id})

id값에 해당하는 역을 가져온다.

**request**

param : “id”

**response**

```json
{
"id": 1,
"name": "name"
}
```

---

### PUT(/stations/{id})

id값에 해당하는 역을 수정한다.

**request**

param : “id”

LineRequest

```json
{
"name": "nameEdit"
}
```

**response**

x

---

### DELETE(/stations/{id})

id값에 해당하는 역을 삭제한다.

**request**

param : “id”

**response**

x
4 changes: 3 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ dependencies {
implementation 'org.springframework.boot:spring-boot-starter-jdbc'

implementation 'net.rakugakibox.spring.boot:logback-access-spring-boot-starter:2.7.1'
implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation'
implementation 'org.slf4j:slf4j-api:1.7.31'

testImplementation 'io.rest-assured:rest-assured:4.4.0'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
Expand All @@ -24,4 +26,4 @@ dependencies {

test {
useJUnitPlatform()
}
}
93 changes: 93 additions & 0 deletions src/main/java/subway/advice/GlobalExceptionHandler.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package subway.advice;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import subway.dto.exception.ExceptionResponse;
import subway.exception.*;

import java.util.stream.Collectors;

@RestControllerAdvice
public class GlobalExceptionHandler {
Laterality marked this conversation as resolved.
Show resolved Hide resolved

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ExceptionResponse> methodArgumentNotValidExceptionHandler(final MethodArgumentNotValidException exception) {
String message = exception.getFieldErrors().stream()
.map(DefaultMessageSourceResolvable::getDefaultMessage)
.collect(Collectors.joining(", "));

return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ExceptionResponse.from(message, HttpStatus.BAD_REQUEST.value()));
}

private static ResponseEntity<ExceptionResponse> getResponseOfBadRequest(final RuntimeException exception) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST)
.body(ExceptionResponse.from(exception.getMessage(), HttpStatus.BAD_REQUEST.value()));
}

@ExceptionHandler(DistanceForkedException.class)
public ResponseEntity<ExceptionResponse> distanceInvalidExceptionHandler(final DistanceForkedException exception) {
return getResponseOfBadRequest(exception);
}

@ExceptionHandler(SectionDuplicatedException.class)
public ResponseEntity<ExceptionResponse> sectionDuplicatedExceptionHandler(final SectionDuplicatedException exception) {
return getResponseOfBadRequest(exception);
}

@ExceptionHandler(NameIsBlankException.class)
public ResponseEntity<ExceptionResponse> nameIsBlankExceptionHandler(final NameIsBlankException exception) {
return getResponseOfBadRequest(exception);
}

@ExceptionHandler(InvalidDistanceException.class)
public ResponseEntity<ExceptionResponse> invalidDistanceExceptionHandler(final InvalidDistanceException exception) {
return getResponseOfBadRequest(exception);
}

@ExceptionHandler(LineNumberUnderMinimumNumber.class)
public ResponseEntity<ExceptionResponse> lineNumberUnderMinimumNumberHandler(final LineNumberUnderMinimumNumber exception) {
return getResponseOfBadRequest(exception);
}

@ExceptionHandler(SectionNotFoundException.class)
public ResponseEntity<ExceptionResponse> sectionNotFoundExceptionHandler(final SectionNotFoundException exception) {
return getResponseOfNotFound(exception);
}

private static ResponseEntity<ExceptionResponse> getResponseOfNotFound(final RuntimeException exception) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(ExceptionResponse.from(exception.getMessage(), HttpStatus.NOT_FOUND.value()));
}

@ExceptionHandler(UpStationNotFoundException.class)
public ResponseEntity<ExceptionResponse> upStationNotFoundExceptionHandler(final UpStationNotFoundException exception) {
return getResponseOfNotFound(exception);
}

@ExceptionHandler(ColorNotBlankException.class)
public ResponseEntity<ExceptionResponse> colorNotBlankExceptionHandler(final ColorNotBlankException exception) {
return getResponseOfNotFound(exception);
}

@ExceptionHandler(SectionNotConnectException.class)
public ResponseEntity<ExceptionResponse> sectionNotConnectExceptionHandler(final SectionNotConnectException exception) {
return getResponseOfNotFound(exception);
}

@ExceptionHandler(Exception.class)
public ResponseEntity<ExceptionResponse> internalServerErrorHandler(final Exception exception) {
Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
logger.error("Server error : " + exception.getMessage());

String internalServerErrorMessage = "내부 서버의 문제입니다. 관리자에게 문의해주세요.";
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body(ExceptionResponse.from(internalServerErrorMessage, HttpStatus.INTERNAL_SERVER_ERROR.value()));
}
}