DevLog ๐ถ
[์ฐํ ์ฝ 5๊ธฐ] ์น ์๋์ฐจ ๊ฒฝ์ฃผ ๋ฏธ์ ํ๊ณ ๋ณธ๋ฌธ
[์ฐํ ์ฝ 5๊ธฐ] ์น ์๋์ฐจ ๊ฒฝ์ฃผ ๋ฏธ์ ํ๊ณ
dolmeng2 2023. 4. 20. 15:40๋๋ ๊ณผ ์งํํ ๋ ๋ฒจ 2 ์ฒซ ํ์ด ํ๋ก๊ทธ๋๋ฐ ๋ฏธ์ ์ธ ์น ์๋์ฐจ ๊ฒฝ์ฃผ ๋ฏธ์ ์ด๋ค :D
์ด์ฉ๋ค ๋ณด๋ 1๋ฑ์ผ๋ก ๋ ๋ฒจ 2 ์ฒซ ๋ฏธ์ ์ ๋ง๋ฌด๋ฆฌํ๊ฒ ๋์๋ค ๐
๋ ๋ฒจ 2์ ๋ชฉํ๋ ๋ฏธ์ ์ ๋ํ ํ๊ณ ๊ธ์ด ๋ฐ๋ฆฌ์ง ์๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์, ๋น ๋ฅด๊ฒ ํ๊ณ ๊ธ์ ์์ฑํด๋ณด๊ณ ์ ํ๋ค.
์ด๋ฒ ๋ฏธ์ ์ ์๊ตฌ์ฌํญ์ ๋นํด ๋ฏธ์ ๊ธฐ๊ฐ์ด ๊ธธ์๊ธฐ ๋๋ฌธ์, ๋ฏธ์ ์ ์ฌ์ ๋กญ๊ฒ ์งํํ ์ ์์๋ค.
๋จ์ ๊ธฐ๊ฐ ๋์์๋ ์คํ๋ง์ ๋ํด์ ์ข ๊ณต๋ถํด๋ณด๋ ์๊ธฐ๋ก ๊ฐ์ ธ๋ณด๋ ค๊ณ ํ๋ค.
โ๏ธ ์์ฑํ ์ฝ๋
- PR ์ ์ถ ์ดํ ์กฐ๊ธ ๋ ์์ ํ ๋ถ๋ถ์ด ์์ด์ ์๋ง 2์ฐจ PR์ ๋ง์ง๋ง ๋ถ๋ถ๊ณผ ์กฐ๊ธ ๋ค๋ฆ ๋๋ค!
โ๏ธ 1์ฐจ PR
โ๏ธ 2์ฐจ PR
โ๏ธ ๊ธฐ๋ฅ ์๊ตฌ์ฌํญ
- ์๋์ฐจ ๊ฒฝ์ฃผ ์ฝ๋ ๊ฐ์ ธ์ค๊ธฐ (๋ ๋ฒจ 1 ๋ ์งํํ๋ ์ฝ๋ ๊ฐ์ ธ์ค๊ธฐ)
- ์น ์์ฒญ/์๋ต ๊ตฌํํ๊ธฐ
: ์น์ ํตํด ๊ฒ์์ ํ๋ ์ด ํ ์ ์๋๋ก ๊ตฌํํ์ธ์.
Request
POST /plays HTTP/1.1
content-type: application/json; charset=UTF-8
host: localhost:8080
{
"names": "๋ธ๋ฆฌ,ํ ๋ฏธ,๋ธ๋ผ์ด",
"count": 10
}
Response
HTTP/1.1 200
Content-Type: application/json
{
"winners": "๋ธ๋ฆฌ",
"racingCars": [
{
"name": "๋ธ๋ฆฌ",
"position": 9
},
{
"name": "ํ ๋ฏธ",
"position": 7
},
{
"name": "๋ธ๋ผ์ด",
"position": 3
},
]
}
- DB ์ฐ๋ํ๊ธฐ (H2 DB ์ฐ๋)
DB์ ์ ์ฅ๋๋ ์ ๋ณด๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
: ํ๋ ์ด ํ์(trialCount)
: ํ๋ ์ด์ด ๋ณ ์ต์ข
์ด๋ ๊ฑฐ๋ฆฌ (์ด๋ฆ(name), ์ต์ข
์์น(position))
: ์ฐ์น์(winners)
: ํ๋ ์ดํ ๋ ์ง/์๊ฐ
- ๊ฒ์ ํ๋ ์ด ์ด๋ ฅ ์กฐํ API ๊ตฌํ
: web application์์ DB์ ์ ์ฅ๋ ํ๋ ์ด ์ด๋ ฅ์ ์์ฒญํ๋ฉด ์๋ตํ๋ ๊ธฐ๋ฅ์ ๊ตฌํํฉ๋๋ค.
HTTP/1.1 200
Content-Type: application/json
[
{
"winners": "๋ธ๋ฆฌ",
"racingCars": [
{
"name": "๋ธ๋ฆฌ",
"position": 6
},
{
"name": "ํ ๋ฏธ",
"position": 4
},
{
"name": "๋ธ๋ผ์ด",
"position": 3
},
]
},
{
"winners": "๋ธ๋ฆฌ,ํ ๋ฏธ,๋ธ๋ผ์ด",
"racingCars": [
{
"name": "๋ธ๋ฆฌ",
"position": 6
},
{
"name": "ํ ๋ฏธ",
"position": 6
},
{
"name": "๋ธ๋ผ์ด",
"position": 6
},
]
}
]
์ด๋ฒ์๋ ๋ง์ ์ด์ผ๊ธฐ๋ฅผ ๋๋ ๊ฒ ์๋์์ด์, ์์ผ๋ก ๊ณ ๋ฏผํ ๋ถ๋ถ๊ณผ ๊ณ ๋ฏผํ๋ ๋ถ๋ถ์ ๋ํด ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
๐ฌ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด alert ํด์ฃผ๊ธฐ
์ฌ์ค ์ด๊ฑฐ๋ html ๊ด๋ จ์ด์ง๋ง, ๋๋ ์ด๋ ์ด๊ฑฐ ํ๋ ค๊ณ 30๋ถ ์ ๋๋ ์ฝ์งํ๋ ๊ฒ ๊ฐ์์ ์ ์ด๋๋ค.
๊ธฐ์กด์ html ์คํ์์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ด๋ถ ์ฝ์์์๋ง 400 ์๋ฌ๊ฐ ๋ฐ์ํ๊ณ , ์๋ฌด๋ฐ ์ผ๋ ๋ฐ์ํ์ง ์์๋ค.
ํ์ง๋ง ๋ญ๊ฐ ์ฌ์ฉ์ ์ ์ฅ์์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋ ๋ญ๊ฐ ๋ํ๋ฌ์ผ๋ฉด ์ข๊ฒ ์ด์, alert ๊ธฐ๋ฅ์ ์ถ๊ฐํ์๋ค.
์ด๋ฐ ์์ผ๋ก ์ค๋ฅ ๋ฐ์ ์ ์๋ฆผ์ด ๊ฐ๋ค.
fetch("/plays", {
method: "POST",
headers: {
"Content-Type": "application/json;charset=UTF-8"
},
body: JSON.stringify(data)
})
...
.catch(error => {
window.alert(JSON.parse(error.message).message);
console.error("Error:", error);
});
๊ทธ๋ฅ ์๋์ฒ๋ผ ์๋ฌ ๋ฉ์์ง๋ฅผ ๊บผ๋ธ ๋ค์์ (JSON.parse๋ฅผ ํตํด json ํํ๋ก ๋ด๋ ค์จ ๊ฐ์์ ๊บผ๋ด๋ ๊ฒ) alert ํด์ฃผ๋ฉด ๋๋ค.
๐ฌ ๋๋ฉ์ธ์์ ๊ด๋ฆฌํ๋ ์์ธ ๋ฉ์์ง๋ฅผ ๊ทธ๋๋ก ๋ทฐ์ ๋ ธ์ถ์์ผ๋ ๋๋๊ฐ?
๋ ๋ฒจ 1 ๋ฏธ์ ์์๋ '์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ฐ์ํ ์ง์ ์์ ๊ด๋ฆฌํด์ผ ํ๋ค' ๋ผ๋ ๊ฒ์ ์ด์ ์ ๋ง์ถ๋ค ๋ณด๋, ์ฝ์์ ๋ทฐ์ ์์ธ ๋ฉ์์ง๊ฐ ์ถ๋ ฅ๋์ด๋ ๊ทธ๋ ๊ฒ ์ ๊ฒฝ์ฐ์ง ์์๋ค. ํ์ง๋ง, ์ด๋ฒ์๋ ์น์ธ ์ํฉ์ด๊ณ html์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ฌ์ฉ์์๊ฒ ๋ ธ์ถ๋๋ ๋ฉ์์ง๊ฐ ๋๋ฉ์ธ์์ ๊ด๋ฆฌ๋๋ ๊ฒ๊ณผ ๋์ผํด์ง๋ค.
๋ง์ฝ ๋ค๊ตญ์ด ๊ธฐ๋ฅ์ ์ถ๊ฐํ๋ค๋ฉด? ํน์, view์ ๋ฐ๋ผ ๋ค๋ฅธ ๋ฌธ๊ตฌ๋ฅผ ์ถ๋ ฅํด์ผ ํ๋ค๋ฉด?
๋๋ฉ์ธ์์ ๊ด๋ฆฌํ๋ ๊ฒ๋ณด๋ค ๋ค๋ฅธ ์ธ๋ถ์์ ๊ด๋ฆฌํ๋๋ก ํ๋ ๊ฒ์ด ์ข์ ๊ฒ์ด๋ค.
๊ธฐ์กด์ ์ฝ๋์ด๋ค.
@ExceptionHandler(IllegalArgumentException.class)
public ResponseEntity<ExceptionDto> handleIllegalArgumentException(final IllegalArgumentException exception) {
final ExceptionDto exceptionDto = new ExceptionDto(exception.getMessage());
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(exceptionDto);
}
๋๋ฉ์ธ์์ ๋ฐ์๋๋ IllegalArgumentException์ ๋ด๊ธด message๋ฅผ ๊บผ๋ด์์ response body๋ก ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ ๋๋ฉ์ธ์์๋ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ฅ๋ฅผ ๋ฐ์์์ผฐ์๋ค.
private void validateDuplicateCarName() {
int uniqueCarCount = new HashSet<>(cars).size();
if (cars.size() != uniqueCarCount) {
throw new DuplicateException(DUPLICATE_MESSAGE);
}
}
์ด๊ฑธ ์ด๋ค ์์ผ๋ก ํด๊ฒฐํ ์ ์์๊น ๊ณ ๋ฏผํ๋ค๊ฐ 2๊ฐ์ง ๋ฐฉ๋ฒ์ ๊ณ ์ํ๋ค.
1. ๋๋ฉ์ธ๋ง๋ค ๊ฐ๊ฐ ๋ค๋ฅธ ์์ธ๋ฅผ ๋ฐ์์์ผ์ ExceptionHandler์์ ์์ธ ์ํฉ์ ๋ง๊ฒ ์ฒ๋ฆฌํ๊ธฐ.
2. ์์ธ๋ ๋์ผํ๊ฒ ๋๋, enum์ ํตํ ErrorCode๋ฅผ ์ฌ์ฉํ์ฌ ๊ด๋ฆฌํ๊ธฐ
์ฒ์์๋ 2๋ฒ ๋ฐฉ์์ ์ฌ์ฉํ ๊น ๊ณ ๋ฏผํ๋ค๊ฐ, ErrorCode์ ๊ฒฝ์ฐ 400, 404 ์ธ์ ์ปค์คํ ์ํ ์ฝ๋๋ฅผ ๋ง๋๋ ๊ฒ๊ณผ ๋น์ทํ๋ค๊ณ ์๊ฐํ๊ณ (๊ฐ์ธ์ ์ธ ์๊ฐ), ํ์ฌ๋ ์ฌ์ฉ์์ ์๋ชป๋ ์ ๋ ฅ ๊ฐ์ ๋ํด์ ์ฒ๋ฆฌํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ์ํ ์ฝ๋ ์ชฝ๊ณผ๋ ๊ด๋ จ์๊ฒ ํ๊ณ ์ถ์ง ์์๋ค.
๋ฏธ์ ์ด ์ข ๋ฃ๋ ์ง๊ธ ์๊ฐํด๋ณด๋ฉด, ๊ทธ๋ฅ ErrorCode๋ผ๋ ์ด๋ฆ ๋์ ์ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ enum์ผ๋ก ๋๊ณ , ๋ด๋ถ์์ ๋ฉ์์ง๋ฅผ ๋ณ์๋ก ๊ด๋ฆฌํด์ ExceptionHandler์์๋ ํด๋น ๊ฐ์ฒด์ ๋ด๊ธด ๋ฉ์์ง๋ฅผ ์ถ๋ ฅํ๋๋ก ํด๋ ๋์ง ์์์๊น ์ถ๋ค.
์ฐ์ , ๊ธฐ๋ณธ์ ์ผ๋ก ๋์ด์จ ๊ฐ์ด null์ด๊ฑฐ๋ ๋น์ด์๋ ๊ฒ์ ๋ํ ์ฒดํฌ๋ Request DTO์๊ฒ ์ฑ ์์ ๋๊ฒผ๋ค.
public class RaceRequest {
@NotBlank(message = "์๋์ฐจ ์ด๋ฆ์ ๋น์ด์์ ์ ์์ต๋๋ค.")
private final String names;
@NotNull(message = "๊ฒฝ์ฃผ ํ์๋ ๋น์ด์์ ์ ์์ต๋๋ค.")
private final int count;
...
}
DTO๋ ๋ทฐ์์ ๋ฐ์์จ ๋ฐ์ดํฐ๋ฅผ ๋๊ฒจ์ฃผ๋ ์ญํ ์ด๊ธฐ ๋๋ฌธ์ message๋ฅผ ๊ด๋ฆฌํด๋ ์๊ด์๋ค๊ณ ์๊ฐํ์๊ณ ,
๋๋ฉ์ธ์์๋ ์์ํ๊ฒ ์์ ํ ๊ฐ์ ๋ฐ๋ ๊ฒ์ด ๋ง๋ค๊ณ ์๊ฐํ๊ธฐ ๋๋ฌธ์ validation annotation์ ํตํ์ฌ ๊ด๋ฆฌํ๋ค.
๊ทธ์ธ์ ์ปค์คํ ์์ธ๋ ๋ค์๊ณผ ๊ฐ์ด ์งํํ์๋ค.
public class ErrorData<T> {
private final T data;
public ErrorData(final T data) {
this.data = data;
}
public T getData() {
return data;
}
}
์ฐ์ , ErrorData๋ผ๋ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์๋ค. ์ด๋ ๋๋ฉ์ธ๋ณ๋ก ๋ค๋ฅธ ์ ํ ์กฐ๊ฑด์ ์์ธ ๋ฉ์์ง์ ์ ๋์ ์ผ๋ก ๋ด๊ธฐ ์ํด์ ๋ง๋ค์๋ค.
private void validateRange(final int raceCount) {
if (raceCount <= MIN_RACE_COUNT) {
throw new ResourceMinRangeException(new ErrorData<>(MIN_RACE_COUNT));
}
}
๊ทธ๋ฆฌ๊ณ ๋ค์๊ณผ ๊ฐ์ด ์์ธ๋ฅผ ๊ฒ์ฆํ์๋ค. ์ด๋ ์ ๋ ฅ์ผ๋ก ๋ค์ด์จ ๊ฒฝ์ฃผ ํ์๊ฐ ์ต์ ํ์ ์ดํ์ธ์ง ๊ฒ์ฆํ๋ ๋ถ๋ถ์ด๋ค.
์ธ์๋ก ๋๋ฉ์ธ์ ๊ท์น์ธ '0๋ฒ ์ดํ'์ ๊ฐ์ ๋ด๋ MIN_RACE_COUNT๋ฅผ ๋ด์๋ค.
๋ฌผ๋ก @Range ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํด๋ ๋์ง๋ง, ๋๋ ๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ฌ์ฉํ์ง ์์๋ค.
1. raceCount๊ฐ 0 ์ดํ๋ผ๋ ๊ฐ์ ๋๋ฉ์ธ ์์ฒด์ ๊ท์น์ด๋ผ๋ ์๊ฐ์ด ๋ค์๋ค.
(๋ง์ฝ ์๊ตฌ์ฌํญ์ด ๋ณ๊ฒฝ๋์ด์ ๊ฒฝ์ฃผ ํ์๋ ์ต์ 5๋ฒ๋ถํฐ ๋ฐ์์ผ ํ๋ค๋ฉด?)
2. ๋๋ฉ์ธ์์ @Range๋ฅผ ํตํด ์ธ์๋ก message๋ฅผ ๋๊ธฐ๋ฉด ๊ฒฐ๊ตญ ๋ทฐ์ ๋ณด์ฌ์ง ๊ฐ์ ๋ ๋ค์ ๋๋ฉ์ธ์์ ๊ด๋ฆฌํ๋ ๊ฒ ๊ฐ์๋ค.
๐ฑ ์ด ๋ถ๋ถ์ ๋ํด์๋ ๋ฆฌ๋ทฐ์ด๋์ด ์๊ฒฌ์ ๋จ๊ฒจ์ฃผ์ จ์ด์ ๋ฉ๋ชจํด๋๊ณ ์ ํ๋ค.
- Presentation Layer์์ ๊ฒ์ฆ๋์ด์ผ ํ๋ ๋ถ๋ถ๊ณผ ๋๋ฉ์ธ์์ ๊ฒ์ฆ๋์ด์ผ ํ๋ ๋ถ๋ถ์ด ์๋ค.
๋๋ฉ์ธ์ ์ผ๋ฐ์ ์ผ๋ก ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ์ ์ฉ๋์ด์ผ ํ๋ ๊ณตํต์ ์ธ '๋๋ฉ์ธ ๊ท์น'์ด๊ณ , ํด๋ผ์ด์ธํธ์ ๋ฐ๋ผ์ ์ ์ฉ๋์ด์ผ ํ๋ ๊ท์น์ ๋๋ฉ์ธ์ ์์ผ๋ฉด ์ ๋๋ค. (ํน์ ํ view๋ฅผ ์์กดํด์ ์ ๋๊ธฐ ๋๋ฌธ์ด๋ค)
๊ทธ๋์ ์๋ฅผ ๋ค์ด๋ณด์๋ฉด, '์๋์ฐจ ์ด๋ฆ์ด 10์ ์ด๋ด์ฌ์ผ ํ๋ค'๋ผ๋ ๊ท์น์ด ๋ชจ๋ ํด๋ผ์ด์ธํธ์๊ฒ ์ ์ฉ๋์ด์ผ ํ๋ค๋ฉด ๋๋ฉ์ธ์ ๊ท์น์ด ๋ ๊ฒ์ด๊ณ , ์ฝ์์์๋ 10์, ์น์์๋ 20์ ๊ฐ์ด ํด๋ผ์ด์ธํธ์ ๋ฐ๋ผ ๋ฌ๋ผ์ง๋ ๊ท์น์ด๋ผ๋ฉด Presentation Layer์์ ๊ฒ์ฆํด์ผ ํ๋ ๊ท์น์ด ๋๋ค.
๋ค๋ง, ๊ฐ ๋๋ฉ์ธ๋ง๋ค ๋ชจ๋ ์์ธ ๋ฉ์์ง๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ์์ธ๋ฅผ ๋ด๋ ๊ฐ์ฒด๊ฐ ๋๋ฌด ๋ง์์ง ์๋ ์์ ๊ฒ ๊ฐ์์ ์ฐ์ ์ ์ด๋ฆ์ ๋ฒ์ฉ์ ์ผ๋ก ์ง์๋ค. ์ด๊ฑฐ๋ ์ด์ ๋ฏธ์ ์์ ๋ค๋ฅธ ๋ฆฌ๋ทฐ์ด๋๊ณผ๋ ์๊ธฐ๋ฅผ ๋๋ ๋ณธ ์ ์ด ์์์ด์, ์ฌ์ค ๊ฝค ๊ณ ๋ฏผ์ด ๋๋ ๋ถ๋ถ์ด์๋๋ฐ ์ฐ์ ์ ErrorCode๋ฅผ ์ ๋ค๋ฆญํ๊ฒ ๋ง๋ค์๊ณ , ๋ฐ์๋๋ ์ด์ ๊ฐ ๋ณ๋ก ์๊ธฐ ๋๋ฌธ์ ์ด๋ ๊ฒ ํด๋ ํ ์์ธ๊ฐ ํ๋์ ๋๋ฉ์ธ์์๋ง ์ฌ์ฉ๋๊ณ ์์ด์ ๊ด์ฐฎ๋ค๊ณ ์๊ฐํ๋ค.
public class ResourceMinRangeException extends RuntimeException {
private final ErrorData<Integer> range;
public ResourceMinRangeException(final ErrorData<Integer> range) {
this.range = range;
}
public ErrorData<Integer> getRange() {
return range;
}
}
์์ธ ๊ฐ์ฒด๋ ๋ค์๊ณผ ๊ฐ์ด ๋ง๋ค์๋ค. ์์์ด ์ต์ ๋ฒ์ ๋ฏธ๋ง์ ๊ฐ์ ๊ฐ์ก์ ๋ ๋ฐ์ํ๋ ์ค๋ฅ๋ผ๋ ์๋ฏธ๋ก ๋ด์๋ค.
๊ทธ๋ฆฌ๊ณ , ํด๋น ๋ฒ์๋ฅผ ๋ด๋ถ์์ ์ธ์๋ก ๊ด๋ฆฌํ ์ ์๋๋ก (ErrorData<Integer>) ํํ๋ก ๋ง๋ค์๋ค.
๋ง์ง๋ง์ผ๋ก @ExceptionHandler๋ฅผ ํตํด ๋ค์๊ณผ ๊ฐ์ด ์์ธ๋ฅผ ์ฒ๋ฆฌํ์๋ค.
@ExceptionHandler(ResourceMinRangeException.class)
public ResponseEntity<ExceptionResponse> resourceRangeException(final ResourceMinRangeException e) {
final Integer minRange = e.getRange().getData();
final ExceptionResponse exceptionResponse =
new ExceptionResponse(String.format("%d๋ณด๋ค ํฐ ๊ฐ์ ์
๋ ฅํด ์ฃผ์ธ์.", minRange));
return ResponseEntity.badRequest().body(exceptionResponse);
}
๋ด๊ฐ ๋ง์ฝ ๋๋ฃ ๊ฐ๋ฐ์์ ํ์ ์ ํ๋ ์ํฉ์ด๊ณ , ๋ทฐ์ ๋ด๋ ค์ง ์์ธ ๋ฉ์์ง์ ๋ํด ๋ณ๊ฒฝํ๊ณ ์ถ๋ค๋ฉด ์ด๋ค ํด๋์ค๋ฅผ ํ์ธํ ๊น? ๋ผ๋ ๊ด์ ์ผ๋ก ๊ณ ๋ฏผํด๋ดค๋๋ฐ, ๋๋ผ๋ฉด ์์ธ์ ๋ํด ํธ๋ค๋งํ๋ ControllerAdvice ๋ถ๋ถ์ ๋จผ์ ํ์ธํ ๊ฒ ๊ฐ์์ ์์ ๊ฐ์ด ์งํํ์๋ค.
๋ํ, ์์ธ response๋ฅผ ๋ด๋ ๊ฐ์ฒด๋ฅผ ๋ฐ๋ก ๋ง๋ค์์๋๋ฐ, ๋์ค์ ํ๋ก ํธ ๊ฐ๋ฐ์์ ํ์ ํ์ ๋ json์ ๊ฐ์ผ๋ก ๋ฐ๋ก string์ด ๋ด๋ ค์ค๋ ๊ฒ๋ณด๋ค, ๊ณตํต๋ ํฌ๋งท์ผ๋ก ๋ฐ์ดํฐ๋ฅผ ์ ํด๋๊ณ ๋ด๋ ค์ฃผ๋ ๊ฒ ๋์ ๊ฒ ๊ฐ๋ค๊ณ ํ๋จํ๋ค. ์ง๊ธ์ ๋ฉ์์ง์ผ ๋ฟ์ด์ง๋ง ๋์ค์ ์ํ ์ฝ๋๋ ํจ๊ป ๋ด๋ ค์จ๋ค๋ ์ง... ๊ทธ๋ด ์๋ ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๋ก ๊ฐ์ธ๋ ๊ฒ ๋ ์ข์ ๊ฒ ๊ฐ๋ค๊ณ ํ๋จํ๊ธฐ๋ ํ๋ค.
๐ฌ Dao์ Repository
๋๋ ์ด๋ฒ ๋ฏธ์ ์ ์งํํ๋ฉด์ ๋ค์๊ณผ ๊ฐ์ด ๊ตฌ์ฑํ์๋ค.
์๋ ๊ฒฝ์ฃผ ๊ฒฐ๊ณผ์ ๋ํด ์ ์ฅํ๋ ํ ์ด๋ธ์ด๊ณ , ๊ฒฝ์ฃผ ํ์์ ์ฐ์น์, ๊ทธ๋ฆฌ๊ณ ๊ฒฝ์ฃผ ์์ ์๊ฐ์ ๋ด์๋ค.
์๋๋ ์๋์ฐจ์ ๋ํด ์ ์ฅํ๋ ํ ์ด๋ธ์ด๊ณ , ์๋์ฐจ ์ด๋ฆ๊ณผ ์์น, ๊ทธ๋ฆฌ๊ณ ์ธ๋ํค๋ก ๊ฒฝ์ฃผ ๊ฒฐ๊ณผ์ ๋ํ ์์ด๋๋ฅผ ๊ฐ์ก๋ค.
๋ํ, ๋น์ฆ๋์ค ๋ก์ง ์์์ ํ๋์ ๊ฒฝ์ฃผ์๋ ์ค๋ณต๋ ์๋์ฐจ ์ด๋ฆ์ ๊ฐ์ง ์ ์๊ธฐ ๋๋ฌธ์ UNIQUE๋ฅผ ๊ฑธ์ด์ฃผ์๋ค.
@Repository
@Transactional(readOnly = true)
public class CarRaceRepositoryImpl implements CarRaceRepository {
private final CarDao carDao;
private final RaceResultDao raceResultDao;
...
}
๊ทธ๋์, ๋ณธ ์๊ตฌ์ฌํญ์์ ์ ๋ณด๋ฅผ ์ ์ฅํ ๋ ํ๋์ Repository์์ ์ ์ฅํ๋ ๋ ๊ธฐ๋ฅ์ ์ํํ๊ธฐ ์ํด ์์ ๊ฐ์ด 2๊ฐ์ Dao๋ฅผ ์ฐธ์กฐํ๋ ํ์์ผ๋ก ์งํํ์๋ค. ๋ํ, ์๋น์ค ๋ ์ด์ด์์ ํด๋น ๋ ํ์งํ ๋ฆฌ๋ง ์ฐธ์กฐํ๋๋ก ๋ง๋ค๊ณ ์ถ์๋ค.
ํ์ง๋ง, ๋ค์๊ณผ ๊ฐ์ ๋ฆฌ๋ทฐ๊ฐ ๋ฌ๋ ธ์๋ค.
๋ Dao๋ฅผ ๊ฐ๊ณ ์๋๊ฒ์ด ๋จ์ผ์ฑ ์์์น์ ์๋ฐฐํ๋ค๊ณ ์๊ฐํ์ง๋ ์์ผ์ ๊ฐ์?
๋๋ ์ด์ ๋ํด์ ๋ค์๊ณผ ๊ฐ์ ๋ต๋ณ์ ๋ฌ์์๋ค.
DAO์ ๊ฒฝ์ฐ 1:1 ๋งคํ์ด ๋์ง๋ง, Repository์ ๊ฒฝ์ฐ Dao๋ฅผ ํฉ์ณ ์กฐ๊ธ ๋ ๋น์ฆ๋์ค ๋ก์ง ๊ด์ ์์ ์ฌ์ฉํ๋ ๊ณ์ธต์ด๋ผ๊ณ ์๊ฐํ๋ค.
๋ง์ฝ ์ฌ์ฉ์์ ํธ์ ๋ชฉ๋ก์ ๊ฐ์ง๊ณ ์ค๊ฒ ๋๋ค๋ฉด, ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ด์ Dao์ ํธ์์ ๋ํ Dao๋ฅผ ํฉ์ณ์ ํด๋น Repository์์ ์ด๋ฌํ ๊ธฐ๋ฅ์ ์ํํ๋ค๊ณ ์๊ฐํ๋ค. (๋น์ ์ด ๊ธ์ ๋ณด๊ณ ์ด๋ฌํ ์๊ฐ์ ์ก์์๋ค.)
ํ์ง๋ง, ๋ฆฌ๋ทฐ์ด๋์ ๋์ ๊ฐ์ ์ํฉ์์ ์ฌ์ฉํ๋ ๊ฒ ์๋๋ผ๊ณ ๋ง์ํด ์ฃผ์ จ๋ค.
๋น์ ์ฌ๋ ํ๋ค์ ํตํด ๋ง์ ๋๋ด๋์ง๋ผ ๋ฐ๋ก ๊ธฐ๋ก์ ๋ชปํ๋๋ฐ, ๋ด๊ฐ ์ดํดํ ๊ฒ์ ๋ค์๊ณผ ๊ฐ์๋ค.
์ง๊ธ ๋์ ๊ฒฝ์ฐ, ์๋์ฐจ์ ๊ฒฝ์ฃผ ๊ฒ์์ FK๋ก ์ฐ๊ฒฐ์ ๋์ด ์์ง๋ง ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ๋์ ๋๋ฉ์ธ์ผ๋ก ์ฐ๊ด์ด ๋์ด ์์ง ์๋ค.
์ค์ง 'Car'๋ผ๋ ๋๋ฉ์ธ๊ณผ, 'Race'๋ผ๋ ๋๋ฉ์ธ๋ง ์กด์ฌํ ๋ฟ์ด์ง, ๋ ๊ฐ์ง์ ๋ํด ์งํฉ๋ ๋๋ฉ์ธ์ ์กด์ฌํ์ง ์์๋ค.
ํ์ง๋ง, ์์ ๋ ํผ๋ฐ์ค์์๋ ๋ค์๊ณผ ๊ฐ์ด ๋ ํฌ์งํ ๋ฆฌ๋ฅผ ์ฌ์ฉํ์๋ค.
public class UserRepositoryImpl implements UserRepository {
private UserDaoImpl userDaoImpl;
private TweetDaoImpl tweetDaoImpl;
@Override
public User get(Long id) {
UserSocialMedia user = (UserSocialMedia) userDaoImpl.read(id);
List<Tweet> tweets = tweetDaoImpl.fetchTweets(user.getEmail());
user.setTweets(tweets);
return user;
}
}
์ฌ๊ธฐ์ ์ฃผ๋ชฉํ ๋ถ๋ถ์ userDaoImpl.read์ ๋ฐํ์ฒด๊ฐ UserSocialMedia๋ผ๋ ๊ฒ์ด๋ค.
Our UserSocialMedia class is a complex domain containing the properties of the User domain too.
์ฌ์ฉ์ ๋๋ฉ์ธ์ ์์ฑ๊ณผ ํธ์์ ๋ํ ์ ๋ณด๊น์ง ๋ด๊ณ ์๋, ํ๋๋ก ํฌ๊ดํ ๋๋ฉ์ธ์ด๋ผ๋ ๊ฒ์ด๋ค.
๊ทธ๋์ DB์ ์ ๊ทํ ๊ด์ ์์ ๋ถ๋ฆฌ๋ ๋ ๊ฐ์ ํ ์ด๋ธ์ ๋ํด ํ๋์ ๋๋ฉ์ธ์ผ๋ก ์ง์ฝํ์ฌ ๊ฐ์ ธ์ค๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค๊ณ ์๊ฐํ๋ค.
๐ฑ DAO
- Data persistence์ ์ถ์ํ (Database์ ๋ํ ์ถ์ํ ๊ณ์ธต)
- Database์ ์ธ์ ํ ๊ณ์ธต์ด๋ฉฐ, ํ์ ์์ค์ ๊ฐ๋ ์ด๋ค.
- ๋ฐ์ดํฐ์ ๋ํ ๋งคํ ๋ฐ ์ ๊ทผํ ์ ์๋ ํด๋์ค
๐ฑ Repository
- ๊ฐ์ฒด์ ์งํฉ์ ๋ํ ์ถ์ํ
- ๋๋ฉ์ธ ์ค๋ธ์ ํธ์ ์กฐ๊ธ ๋ ๊ฐ๊น์ด ๊ฐ๋ ์ด๋ค.
- ๋๋ฉ์ธ์ ๋ฐ์ดํฐ ์ ๊ทผ ๊ณ์ธต ์ฌ์ด์ ์กด์ฌํ๋ ๋ ์ด์ด์ด๋ค.
(๋ฌผ๋ก , ๋๋ฉ์ธ์ ๋น์ฆ๋์ค ๋ก์ง์ด ๊ฑฐ์ ์๋ค๋ฉด Repository๊ฐ ๊ณง ๋จ์ํ Dao ํํ๊ฐ ๋ ์ ์๋ค.)
์ฌ์ค ๊ทธ ์ธ๋ ๊ฝค๋ ๋๊ผ๋ ์ ์ด ๋ง์๋ฐ, ์ด๊ฑฐ๋ ํ๊ณ ๋ก ์ฐ๋ ๊ฒ๋ณด๋ค ๋ณ๋์ ๊ธ๋ก ์ฐ๋ ๊ฒ ์ข์ ๊ฒ ๊ฐ์์ ๋จ๊ฒจ๋๋ค.
๋ฏธ์ ์ข ๋ฃ ๊ธฐ๊ฐ๊น์ง ์ต๋ํ ๋ธ๋ก๊ทธ ๊ธ์ ์ฐ๋๋ฐ์ ์ง์คํด์ผ๊ฒ ๋ค!
'์ฐ์ํํ ํฌ์ฝ์ค > ๋ ๋ฒจ 2' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[์ฐํ ์ฝ 5๊ธฐ] ๋ ๋ฒจ 2 ๋ ๋ฒจ ์ธํฐ๋ทฐ ์ ๋ฆฌ ๋ฐ ๊ฐ์ ํ๊ณ (5) | 2023.06.16 |
---|---|
[์ฐํ ์ฝ 5๊ธฐ] ์ฅ๋ฐ๊ตฌ๋ ํ์ ๋ฏธ์ ํ๊ณ (2) | 2023.06.16 |
[์ฐํ ์ฝ 5๊ธฐ] ์งํ์ฒ ๋ฏธ์ ํ๊ณ (4) | 2023.05.22 |
[์ฐํ ์ฝ 5๊ธฐ] ์ฅ๋ฐ๊ตฌ๋ ๋ฏธ์ ํ๊ณ (0) | 2023.05.15 |