From b7f48dd9ab611a6523b2a4204f6c86e631c04785 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 26 Sep 2023 19:53:49 +0900 Subject: [PATCH 1/9] =?UTF-8?q?[1=EC=A3=BC=EC=B0=A8]=20=EA=B9=80=EC=A7=80?= =?UTF-8?q?=EB=82=98=20=ED=95=99=EC=8A=B5=20PR=20=EC=A0=9C=EC=B6=9C?= =?UTF-8?q?=ED=95=A9=EB=8B=88=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "week01/1\354\243\274\354\260\250.md" | 30 --- .../\352\271\200\354\247\200\353\202\230.md" | 172 ++++++++++++++++++ 2 files changed, 172 insertions(+), 30 deletions(-) delete mode 100644 "week01/1\354\243\274\354\260\250.md" create mode 100644 "week01/\352\271\200\354\247\200\353\202\230.md" diff --git "a/week01/1\354\243\274\354\260\250.md" "b/week01/1\354\243\274\354\260\250.md" deleted file mode 100644 index 95ebbae..0000000 --- "a/week01/1\354\243\274\354\260\250.md" +++ /dev/null @@ -1,30 +0,0 @@ -## COW SPRING 2기 PRE-ONBOARDING 학습 과제 - -### 자바의 필수 개념들을 차근차근 살펴보자. - -* 자바의 primitive Type과 Reference Type은 어떤 차이가 있나요? - - -* 자바의 접근 제어자에 대해 설명해주세요. - - -* static 키워드에 대해 설명해주세요. - - -* final 키워드에 대해 설명해주세요. - * ++ 상속 관련된 내용도 포함할 것! - -* 오버로딩(Overloading)과 오버라이딩(Overriding)에 대해 설명해주세요. - - -* 추상 클래스와 인터페이스는 각각 무엇이고, 어떤 차이를 가지는지 설명해주세요 - * 반드시 추상 클래스와 인터페이스의 사용 목적을 명시해주세요. - - -* Java Enum에 대해 설명해주세요. - - -* 객체지향이란 무엇일까요? 객체지향을 지키면 어떤 이점을 얻을 수 있나요? - - -* 자바 객체지향의 4대 특성에 대해 각각 설명해주세요. \ No newline at end of file diff --git "a/week01/\352\271\200\354\247\200\353\202\230.md" "b/week01/\352\271\200\354\247\200\353\202\230.md" new file mode 100644 index 0000000..2d54b20 --- /dev/null +++ "b/week01/\352\271\200\354\247\200\353\202\230.md" @@ -0,0 +1,172 @@ +## COW SPRING 2기 PRE-ONBOARDING 학습 과제 + +### 자바의 필수 개념들을 차근차근 살펴보자. + +* 자바의 primitive Type과 Reference Type은 어떤 차이가 있나요? + + - 타입(Data Type)이란? + - 해당 데이터가 메모리에 어떻게 저장되고, 프로그램에서 어떻게 처리되어야 하는지를 명시적으로 알려주는 것이다. + - 자바에서 타입을 크게 `기본형 타입`과 `참조형 타입`이 있다. + + - **기본형 타입(Primitive type)** + - 총 8가지의 기본형 타입을 미리 정의하여 제공한다. + - 기본값이 있기 때문에 Null이 존재하지 않는다. 만약 기본형 타입에 Null을 넣고 싶다면 래퍼 클래스를 활용한다 + - **실제 값**을 저장하는 공간으로 **스택(Stack)** 메모리에 저장된다. + - 컴파일 시점에 담을 수 있는 크기를 벗어나면 에러를 발생시키는 `컴파일 에러`가 발생한다. + - 타입 종류: boolean, int, double, char 등 + + - **참조형 타입(Reference type)** + - 기본형 타입을 제외한 모든 타입 + - 빈 객체를 의미하는 Null이 존재 + - 값이 저장되어 있는 곳의 **주소값**을 저장하는 공간으로 **힙(Heap)** 메모리에 저장된다. + - 문법상으로는 에러가 없지만 실행시켰을 때 에러가 나는 `런타임 에러` 발생.
+ _(예를 들어 객체나 배열을 Null 값으로 받으면 NullPointException이 발생 -> 변수값을 넣어야 한다.)_ + - 타입 종류: 배열(Array), 열거(Enumeration), 클래스(Class), 인터페이스(Interface) + +
+ +* 자바의 접근 제어자에 대해 설명해주세요. + - 제어자(modifier)란 + - 클래스와 클레스 멤버의 선언 시 사용하여 부가적인 의미를 부여하는 키워드를 말한다. + - 접근 제어자(access modifier)와 기타 제어자로 구분할 수 있다. + - 접근 제어자(access modifier) + - 접근 제어자를 사용하여 클래스 외부에서의 직접적인 접근을 허용하지 않는 멤버를 설정하여 정보 은닉을 구체화할 수 있다. + 1. private + - private 접근 제어자를 사용하여 선언된 클래스 멤버는 외부에 공개되지 않으며, 외부에서는 직접 접근할 수 없다. + - private 멤버는 해당 멤버를 선언한 클래스에서만 접근 가능 + + 2. public 접근 제어자 + - public 접근 제어자를 사용하여 선언된 클래스 멤버는 외부로 공개되며, 해당 객체를 사용하는 프로그램 어디에서나 직접 접근할 수 있다. + - 자바 프로그램은 public 메소드를 통해서만 해당 객체의 private 멤버에 접근할 수 있다. + - 즉, public 메소드는 private 멤버와 프로그램 사이의 인터페이스(interface) 역할을 수행한다고 할 수 있다. + + 3. default 접근 제어 + - 자바에서는 클래스 및 클래스 멤버의 접근 제어 기본값으로 default 접근 제어를 별도로 명시하고 있다. + - 이러한 default를 위한 접근 제어자는 따로 존재하지 않으며, 접근 제어자가 지정되지 않으면 자동적으로 default 접근 제어를 가지게 된다. + - default 접근 제어를 가지는 멤버는 같은 클래스의 멤버와 같은 패키지에 속하는 멤버에서만 접근할 수 있다. + + 4. protected 접근 제어자 + - protected 멤버는 부모 클래스에 대해서는 public 멤버처럼 취급되며, 외부에서는 private 멤버처럼 취급된다. + - 즉, 같은 패키지에 속하는 클래스와 다른 패키지에 속하는 자식 클래스에서만 접근할 수 있다. + - 클래스의 protected 멤버에 접근할 수 있는 영역 + 1. 이 멤버를 선언한 클래스의 멤버 + 2. 이 멤버를 선언한 클래스가 속한 패키지의 멤버 + 3. 이 멤버를 선언한 클래스를 상속받은 자식 클래스의 멤버 + +
+ +* static 키워드에 대해 설명해주세요. + - Java에서 Static 키워드를 사용한다는 것은 메모리에 한번 할당되어 프로그램이 종료될 때 해제되는 것을 의미한다 + + - 일반적으로 만든 Class -> Static 영역에 생성 / new 연산으로 생성한 객체 -> Heap 영역에 생성 + - 객체의 생성시에 할당된 Heap 영역의 메모리는 Garbage Collector를 통해 수시로 관리를 받는다. + - Static 영역에 할당된 메모리는 모든 객체가 공유하는 메모리라는 장점을 갖는다. + - 하지만 Garbage Collector의 관리 영역 밖에 존재하므로 Static을 자주 사용하면 프로그램의 종료시까지 메모리가 할당된 채로 존재 + -> 자주 사용하게 되면 시스템의 퍼포먼스에 악영향을 주게 된다. +
+ +* final 키워드에 대해 설명해주세요. + * ++ 상속 관련된 내용도 포함할 것! + - final은 오직 한 번만 할당할 수 있는 entity를 정의할 때 사용된다. + - final 변수가 객체를 참조하고 있다면, 그 객체의 상태가 바뀌어도 final 변수는 매번 동일한 내용을 참조한다. + + - final 클래스 + - final이 붙어있는 클래스는 상속할 수 없다. -> 보안이나 효율성 측면에서 장점을 갖게된다. + - java.lang.System이나 java.lang.String 처럼 자바에서 기본적으로 제공하는 라이브러리 클래스는 final을 사용한다. + + - final 메서드 + - 어떤 클래스를 상속하는데 그 안에 final 메서드가 있다면, 오버라이딩으로 수정할 수 없다. + + - final 변수 + - final 변수는 한 번 값을 할당하면 수정할 수 없다. + - 즉, 초기화는 한 번만 가능하다 + +
+* 오버로딩(Overloading)과 오버라이딩(Overriding)에 대해 설명해주세요. + + - 오버로딩(Overloading) + - 자바의 한 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메소드가 있더라도 + 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메소드를 정의할 수 있다. + - 조건: 메소드의 이름이 같고, 매개변수의 개수나 타입이 달라야 한다. + - 주의할 점: 주의할 점은 '리턴 값만' 다른 것은 오버로딩을 할 수 없다. + - 사용하는 이유 + 1. 같은 기능을 하는 메소드를 하나의 이름으로 사용할 수 있다. + 2. 메소드의 이름을 절약할 수 있다 + + + - 오버라이딩(Overriding) + - 부모 클래스로부터 상속받은 메소드를 자식 클래스에서 재정의하는 것을 의미한다. + - 상속받은 메소드를 그대로 사용할 수도 있지만, 자식 클래스에서 상황에 맞게 변경해야하는 경우 오버라이딩할 필요가 생긴다. + - 조건: 오버라이딩은 부모 클래스의 메소드를 재정의하는 것이므로, 자식 클래스에서는 **오버라이딩하고자 하는 메소드의 이름, 매개변수, 리턴 값이 모두 같아야 한다**. + - 접근 제어자를 설정하는 규칙 + 1. 자식 클래스에서 오버라이딩하는 메소드의 접근 제어자는 부모 클래스보다 더 좁게 설정할 수 없다. + 2. 예외(Exception)는 부모 클래스의 메소드 보다 많이 선언할 수 없다. + 3. static메소드를 인스턴스의 메소드로 또는 그 반대로 바꿀 수 없다. + + -참고 링크: https://hyoje420.tistory.com/14 +
+ +* 추상 클래스와 인터페이스는 각각 무엇이고, 어떤 차이를 가지는지 설명해주세요 + * 반드시 추상 클래스와 인터페이스의 사용 목적을 명시해주세요. + + - 추상 클래스 + - 일반 클래스와 크게 다르지 않다 + - 단지, 추상 메서드를 선언하여 상속을 통해 자손 클래스에서 완성하도록 유도하는 클래스이다. + - 사용 목적: 상속을 위한 클래스 + -> 따로 객체를 생성할 수 없음 + - 클래스 앞에 'abstract'라는 예약어를 사용 + + - 인터페이스 + - 추상 클래스가 미완성 설계도라면 인터페이스는 기본 설계도라고 할 수 있다. + - 추상클래스처럼 다른 클래스를 작성하는 데에 도움을 주는 목적으로 작성하고, 클래스와 다르게 다중상속(구현)이 가능하다 + +
+ +* Java Enum에 대해 설명해주세요. + - 자바에서는 `enum` 키워드를 사용하여 열거를 정의할 수 있다. + - 사용예시 + `enum Day { + MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, STURDAY, SUNDAY; + }` + - 장점 + - 코드가 단순해지며 가독성이 좋아진다. + - 키워드 enum 을 사용함으로써 구현의 의도가 열거임을 분명하게 나타낼 수 있다. + - 자체 클래스 상수와 달리 switch 문에서도 사용할 수 있다. + - 단순 상수와 비교되는 자동완성, 오타검증, 텍스트 리팩토링 등의 IDE 지원을 받을 수 있다. + +
+ +* 객체지향이란 무엇일까요? 객체지향을 지키면 어떤 이점을 얻을 수 있나요? + + - 객체지향이란, 프로그래밍에서 필요한 데이터를 추상화 시켜 **상태와 행위를 가진 객체**로 만들고, + 객체들간의 상호작용을 통해 로직을 구성하는 프로그래밍 방법이다. + + - 객체지향의 이점 + - 코드의 재사용성이 높다 + - 상속을 통해 불필요한 코드의 중복을 제거하고, 쉽고 빠르게 설계할 수 있다. + + - 유지보수가 용이하다. + - 기존 기능을 수정할 때, 캡슐화에 의해 주변에 미치는 영향을 최소화할 수 있다. + - 새 기능을 추가할 때, 상속을 통해 기존의 기능을 활용할 수 있다. + + - 디버깅이 쉽다. +
+ +* 자바 객체지향의 4대 특성에 대해 각각 설명해주세요. + 1. 추상화 + - 객체에서 공통된 속성과 행위를 추출하는 것 + - 공통의 속성과 행위를 찾아서 타입을 정의하는 과정 + - 추상화는 불필요한 정보는 숨기고 중요한 정보만을 표현함으로써 프로그램을 간단하게 만드는 것 + + 2. 캡슐화 + - 데이터 구조와 데이터를 다루는 방법들을 결합 시켜 묶는 것 (변수와 함수를 하나로 묶는 것을 뜻함) + - 낮은 결합도를 유지할 수 있도록 설계하는 것 + + 3. 상속 + - 클래스의 속성과 행위를 하위 클래스에 물려주거나 하위 클래스가 상위 클래스의 속성과 행위를 물려받는 것을 말한다 + - 새로운 클래스가 기존의 클래스의 데이터와 연산을 이용할 수 있게 하는 기능 + + 4. 다형성 + - 하나의 변수명, 함수명이 상황에 따라 다른 의미로 해석 될 수 있는 것 + - 어떠한 요소에 여러 개념을 넣어 놓는 것 + - 객체 지향 프로그래밍은 하나의 클래스 내부에 같은 이름의 행위를 여러개 정의하거나 상위 클래스의 행위를 하위 클래스에서 재정의하여 사용할 수 있기 때문에 다형성이라는 특징을 갖게 된다. \ No newline at end of file From 8c838094d095111ed59052ed498ccd9297e1f0c7 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 3 Oct 2023 23:27:01 +0900 Subject: [PATCH 2/9] =?UTF-8?q?2=EC=A3=BC=EC=B0=A8=20=ED=95=99=EC=8A=B5=20?= =?UTF-8?q?PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\352\271\200\354\247\200\353\202\230.md" | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 "week02/\352\271\200\354\247\200\353\202\230.md" diff --git "a/week02/\352\271\200\354\247\200\353\202\230.md" "b/week02/\352\271\200\354\247\200\353\202\230.md" new file mode 100644 index 0000000..5e0343c --- /dev/null +++ "b/week02/\352\271\200\354\247\200\353\202\230.md" @@ -0,0 +1,40 @@ +### 2주차 학습 PR + +- 요구사항 정의 + 1. 추첨 결과 출력 + - 수익률 출력 (수익률 = 당첨 금액 / 구입 금액) + 2. 추첨 + - 숫자랑 위치 일치하는지 확인 + - 보너스볼 확인 + 3. 보너스 번호 입력 + - 숫자는 1 ~ 45 + - (error) 당첨 번호와 중복 불가 + 4. 당첨 번호 입력 + - 6개 숫자 입력 (ex: 1, 2, 3) + - 숫자는 1 ~ 45 + - 입력 구분자는 , + - (error) 중복된 숫자 불가 + 5. 로또 목록 + - 로또 생성 + - 숫자는 1 ~ 45 + - (error) 중복된 숫자 불가 + - Collections.shuffle() 활용 + - 목록 출력 + - 로또 숫자 정렬 + 6. 구매한 로또 개수 출력 + 7. 로또 구입 금액 + - 로또 가격은 1000원 + - (error) 1000원 단위 외의 금액 불가 + - (error) 문자열 입력 + - 구매 로또 개수 구하기 (입력받은 금액 / 1000) + +- 구현에 대한 고민 + - 하나의 클래스가 하나의 책임을 가지도록 하고 싶은데 어디까지 쪼개고 나눠야 할 지 감이 잘 안 잡힌다. + - 예를 들면, 로또 금액 입력받는 클래스, 발행된 로또들을 관리하는 클래스 같이 하나하나 쪼개면 너무 클래스들이 많아질 것 같아 고민이 된다.. + +- LottoManager와 LottoGenerator의 책임 분리가 조금 어려웠다. 로또 숫자 생성과 저장 및 관리를 같이하게 되면 단일책임의 원칙에 어긋날 것 같아 클래스를 분리해봤는데, 또 한편으로는 비슷한 기능이라 하나의 클래스 내에서 메소드로 구현해도 괜찮지 않을까 하는 생각도 들었다. +- `WARNING: An illegal reflective access operation has occurred` 이란 경고문구 발생 + - `--illegal-access=deny` 이라는 jvm 옵션을 추가해 일단은 경고문구가 뜨지 않게 했으나, `unable to determine if the scanner is closed.`이라는 경고문구가 다시 추가되었다.. + - 라이브러리의 업데이트를 받아와야 하는지,, 일단은 프로그램 정상 동작이 최우선 목표였기에 넘어갔다. +- LottoGenerator 클래스의 generateLotto메서드에서 구매한 로또 장 수 만큼 로또를 발행하게끔 구현했는데, 후에 이를 Lottomanager클래스에서 발행된 로또를 관리하게끔 메서드를 끌어와 사용하다보니 에러가 발생했다.. 너무 클래스간 관계가 복잡해진것 같다.. +- 또한 LottoResult 부분은 로또 당첨번호와 구입한 번호들을 비교하여 통계를 내는 마지막 단계인데, 워낙 클래스도 많고 비슷한 변수도 많다보니 결국 꼬여버린 것 같다. 어떻게든 동작되게끔 하려 했지만 그보다는 다시 클래스간 관계를 정의하고 정리된 상태에서 다시 코드를 짜보는게 맞는 것 같다는 생각을 했다. \ No newline at end of file From f22200c06fdc0f3148e7191e60b842d489fe542d Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 10 Oct 2023 21:47:49 +0900 Subject: [PATCH 3/9] =?UTF-8?q?docs=20:=203=EC=A3=BC=EC=B0=A8=20README=20?= =?UTF-8?q?=EC=97=85=EB=A1=9C=EB=93=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "week03/3\354\243\274\354\260\250.md" | 334 +++++++++++++++++++++++--- 1 file changed, 306 insertions(+), 28 deletions(-) diff --git "a/week03/3\354\243\274\354\260\250.md" "b/week03/3\354\243\274\354\260\250.md" index f19c798..1bf35b9 100644 --- "a/week03/3\354\243\274\354\260\250.md" +++ "b/week03/3\354\243\274\354\260\250.md" @@ -1,45 +1,323 @@ -# 3주차 학습 PR -학습 PR 역시 로또 리팩토링에 도움이 되는 내용들로 구성되어 있습니다. -해당 개념들을 학습한 뒤, 본인의 로또 코드에 적용까지 해 보신다면..? 비로소 본인 것이 됩니다 ㅎㅎ +# [카우 3주차] -아래 `*` 은 여러분들의 학습을 위한 **최소한의** 가이드라인입니다. -꼭 깊이있는 학습 후에 꼼꼼하게 기록해주세요💯 +--- -## 일급 컬렉션이란? +**3주차 학습 PR** -* 일급 컬렉션이란? +학습 PR 역시 로또 리팩토링에 도움이 되는 내용들로 구성되어 있습니다. 해당 개념들을 학습한 뒤, 본인의 로또 코드에 적용까지 해 보신다면..? 비로소 본인 것이 됩니다 ㅎㅎ -* 일급 컬렉션은 왜 사용하는가? 어떤 장점이 있는지? +아래 `*` 은 여러분들의 학습을 위한 **최소한의** 가이드라인입니다. 꼭 깊이있는 학습 후에 꼼꼼하게 기록해주세요💯 -+ 불변 객체..방어적 복사도 함께 찾아보시면 좋을 것 같아요! -+ https://tecoble.techcourse.co.kr/post/2021-04-26-defensive-copy-vs-unmodifiable/ +## **일급 컬렉션이란?** -## MVC 패턴이란? - +- 일급 컬렉션이란? + - Java에서 일급 컬렉션(First-Class Collection)은 다른 객체와 동등한 지위를 갖는 컬렉션 객체 + - 특징 + - 컬렉션 객체는 변수나 매개변수에 할당할 수 있다. + - 컬렉션 객체는 다른 객체와 동등한 지위를 가진다. + - 컬렉션 객체는 반환값으로 사용할 수 있다. + - 컬렉션 객체는 필요한 경우 메서드에서 생성할 수 있다. -* MVC는 왜 사용하는지? + -## Java의 Stream이란? + - 일급 컬렉션을 사용하지 않은 코드 -* Stream의 특징? 장점? - * 병렬 처리 - * 작업 분류 - * lazy Evaluation - * 내부 반복 방식 - * for문과의 차이점? + ```jsx + public class Student { + private List subjects; + + public Student(List subjects) { + this.subjects = subjects; + } + + public List getSubjects() { + return subjects; + } + } + ``` -* 중간 연산 메서드 + 위 코드 중 Student 클래스에서 List 타입의 subjects를 직접 다루고 있다. 이 경우 Student 클래스는 List 타입에 의존성을 갖게 되며, List의 구현이 변경될 경우 Student 클래스도 함께 변경되어야 하는 문제점을 가지고 있다. -* 최종 연산 메서드 -## 제네릭이란? + - 일급 컬렉션을 사용한 코드 + ```jsx + public class Student { + private Subjects subjects; + + public Student(Subjects subjects) { + this.subjects = subjects; + } + + public Subjects getSubjects() { + return subjects; + } + } + + public class Subjects { + private List subjects; + + public Subjects(List subjects) { + this.subjects = subjects; + } + + public void addSubject(String subject) { + subjects.add(subject); + } + + public List getSubjects() { + return new ArrayList<>(subjects); + } + } + ``` -## Optional이란? + 위 코드에서는 Student 클래스에서 Subjects 클래스를 사용하도록 변경되었다. Subjects 클래스는 List타입의 Subjects를 감싸고 있으며, Subject 객체를 추가하거나, 모든 Subject 객체를 가져올 수 있도록 메서드를 제공한다. + - + 이렇게 함으로써, Student 클래스는 Subjects 클래스랑만 의존성을 갖게 되고 이전에 지녔던 문제점인 List타입에 대한 의존성을 제거할 수 있다. +- 일급 컬렉션은 왜 사용하는가? 어떤 장점이 있는지? -## References - -* \ No newline at end of file + 1. 가독성과 유지보수성이 향상된다. + + 일급컬렉션을 사용하면 해당 컬렉션을 사용하는 클래스에서 해당 컬렉션의 역할과 의미를 바로 파악할 수 있고, 유지보수성이 향상된다. + + 1. 유효성 검증이 용이해진다. + + 일급 컬렉션을 사용하면 해당 컬렉션의 내부 구현을 캡슐화할 수 있기 때문에 유효성 검증 코드를 해당 컬렉션 클래스 내부에 구현하여 컬렉션의 사용자들이 해당 유효성 검증 로직을 호출하는 번거로움을 줄일 수 있다. + + 2. 불변성을 보장할 수 있다. + + 일급 컬렉션을 사용하면 해당 컬렉션을 불변(immutable)으로 만들어서 변경을 방지할 수 있다. + +- 불변 객체..방어적 복사도 함께 찾아보시면 좋을 것 같아요! +- [https://tecoble.techcourse.co.kr/post/2021-04-26-defensive-copy-vs-unmodifiable/](https://tecoble.techcourse.co.kr/post/2021-04-26-defensive-copy-vs-unmodifiable/) + +## **MVC 패턴이란?** + +- MVC는 왜 사용하는지? + - Intro + - 스프링 프레임워크의 모듈 중에는 웹 계층을 담당하는 몇 가지 모듈이 있다. 웹 계층에 서블릿(Servlet) API를 기반으로 클라이언트의 요청을 처리하는 모듈이 있는데 이를 **스프링 웹 MVC** 라고 한다. + - 서블릿(Servlet)이란? + - 클라이언트의 요청을 처리하도록 특정 규약에 맞춰 Java 코드로 작성하는 클래스 파일이다. + - **아파치 톰캣(Apache Tomcat)**은 이러한 서블릿들이 웹 애플리케이션으로 실행할 수 있도록 해주는 서블릿 컨테이너(Servlet Container) 중 하나이다. + - Spring MVC 내부에서는 서블릿을 기반으로 웹 애플리케이션을 동작하며, 스프링 부트는 기본적으로 아파치 톰캣이 내장되어 있다. + - MVC란? + + MVC 패턴은 애플리케이션을 개발할 때 사용하는 디자인 패턴이다. + + 애플리케이션의 개발 영역을 MVC(Model, View, Controller)로 구분하여 각 역할에 맞게 코드를 작성하는 개발 방식이다. + + MVC 패턴을 도입하면서 UI 영역과 도메인(비즈니스 로직) 영역으로 구분되어 서로에게 영향을 주지 않으면서 개발과 유지보수가 가능해지게 되었다. + + ![[출처: 인프런 김영한 강의]](%5B%E1%84%8F%E1%85%A1%E1%84%8B%E1%85%AE%203%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1%5D%2013426a9837e040c1bb5d8e3db912cf43/Untitled.png) + + [출처: 인프런 김영한 강의] + + - Model(모델) + + > 데이터(data) 가공을 책임지는 컴포넌트(component) + > + + 모델은 어플리케이션의 정보, 데이터를 나타냅니다. 데이타베이스, 초기화 된 상수나 값, 변수 등을 뜻합니다. 비즈니스 로직을 처리한 후 모델의 변경 사항을 컨트롤러와 뷰에 전달합니다. + + 모델은 다음과 같은 규칙을 가지고 있습니다. + + - 사용자가 편집하길 원하는 모든 데이터를 가지고 있어야 합니다. + - 뷰나 컨트롤러에 대해서 어떤 정보도 알지 말아야 합니다. + - 변경이 일어나면, 변경 통지에 대한 처리 방법을 구현해야만 합니다. + + - View(뷰) + + > *사용자에게 보여지는 부분, 즉 유저 인터페이스(User interface)* + > + + MVC 패턴은 여러 개의 뷰가 존재할 수 있으며, Model에게 데이터를 전달받는다. + + View는 받은 데이터를 화면에 표시해주는 역할을 가지고 있다. 모델에게 전달받은 데이터를 별도로 저장하지 않아야 한다. 사용자가 화면에 표시된 내용을 변경하게 되면 모델에게 전달하여 모델을 변경해야 합니다. + + 뷰는 다음과 같은 규칙을 가지고 있습니다. + + - 모델이 가지고 있는 정보를 따로 저장해서는 안됩니다. + - 모델이나 컨트롤러와 같이 다른 구성 요소들을 몰라야 됩니다. + - 변경이 일어나면 변경통지에 대한 처리방법을 구현해야만 합니다. + + View는 Model을 이용하여 웹 브라우저와 같은 애플리케이션의 화면에 보이는 리소스(Resource)를 제공하는 역할을 한다. + + 스프링 MVC에서 “View”는 사용자에게 표시되는 UI부분이다. 이는 데이터를 사용자에게 시각적으로 제공하도록 설계된 컴포넌트로, 일반적으로 HTML 형식으로 브라우저에 표시된다. + + 그러나 “View”는 HTML만 한정되는 것은 아니며, JSON, XML 등 다른 형식으로도 데이터를 제공할 수 있다. + + - Controller(컨트롤러) + + > 모델과 뷰 사이를 이어주는 브릿지(bridge) 역할 + > + + 모델이나 뷰는 서로의 존재를 모르고 있다. 변경 사항을 외부로 알리고 수신하는 방법만 있는데, 컨트롤러는 이를 중재하기 위한 컴포넌트다. + + 모델과 뷰에 대해 알고 있으며, 모델이나 뷰로부터 변경 내용을 통지 받으면 이를 각 구성 요소에게 통지한다. 사용자가 어플리케이션을 조작하여 발생하는 변경 이벤트들을 처리하는 역할을 수행한다. + + 컨트롤러는 다음과 같은 규칙을 가지고 있다. + + - 모델이나 뷰에 대해서 알고 있어야 한다. + - 모델이나 뷰의 변경을 모니터링 해야 한다. + +- MVC 패턴은 왜 등장했는가? 등장 배경? + - 초기 + + MVC 패턴을 적용하지 않고 서블릿만을 사용하여 상품 등록 뷰를 클라이언트에게 전달하기 위해서는 Response Body에 직접 HTML를 작성하여 응답해야 한다. + + HTML을 직접 개발자가 작성하면 생산성이 매우 떨어진다. 이로인해 HTML과 유사한 JSP가 나타난다. + + - JSP의 등장 + + 동적인 결과를 나타내기위해 HTML의 필요한 곳에 자바 코드를 작성하려는 시도가 있었고 그 결과 **JSP**가 탄생하였다. JSP를 사용하면 손쉽게 HTML을 작성할 수 있고 필요에 따라 자바 코드를 작성하여 클라이언트의 동적인 요청을 처리할 수 있다. + + JSP에 자바 코드를 작성하면 HTML 형식의 데이터를 손쉽게 작성할 수 있고, 서블릿은 단순히 요청이 들어오면 해당 서블릿에 렌더링만 해주면된다. 서블릿만 사용했을 때보다는 많이 발전했지만 문제는 여전히 존재한다. + + JSP에 너무 많은 책임이 부여된다. JSP에는 비즈니스 로직과 뷰에 대한 책임이 혼재한다. 비즈니스 로직을 수정 했을 때, 뷰에 대한 수정이 필요할 때 모두 JSP 코드를 수정해야한다. 그리고 결정적으로 + + **비즈니스 로직과 뷰는 변경의 라이프 사이클이 다르다.** + + 즉 비즈니스 로직의 변경 시기와 뷰의 변경 시기가 서로 다르다는 것이다. 보통 변경의 라이프 사이클이 다를 경우 역할을 분리해주는 것이 좋다. + + - MVC 패턴의 등장 + + MVC 패턴은 이전에 JSP나 서블릿으로만 처리했던 과정을 모델-뷰-컨트롤러로 역할을 나누는 것을 의미한다. + + +## **Java의 Stream이란?** + +- Stream의 특징? 장점? + - 기존 루프문 처리의 문제점 + + 기존 Java에서 컬렉션 데이터를 처리할때는 for, foreach 루프문을 사용하면서 컬렉션 내의 요소들을 하나씩 다루었다. 간단한 처리나 컬렉션의 크기가 작으면 큰 문제가 아니지만 복잡한 처리가 필요하거나 컬렉션의 크기가 커지면 루프문의 사용은 성능저하를 일으키게 되었다. + + - 스트림의 등장 + + 스트림은 Java8에서 추가된 기능으로 컬렉션 데이터를 선언형으로 쉽게 처리할수 있다. 복잡한 루프문을 사용하지 않아도 되며 루프문을 중첩해서 사용해야 되는 최악의 경우도 더 이상 없어졌다. + + - 병렬 처리 + + **외부 반복자(`external iterator`)**란 **개발자가 코드로 직접 컬렉션의 요소를 반복해서 가져오는 코드 패턴**이다. index를 이용하는 for문, 그리고 Iterator를 이용하는 while문은 모두 외부 반복자를 이용하는 것이다. + + 반대로 **내부 반복자(iternal iterator)**란 **컬렉션 내부에서 요소들을 반복시키고, 개발자는 요소 당 처리해야 할 코드만 제공하는 코드 패턴**을 말한다. + + ![Untitled](%5B%E1%84%8F%E1%85%A1%E1%84%8B%E1%85%AE%203%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1%5D%2013426a9837e040c1bb5d8e3db912cf43/Untitled%201.png) + + - 내부 반복자를 사용했을 때의 이점 + + 내부 반복자를 사용하면 컬렉션 내부에서 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맡겨두고, **개발자는 요소 처리 코드에만 집중할 수 있게 된다.** 내부 반복자는 요소들의 반복 순서를 변경하거나, 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있게 도와주기 때문에 **하나씩 처리하는 순차적 외부 반복자보다는 효율적으로 요소를 반복시킬 수 있다.** + + + **Iterator**는 **컬렉션의 요소를 가져오는 것에서부터 처리하는 것까지 모두 개발자가 작성**해야 하지만,**스트림**은 람다식으로 요소 처리 내용만 전달할 뿐, **반복은 컬렉션 내부에서 일어난다.** + + 스트림을 이용하면 **코드도 간결**해지지만, 무엇보다도 **요소의 병렬 처리가 컬렉션 내부에서 처리**된다는 효과까지 있다. + + + + - 작업 분류 + - 중간 연산 + - 연산결과가 스트림을 반환하기 때문에 스트림에 연속해서 중간 연산을 할  수 있다. (0 ~ n번) + - 최종 연산 + - 연산 결과가 스트림이 아닌 연산으로, 스트림의 요소를 소모하기 때문에 마지막에 단 한번만 사용이 가능하다. (0~1번) + + ```jsx + stream.distinct().limit(5).sorted().forEach(System.out::println); + // distinct(), limit(), sorted() -> 중간 연산 + // 마지막 스트림을 소모하여 각 스트림의 요소를 출력하는 forEach -> 최종 연산 + ``` + + - lazy Evaluation (지연된 연산) + - 스트림에서 연산을 할때 한 가지 중요한 점은, 최종 연산이 수행되기 전까지는 중간 연산이 수행 되지 않는다는 점이다. + - 위 코드에서 distinct()나 sorted()같은 중간 연산을 호출한다고 해도 즉각적인 연산이 시행되는 것이 아니다. 중간 연산을 호출하는 것은 단지 어떤 작업이 수행되어야 하는지를 지정해주는 것일 뿐이다. + - **최종 연산이 수행 될때야 비로소 스트림의 요소들이 중간 연산이 수행된다.** + + - 내부 반복 방식 + - 외부 반복 + - 사용자가 직접 요소를 반복 + - 내부 반복 + - 스트림은 반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장 + - 장점: 작업을 투명하게 병렬적으로 처리하거나 최적화된 다양한 순서로 처리가 가능하다. + - for문과의 차이점? +- 중간 연산 메서드 + - ****filter() / distinct()**** + - filter() + - Stream에서 조건에 맞는 데이터만을 정제하여 더 작은 컬렉션을 만드는 데 사용한다. 매개 값으로 조건이 주어지며, 참이 되는 요소만을 필터링한다. + - distinct() + - Stream 요소들의 중복된 데이터를 제거하기 위해 사용한다. + - ****map() / flatMap()**** + - map() + - 기존의 Stream 요소들을 대체하는 요소로 구성된 새로운 Stream을 형성하는 연산이다. 저장된 값을 특정한 형태로 변환하는 데 주로 사용된다. + - flatMap() + - 여러 개의 요소들로 구성된 새로운 스트림을 반환한다. + - sorted() + - Stream의 요소들을 정렬하기 위해 사용한다. sorted() 메서드는 파라미터로 Comparator를 넘길 수 있다. + + 만약, 파라미터의 인자 없이 호출할 경우에는 오름차순 정렬을 한다. + + 내림차순 정렬을 하기 위해서는 Comparator의 `reverseOrder(`) 메서드를 이용한다. + + - ****limit()**** + - 스트림에서 입력 값의 숫자만큼 요소들을 가져와 새로운 스트림을 생성한다. + - ****peek()**** + - 요소를 하나씩 돌면서 출력하는 기능이다. + - 중간 연산이므로 하나의 스트림에 여러 번 사용이 가능하다. +- 최종 연산 메서드 + - ****forEach()**** + - 요소를 하나씩 돌면서 출력하는 기능이다. + - 스트림의 요소를 소모하기 때문에 한 번만 호출할 수 있다. + - match() + 1. allMatch() : 모든 요소들이 매개 값으로 주어진 Predicate의 조건 검사 + 2. anyMatch() : 최소한 한 개의 요소가 매개 값으로 주어진 Predicate의 조건 검사 + 3. noneMatch() : 모든 요소들이 매개 값으로 주어진 Predicate의 만족하지 않는 조건 검사 + - ****sum(), count(), average(), max(), min()**** + - 집계에 대한 메서드 + +## **제네릭이란?** + +**클래스 내부에서 사용할 데이터 타입을 외부에서 지정하는 기법**을 의미한다. + +객체별로 다른 타입의 자료가 저장될 수 있도록 한다. + +```jsx +ArrayList list = new ArrayList<>(); +// 꺽쇠 괄호가 제네릭! + +``` + +괄호 안에는 타입명을 기재한다. 그러면 위 리스트 클래스 자료형의 타입은 String 타입으로 지정되어 문자열 데이터만 리스트에 적재할 수 있게 된다. + +## **Optional이란?** + +- NullPointerException(NPE)를 방지할 수 있도록 도와준다. +- **Optional는 NULL이 올 수 있는 값을 감싸는 Wrapper 클래스로, NPE가 발생하지 않도록 도와준다.** +- Optional 클래스는 아래 예제처럼 value에 값을 저장하기 때문에 NULL이더라도 바로 NPE가 발생하지 않으며, 각종 메서드를 제공한다. + +```jsx +public final class Optional { + + private final T value; +... + +} +``` + +- 하지만, Optional은 데이터를 Wrapping하고 다시 풀고, NULL일 경우에는 대체 함수를 호출하는 등의 오버헤드가 있으므로 성능이 저하될 수 있다. +- 그래서 메서드의 반환 값이 절대 NULL이 아니라면 Optional을 사용하지 않는 것이 성능 저하가 적다. + + + +## **References** + +- [일급 컬렉션(First-Class Collection)이란? (tistory.com)](https://dkswnkk.tistory.com/696) +- [[Java] 스트림과 병렬 처리 ① (velog.io)](https://velog.io/@mmy789/Java-%EC%8A%A4%ED%8A%B8%EB%A6%BC%EA%B3%BC-%EB%B3%91%EB%A0%AC-%EC%B2%98%EB%A6%AC-1) +- [[Java] Optional이란? 개념과 사용법 - 1 (tistory.com)](https://frtt0608.tistory.com/152) \ No newline at end of file From c4079f673c3c13deba8e8867e9599400f06932c0 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Thu, 12 Oct 2023 23:11:37 +0900 Subject: [PATCH 4/9] =?UTF-8?q?docs:=203=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jina4066.md | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) rename "week03/3\354\243\274\354\260\250.md" => week03/jina4066.md (87%) diff --git "a/week03/3\354\243\274\354\260\250.md" b/week03/jina4066.md similarity index 87% rename from "week03/3\354\243\274\354\260\250.md" rename to week03/jina4066.md index 1bf35b9..63159a2 100644 --- "a/week03/3\354\243\274\354\260\250.md" +++ b/week03/jina4066.md @@ -112,9 +112,7 @@ MVC 패턴을 도입하면서 UI 영역과 도메인(비즈니스 로직) 영역으로 구분되어 서로에게 영향을 주지 않으면서 개발과 유지보수가 가능해지게 되었다. - ![[출처: 인프런 김영한 강의]](%5B%E1%84%8F%E1%85%A1%E1%84%8B%E1%85%AE%203%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1%5D%2013426a9837e040c1bb5d8e3db912cf43/Untitled.png) - - [출처: 인프런 김영한 강의] + ![inflearn_image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/e01b08e4-686a-4b74-be7c-3eb50fea40d1) - Model(모델) @@ -205,33 +203,34 @@ 반대로 **내부 반복자(iternal iterator)**란 **컬렉션 내부에서 요소들을 반복시키고, 개발자는 요소 당 처리해야 할 코드만 제공하는 코드 패턴**을 말한다. - ![Untitled](%5B%E1%84%8F%E1%85%A1%E1%84%8B%E1%85%AE%203%E1%84%8C%E1%85%AE%E1%84%8E%E1%85%A1%5D%2013426a9837e040c1bb5d8e3db912cf43/Untitled%201.png) + ![iterator_image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/3ef943f9-8c73-460a-a85c-bc94026a669c) + - - 내부 반복자를 사용했을 때의 이점 +- 내부 반복자를 사용했을 때의 이점 - 내부 반복자를 사용하면 컬렉션 내부에서 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맡겨두고, **개발자는 요소 처리 코드에만 집중할 수 있게 된다.** 내부 반복자는 요소들의 반복 순서를 변경하거나, 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있게 도와주기 때문에 **하나씩 처리하는 순차적 외부 반복자보다는 효율적으로 요소를 반복시킬 수 있다.** +내부 반복자를 사용하면 컬렉션 내부에서 어떻게 요소를 반복시킬 것인가는 컬렉션에게 맡겨두고, **개발자는 요소 처리 코드에만 집중할 수 있게 된다.** 내부 반복자는 요소들의 반복 순서를 변경하거나, 멀티 코어 CPU를 최대한 활용하기 위해 요소들을 분배시켜 병렬 작업을 할 수 있게 도와주기 때문에 **하나씩 처리하는 순차적 외부 반복자보다는 효율적으로 요소를 반복시킬 수 있다.** - **Iterator**는 **컬렉션의 요소를 가져오는 것에서부터 처리하는 것까지 모두 개발자가 작성**해야 하지만,**스트림**은 람다식으로 요소 처리 내용만 전달할 뿐, **반복은 컬렉션 내부에서 일어난다.** +**Iterator**는 **컬렉션의 요소를 가져오는 것에서부터 처리하는 것까지 모두 개발자가 작성**해야 하지만,**스트림**은 람다식으로 요소 처리 내용만 전달할 뿐, **반복은 컬렉션 내부에서 일어난다.** - 스트림을 이용하면 **코드도 간결**해지지만, 무엇보다도 **요소의 병렬 처리가 컬렉션 내부에서 처리**된다는 효과까지 있다. +스트림을 이용하면 **코드도 간결**해지지만, 무엇보다도 **요소의 병렬 처리가 컬렉션 내부에서 처리**된다는 효과까지 있다. - - - 작업 분류 - - 중간 연산 - - 연산결과가 스트림을 반환하기 때문에 스트림에 연속해서 중간 연산을 할  수 있다. (0 ~ n번) - - 최종 연산 - - 연산 결과가 스트림이 아닌 연산으로, 스트림의 요소를 소모하기 때문에 마지막에 단 한번만 사용이 가능하다. (0~1번) +- 작업 분류 + - 중간 연산 + - 연산결과가 스트림을 반환하기 때문에 스트림에 연속해서 중간 연산을 할  수 있다. (0 ~ n번) + - 최종 연산 + - 연산 결과가 스트림이 아닌 연산으로, 스트림의 요소를 소모하기 때문에 마지막에 단 한번만 사용이 가능하다. (0~1번) - ```jsx - stream.distinct().limit(5).sorted().forEach(System.out::println); - // distinct(), limit(), sorted() -> 중간 연산 - // 마지막 스트림을 소모하여 각 스트림의 요소를 출력하는 forEach -> 최종 연산 - ``` + ```jsx + stream.distinct().limit(5).sorted().forEach(System.out::println); + // distinct(), limit(), sorted() -> 중간 연산 + // 마지막 스트림을 소모하여 각 스트림의 요소를 출력하는 forEach -> 최종 연산 + ``` - lazy Evaluation (지연된 연산) - 스트림에서 연산을 할때 한 가지 중요한 점은, 최종 연산이 수행되기 전까지는 중간 연산이 수행 되지 않는다는 점이다. @@ -244,7 +243,7 @@ - 내부 반복 - 스트림은 반복을 알아서 처리하고 결과 스트림값을 어딘가에 저장 - 장점: 작업을 투명하게 병렬적으로 처리하거나 최적화된 다양한 순서로 처리가 가능하다. - - for문과의 차이점? + - for문과의 차이점? - 중간 연산 메서드 - ****filter() / distinct()**** - filter() From 975ae14c2cc5f2a84fe3e234265414665ba6b511 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 17 Oct 2023 19:13:43 +0900 Subject: [PATCH 5/9] =?UTF-8?q?docs=20:=204=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "week04/4\354\243\274\354\260\250.md" | 21 ---- week04/jina4066.md | 161 ++++++++++++++++++++++++++ 2 files changed, 161 insertions(+), 21 deletions(-) delete mode 100644 "week04/4\354\243\274\354\260\250.md" create mode 100644 week04/jina4066.md diff --git "a/week04/4\354\243\274\354\260\250.md" "b/week04/4\354\243\274\354\260\250.md" deleted file mode 100644 index ecbc830..0000000 --- "a/week04/4\354\243\274\354\260\250.md" +++ /dev/null @@ -1,21 +0,0 @@ -# 4주차 학습 PR - -이번 주의 메인 테마는 테스트입니다. -단위 테스트와 테스트 툴인 JUnit5, AssertJ를 공부하고, 로또 미션에 충분한 테스트를 작성해주세요! -많은 예시 코드를 보시면 금방 감이 오실 겁니다! - -* 테스트 코드란? 테스트 코드는 왜 작성하는지? - -* 단위 테스트란? - -* JUnit5, AssertJ란? - -* BDD란? - -* private method test - -* @ParameterizedTest - -* 참고하면 좋을 것 같은 링크 -* https://youtu.be/mIO4Rbe_M74?feature=shared -* https://tecoble.techcourse.co.kr/post/2021-05-25-unit-test-vs-integration-test-vs-acceptance-test/ \ No newline at end of file diff --git a/week04/jina4066.md b/week04/jina4066.md new file mode 100644 index 0000000..3e6d59c --- /dev/null +++ b/week04/jina4066.md @@ -0,0 +1,161 @@ +# [4주차 학습 PR] + +--- + +이번 주의 메인 테마는 테스트입니다. 단위 테스트와 테스트 툴인 JUnit5, AssertJ를 공부하고, 로또 미션에 충분한 테스트를 작성해주세요! 많은 예시 코드를 보시면 금방 감이 오실 겁니다! + +- 테스트 코드란? 테스트 코드는 왜 작성하는지? + - 테스트 코드란, 소프트웨어의 기능과 동작을 테스트하는 데 사용되는 코드로, 개발자가 작성한 코드를 실행하고 예상된 결과가 정상적으로 나오는지 확인하는 데 사용된다. + - 테스트 코드에는 단위 테스트(Unit Testing), 통합 테스트(Integration Testing), E2E(End to End Testing) 등의 다양한 종류가 있으며, 각각의 테스트는 특정한 측면에서 소프트웨어의 동작을 테스트한다. + - 이처럼 테스트를 구분하는 이유는 테스트 대상의 범위가 다르기 때문이다. + - 개발자는 테스트 코드를 작성함으로써, 개발 과정 중 예상치 못한 문제를 미리 발견할 수 있고, 코드 수정이 필요한 상황에서 유연하고 안정적인 대응을 할 수 있다. + + + +- 단위 테스트란? + - 단위 테스트(Unit Test)는 소프트웨어 개발에서 일반적으로 사용되는 테스트 중 하나로, 개별적인 코드 단위(하나의 기능을 하는 코드)가 의도한 대로 작동하는지 확인하는 과정이다. + - 구현 단계에서 각 모듈의 개발을 완료한 후 개발자가 명세서의 내용대로 정 + 확히 구현되었는지를 테스트한다. +- JUnit5, AssertJ란? + - `JUnit5` + + > JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage + > + - JUnit Platform : 테스트를 실행해주는 런처 제공, TestEngine API 정의 + - JUnit Jupiter : TestEngine API 구현체로 JUnit5 제공 + - JUnit Vintage : 하위 버전을 실행할 수 있는 TestEngine 제공 + + - 특징 + - 테스트를 작성하고 실행하는 데 사용되는 오픈 소스 프레임 워크 + - annotation을 제공한다. + - 테스트 기대 결과를 위한 assertion을 제공한다. + - test runner를 제공한다. + - 퀄리티를 올리며 빠르게 코드를 작성할 수 있게 해준다. + - 자동으로 테스트가 실행될 수 있으며 자체의 결과를 확인하고 바로 결과를 제공한다. + - 테스트 cases 및 기타 테스트 suites를 포함하는 test suites로 구성된다. + - 테스트 성공 시 초록, 실패 시 빨강으로 표시된다. + - `AssertJ` + - AssertJ는 많은 assertion을 제공하는 자바 라이브러리이다. + - 에러 메세지와 테스트 코드의 가독성을 매우 높여주고 IDE에서 쓰기 굉장히 쉽다. + - 특히, junit에서 제공하는 assertEquals에 비해 훨씬 가독성이 올라간다. + + ```java + assertEquals(expected, actual); //junit + + assertThat(actual).isEqualTo(expected); //AssertJ + ``` + +- BDD란? + - ****BDD (Behavior Driven Development)는 제품이나 서비스의 행동에 초점을 맞춘 개발 방법론이다**** + - TDD에서 파생된 개발 방법론으로 개발자와 비개발자간의 협업 과정을 녹여낸 방법 + + + + - BDD의 개발 절차 + - Given - When -Then 세가지로 테스트를 진행하는 것 + - Given + - 시나리오 상에서 주어진 환경을 정의 + - When + - 사용자가 어떤 행위를 하는 것을 정의 + - Then + - 그에 따른 어떠한 결과를 정의 + + - private method test + - Java Reflection API를 이용한 메소드 호출 + - 자바는 클래스와 메소드 자체를 포함해 클래스의 변수, 메소드의 파라미터 타입, 메소드 이름 등의 메타 정보들을 위한 Class, Method 등을 정의해두었다. + - 리플렉션을 이용하면 정적으로 고정된 메소드의 코드를 메타정보로 추상화된 Method를 얻어낼 수 있으며 직접 호출 또한 가능하다. + - 그러므로 우리가 테스트하고자 하는 클래스로부터 Method를 추출하여 해당 메소드를 직접 invoke해주면 된다. + + ```java + @ExtendWith(MockitoExtension.class) + class PrivateTestClassTest { + + @InjectMocks + private PrivateTestClass target; + + @Test + void isPredifined가True_ReflectionAPI() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { + // given + String name = "Jina"; + Method method = target.getClass().getDeclaredMethod("isPredefined", String.class); + method.setAccessible(true); + + // when + boolean result = (boolean)method.invoke(target, name); + + // then + assertThat(result).isTrue(); + } + } + ``` + + 해당 메소드를 얻어오기 위해서는 메소드의 이름과 타입 클래스를 넘겨주어야 하며, private 메소드는 기본적으로 접근 가능 여부가 false이므로 이를 true로 변경해주어야 한다. —> 스프링 프레임워크로 더 간단히 test 가능 + + - ****Spring의 ReflectionTestUtils를 이용한 메소드 호출**** + - 스프링 프레임워크는 내부적으로 리플렉션을 상당히 많이 활용하고 있다. + - 그래서 직접 자바의 리플렉션 API를 하는 것 보다는 효율적으로 리플렉션을 사용하기 위한 유틸성 클래스인 ReflectionTestUtils를 제공하고 있다. + + ```java + @ExtendWith(MockitoExtension.class) + class PrivateTestClassTest { + + @InjectMocks + private PrivateTestClass target; + + @Test + void isPredifined가True_ReflectionTestUtils() { + // given + String name = "MangKyu"; + + // when + boolean result = ReflectionTestUtils.invokeMethod(target, "isPredefined", name); + + // then + assertThat(result).isTrue(); + } + } + ``` + + private 메소드를 호출하기 위한 ReflectionTestUtils의 invokeMethod는 파라미터로 타깃 객체, 메소드 이름, 파라미터 목록(가변 변수)를 받고 있다. 위의 코드를 실행하면 테스트가 성공함을 확인할 수 있다. + + - ****private 메소드 테스트를 지양해야 하는 이유**** + + 리플렉션은 런타임에 동작하는 기술로, 클래스와 메소드의 메타정보를 사용해서 애플리케이션을 동적으로 유연하게 만들 수 있다. 그래서 리플렉션을 사용하면 private 메소드를 invoke 할 수 있다. + + 그런데 문제는 이렇게 작성한 private 메소드에 대한 테스트는 깨지기 쉬운 테스트가 된다는 것이다. + + private 메소드는 내부를 감추어 클라이언트와의 결합도를 낮춰주는데, 클라이언트인 테스트 클래스가 내부 메소드를 알고 있으니 결합도가 높아진다. 그리고 이는 유지보수할 때 테스트에 대한 비용을 증가시키는 요인이 될 수 있는데, 메소드 이름이나 파라미터 등을 변경할 때 실패하게 된다. 또한 리플렉션 자체 역시 컴파일 에러를 유발하지 못하므로 최대한 사용을 자제해야 한다. + +- @ParameterizedTest + - 여러 argument를 이용해 테스트를 여러번 돌릴 수 있는 테스트를 할 수 있는 기능 + - 사용하기 위해서는 `@Test` 대신 `@ParameterizedTest` 를 붙이면 된다. + - `@ParameterizedTest`를 사용하게 되면 최소 하나의 source 어노테이션을 붙여주어야 한다. + + --- + + - source annotaion + - ****ValueSource**** + - **argument가 하나**인 테스트에 사용할 수 있다. + - short, byte, int, long ,float, double, char, boolean, String, java.lang.Class에 사용할 수 있다. + - ****NullSource, EmptySource, NullAndEmptySource**** + - NullSource : null을 보낸다 + - EmptySource : 비어 있는 배열, 컬렉션, 문자열 등을 반환한다 + - NullAndEmptySource : NullSource와 EmtpySource를 합쳐놓은 것이다 + - ****EnumSource**** + - Enum을 argument로 보내줄 수 있다. + + 1. Enum 전체를 가져오기 + + 1. Enum의 특정 목록만 가져오기 + 2. regex 사용하기 + - ****MethodSource**** + - 테스트 클래스 내의 메소드 혹은 외부 클래스의 메소드가 반환하는 값을 source로 삼는 것이다. + - 테스트 클래스 내에 있고 `@TestInstance(Lifecycle.PRE_CLASS)`를 붙인 것이 아니라면, 모두 static 메소드여야 한다. + - 한 파라미터만 넣을 수도 있고, 여러 파라미터를 넣을 수도 있다. + - 테스트 메소드와 이름이 동일하면 source를 명시적으로 적어주지 않아도 된다. +- 참고하면 좋을 것 같은 링크 +- [https://youtu.be/mIO4Rbe_M74?feature=shared](https://youtu.be/mIO4Rbe_M74?feature=shared) +- [https://tecoble.techcourse.co.kr/post/2021-05-25-unit-test-vs-integration-test-vs-acceptance-test/](https://tecoble.techcourse.co.kr/post/2021-05-25-unit-test-vs-integration-test-vs-acceptance-test/) From 7dad91b1e7a1fa09ff884013f0e0dbc20e7ec86b Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 7 Nov 2023 21:47:07 +0900 Subject: [PATCH 6/9] =?UTF-8?q?docs:=207=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\352\271\200\354\247\200\353\202\230.md" | 0 "week07/7\354\243\274\354\260\250.md" | 24 --- .../\352\271\200\354\247\200\353\202\230.md" | 161 ++++++++++++++++++ 3 files changed, 161 insertions(+), 24 deletions(-) rename week04/jina4066.md => "week04/\352\271\200\354\247\200\353\202\230.md" (100%) delete mode 100644 "week07/7\354\243\274\354\260\250.md" create mode 100644 "week07/\352\271\200\354\247\200\353\202\230.md" diff --git a/week04/jina4066.md "b/week04/\352\271\200\354\247\200\353\202\230.md" similarity index 100% rename from week04/jina4066.md rename to "week04/\352\271\200\354\247\200\353\202\230.md" diff --git "a/week07/7\354\243\274\354\260\250.md" "b/week07/7\354\243\274\354\260\250.md" deleted file mode 100644 index cd83de7..0000000 --- "a/week07/7\354\243\274\354\260\250.md" +++ /dev/null @@ -1,24 +0,0 @@ -## 7주차 학습 PR - -### 싱글톤 패턴이란? - - -### 싱글톤 컨테이너란?(feat.싱글톤의 단점..?) - - -### Java의 POJO란 무엇인가?(feat.Spring의 Bean) - - -### 스프링의 사용 이유, 장점이나 특징(이거 중요!!) - - -### 스프링에서 사용되는 어노테이션 10개 이상 정리하기 --> 세션을 맡아주셨던 경호님께서 이때 어노테이션 한번에 정리해두니 그렇게 편했다고.. - - -### controller - service - repository란? - - -### (선택) 지난 세션에서 추가적으로 궁금했던 것들 자유롭게 기록 -지난 세션이나 학습 pr을 공부하시면서 어 그럼 이건 뭐지..? 하는 궁금증이 생겨난다면, -더 깊이있게 학습하시고 소제목(###)을 추가적으로 달아서 정리해보세요!! \ No newline at end of file diff --git "a/week07/\352\271\200\354\247\200\353\202\230.md" "b/week07/\352\271\200\354\247\200\353\202\230.md" new file mode 100644 index 0000000..28aec9d --- /dev/null +++ "b/week07/\352\271\200\354\247\200\353\202\230.md" @@ -0,0 +1,161 @@ +## **7주차 학습 PR** + +### **싱글톤 패턴이란?** + +- 소프트웨어 디자인 패턴에서 싱글턴 패턴(Singleton pattern)을 따르는 클래스는, 생성자가 여러 차례 호출되더라도 **실제로 생성되는 객체는 하나**이고 최초 생성 이후에 호출된 생성자는 최초의 생성자가 생성한 객체를 리턴한다. +- 간단히 설명하면 싱글톤 패턴은 **객체의 인스턴스를 한개만 생성되게 하는 패턴이다.** +- 즉, 싱글톤 패턴은 아래와 같은 상황에 사용한다. + - 프로그램 내에서 하나의 객체만 존재해야 한다. + - 프로그램 내에서 여러 부분에서 해당 객체를 공유하여 사용해야한다. + +- 싱글톤 패턴의 이점은? + + **1. 메모리 측면의 이점** + + 싱글톤 패턴을 사용하게 된다면 한개의 인스턴스만을 고정 메모리 영역에 생성하고 추후 해당 객체를 접근할 때 메모리 낭비를 방지할 수 있다. + + **2. 속도 측면의 이점** + + 생성된 인스턴스를 사용할 때는 이미 생성된 인스턴스를 활용하여 속도 측면에 이점이 있다. + + **3. 데이터 공유가 쉽다** + + 전역으로 사용하는 인스턴스이기 때문에 다른 여러 클래스에서 데이터를 공유하며 사용할 수 있다. 하지만 동시성 문제가 발생할 수 있어 이 점은 유의하여 설계하여야 한다. + + - 동시성 문제란? + - 여러 스레드가 동시에 같은 인스턴스의 필드 값을 변경하면서 발생하는 문제 + - 중요한 점은 값에 무조건 동시에 접근한다고 문제가 발생하는 것이 아니라 값을 어디선가 **변경**할 때 발생한다. + - 스레드는 별도의 stack 영역을 갖기 떄문에, 인스턴스를 갖도록 설계하지 않고 지역변수나 매개변수 등으로 객체를 넘겨서 사용하게 되면 적은 노력으로 동시성 이슈를 피할 수 있다. + + +### **싱글톤 컨테이너란?(feat.싱글톤의 단점..?)** + +- 싱글톤 패턴은 많은 문제들을 가지고 있다. + - 싱글톤 패턴을 적용하기 위해 구현할 코드양이 많아지면서 비용이 늘어난다. + - 싱글톤 패턴은 클래스 내에서 하나의 유일한 인스턴스를 생성하고 유지해야 한다. 이를 위해 인스턴스 변수를 선언하고, 생성자를 private으로 만들어야 한다. 또한 인스턴스를 얻거나 생성하는 메서드를 만들어야 한다. 싱글톤 패턴을 구현하는 데에 이 모든 코드가 필요하므로 코드 양이 늘어나게 된다. + - 의존관계상 클라이언트가 구현체에 의존하면서 DIP를 위반하게 된다. + - DIP를 위반하면 자연스럽게 OCP를 위반할 가능성도 높아진다. + - 테스트가 어려워진다. + - 인스턴스를 미리 다 받아서 설정이 끝난 상태이기에 유연한 테스트가 힘들다. + - 내부 속성을 변경하거나 초기화가 어렵다. + - private 생성자로 자식 클래스를 만들기 어렵다. + - 유연성이 떨어진다. + + → 하지만 스프링 컨테이너에서는 싱글톤의 이러한 단점들을 해결하면서 장점만 가지는 싱글톤을 사용한다. + +- 싱글톤 컨테이너 + - 스프링 컨테이너는 싱글톤 패턴을 적용하지 않아도 싱글톤으로 객체들을 관리한다. + - 스프링 컨테이너는 싱글톤 컨테이너 역할을 한다. 이처럼 싱글톤 객체를 생성 및 관리하는 기능을 **싱글톤 레지스트리**라 한다. + - 이렇게 스프링 컨테이너에서 싱글톤 컨테이너 역할을 해줌으로써 싱글톤 패턴의 단점을 없애고 객체의 단일성을 유지할 수 있다. + + → 그렇기에 각각의 빈들은 싱글톤 패턴 적용을 위한 코드를 작성할 필요가 없다. + → 더하여 DIP, OCP, 테스트, private 생성자를 고민하지 않아도 된다. + + +### **Java의 POJO란 무엇인가?(feat.Spring의 Bean)** + +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/b02c0dbc-3fb8-4ea0-bbc2-b155dfa3d244) + +- POJO란 Plain Old Java Object의 약자로, 이를 직역하면 순수한 오래된 자바 객체이다. 즉, Java로 생성하는 순수한 객체를 뜻한다. +- 위 이미지는 Spring 삼각형이라는 유명한 이미지로 Spring의 핵심 개념들을 모두 표현하고 있다. POJO는 IoC/DI, AOP, PSA를 통해서 달성할 수 있다는 것을 의미한다. +- POJO는 객체 지향적인 원리에 충실하면서 환경과 기술에 종속되지 않고, 필요에 따라 재활용될 수 있는 방식으로 설계된 오브젝트를 의미한다. 이러한 POJO에 애플리케이션의 핵심 로직과 기능을 담아 설계하고 개발하는 방법을 `POJO 프로그래밍`이라고 한다. + +- POJO 프로그래밍 + - POJO를 이용하여 프로그래밍 코드를 작성하는 것이다. 그러나 순수 자바 객체만을 사용한다고 해서 POJO 프로그래밍이라고 볼 수는 없다. + - POJO 프로그래밍으로 작성한 코드가 되기 위해서는 기본적인 규칙들을 지켜야 한다. + 1. Java나 Java의 스펙에 정의된 것 이외에는 다른 기술이나 규약에 얽매이지 않아야 한다. + - Java 프로그래밍에서 자바 언어와 자바 플랫폼의 표준 스펙에는 의존성을 가질 수 있지만, Java 이외의 외부 기술, 프레임워크, 라이브러리, 또는 규약에 대한 의존성을 최소화해야 한다는 의미 + 2. 특정 환경에 종속적이지 않아야 한다. + - 자체 개발한 코드와 Java 표준 라이브러리를 주로 사용하며, 특정 프레임워크나 플랫폼에 강하게 의존하지 않아야 한다. + + - POJO 프로그래밍이 필요한 이유 + - 특정 환경이나 기술에 종속적이지 않으면 재사용이 가능하고, 확장 가능한 유연한 코드를 작성할 수 있다. + - 저수준 레벨의 기술과 환경에 종속적인 코드를 제거하여 코드를 간결해지며 디버깅하기에도 상대적으로 쉬워진다. + - 특정 기술이나 환경에 종속적이지 않기 때문에 테스트가 단순해진다. + - **객체지향적인 설계를 제한 없이 적용할 수 있다.** + + +### **스프링의 사용 이유, 장점이나 특징(이거 중요!!)** + +1. POJO 프로그래밍을 지향 + - POJO는 순수 Java만을 사용하여 만든 객체이므로 특정 기술이나 환경에 종속되지 않는다. 따라서, **외부 기술이나 규약의 변화에 얽매이지 않아, 보다 유연하게 변화와 확장에 대처할 수 있다.** 이러한 POJO를 사용하여 비즈니스 로직을 구현하면 **객체지향 설계를 제한없이 적용할 수 있으며, 코드가 단순해져 테스트와 디버깅 또한 쉬워진다.** + - 메소드나 객체(bean)의 호출 작업은 제어의 역전을 통해 외부에서 이루어진다. + - 제어의 역행을 전제조건으로 DI가 일어난다. + - 의존성을 가진 객체에 대해 스프링에서 의존성 주입이 발생하도록 한다. + - 의존성 주입 특성으로 인해 개발자가 POJO 개발이 가능하게 된다. + +2. PSA(Portable Service Abstraction, 일관된 서비스 추상화) + - 만일, 개발을 하던 중 사용 중이던 DB를 바꿔야 하는 상황이 왔을 떄, 각 DB 마다 사용 방법이 다르다면 코드를 모두 수정해 주어야 한다. + - 그러나 스프링을 사용하면 동일한 사용방법을 유지한 채로 데이터베이스를 바꿀 수 있다. 이는 **스프링이 데이터베이스 서비스를 추상화한 인터페이스를 제공해주기 때문에 가능**하다. + - 즉, 스프링은 Java를 사용하여 데이터베이스에 접근하는 방법을 규정한 인터페이스를 제공하고 있으며, 이를 J**DBC(Java DataBase Connectivity)**라고 한다. + - 각 데이터베이스를 만든 회사들은 자신의 데이터베이스에 접근하는 드라이버를 Java 코드의 형태로 배포하는데, **이 드라이버에 해당하는 Java 코드의 클래스가 JDBC를 구현합니다.** 따라서, JDBC를 기반으로 하여 데이터베이스 접근 코드를 작성해두면, 이후에 데이터베이스를 바꾸어도 기존에 작성한 데이터베이스 접근 로직을 그대로 사용할 수 있다. + - 이러한 JDBC처럼 **특정 기술과 관련된 서비스를 추상화하여 일관된 방식으로 사용될 수 있도록 한 것을 PSA(Portable Service Abstraction, 일관된 서비스 추상화)라고 한다.** + +3. AOP(관점지향 프로그래밍) 지원 + - 애플리케이션을 개발할 때에 구현해야 하는 기능들은 크게 **공통 관심 사항**과 **핵심 관심 사항**으로 분류할 수 있다. 먼저, **핵심 관심 사항은 애플리케이션의 핵심 기능과 관련된 관심 사항**으로, 커피 주문 애플리케이션을 예로 든다면 메뉴 등록하기, 주문하기, 주문 변경하기 등이 있다. + - 반면, **공통 관심 사항은 모든 핵심 관심 사항에 공통적으로 적용되는 관심 사항들을 의미한다.** 예를 들어, 메뉴 등록하기, 주문하기, 주문 변경하기 등 모든 핵심 관심 사항에는 로깅이나 보안 등과 관련된 기능들이 공통적으로 적용되어야만 한다. + - 이 때, 핵심 관심 사항과 공통 관심 사항이 코드에 함께 모여 있으면 필연적으로 **공통 관심 사항과 관련된 코드가 중복**될 수밖에 없다. 이처럼 코드가 중복되어져 있는 경우, **공통 관심 사항을 수행하는 로직이 변경되면 모든 중복 코드를 찾아서 일일이 수정해주어야만 한다.** + - 코드의 중복이라는 문제를 해결하기 위해서는 공통 관심 사항과 관련된 기능들을 별도의 객체로 분리해낸 다음, 분리해낸 객체의 메서드를 통해 공통 관심 사항을 구현한 코드를 실행시킬 수 있도록 해야 한다. 이처럼, 애플리케이션 전반에 걸쳐 적용되는 공통 기능을 비즈니스 로직으로부터 분리해내는 것을 AOP(Aspect Oriented Programming, 관심 지향 프로그래밍)라고 한다. + +### **스프링에서 사용되는 어노테이션 10개 이상 정리하기** + +- `Annotation`은 클래스와 메서드에 추가하여 다양한 기능을 부여하는 역할을 한다. Annotation을 활용하여 Spring Framework는 해당 클래스가 어떤 역할인지 정하기도 하고, Bean을 주입하기도 하며, 자동으로 getter나 setter를 생성하기도 한다. 이러한 Annotation을 통하여 **코드량이 감소하고 유지보수하기 쉬우며, 생산성이 증가된다.** +- @Component + - 개발자가 생성한 Class를 Spring의 Bean으로 등록할 때 사용하는 Annotation + - Spring은 해당 Annotation을 보고 Spring의 Bean으로 등록 +- ****@ComponentScan**** + - Spring Framework는 @Component, @Service, @Repository, @Controller, @Configuration 중 1개라도 등록된 클래스를 찾으면, Context에 bean으로 등록 + - @ComponentScan Annotation이 있는 클래스의 하위 Bean을 등록 될 클래스들을 스캔하여 Bean으로 등록 +- ****@Bean**** + - @Bean Annotation은 개발자가 제어가 불가능한 외부 라이브러리와 같은 것들을 Bean으로 만들 때 사용 +- ****@Controller**** + - Spring에게 해당 Class가 Controller의 역할을 한다고 명시하기 위해 사용하는 Annotation +- @****RequestHeader**** + - Request의 header값을 가져올 수 있으며, 해당 Annotation을 쓴 메소드의 파라미터에 사용 +- @****RequestMapping**** + - @RequestMapping(value=”“)와 같은 형태로 작성하며, 요청 들어온 URI의 요청과 Annotation value 값이 일치하면 해당 클래스나 메소드가 실행 + - Controller 객체 안의 메서드와 클래스에 적용 가능하며, 아래와 같이 사용 + - Class 단위에 사용하면 하위 메소드에 모두 적용 + - 메소드에 적용되면 해당 메소드에서 지정한 방식으로 URI를 처리 +- ****@ResponseBody**** + - @ResponseBody은 메소드에서 리턴되는 값이 View 로 출력되지 않고 HTTP Response Body에 직접 쓰인다. + - return 시에 json, xml과 같은 데이터를 return +- ****@RequestParam**** + - URL에 전달되는 파라미터를 메소드의 인자와 매칭시켜, 파라미터를 받아서 처리할 수 있는 Annotation + - Json 형식의 Body를 MessageConverter를 통해 Java 객체로 변환 +- ****@Autowired**** + - Spring Framework에서 Bean 객체를 주입받기 위한 방법은 크게 3가지가 있다. + - @Autowired + - 생성자 (@AllArgsConstructor 사용) + - setter + - Bean을 주입받기 위하여 @Autowired 를 사용 Spring Framework가 Class를 보고 Type에 맞게(Type을 먼저 확인 후, 없으면 Name 확인) Bean을 주입 +- ****@SpringBootTest**** + - Spring Boot Test에 필요한 의존성을 제공 +- ****@Test**** + - JUnit에서 테스트 할 대상을 표시 + +### **controller - service - repository란?** + +1. **Controller**: + - Controller는 웹 애플리케이션에서 HTTP 요청을 처리하고 클라이언트에게 HTTP 응답을 제공하는 역할 + - 클라이언트에서 HTTP 요청을 보내면 Controller는 해당 요청을 처리하고 비즈니스 로직을 호출하거나 다른 서비스와 상호작용 + - 주요 역할은 요청을 라우팅하고 모델 및 뷰를 결합하여 클라이언트에게 응답을 제공 + - 스프링 프레임워크에서는 **`@Controller`** 어노테이션을 사용하여 Controller 클래스를 정의하며, 이러한 클래스는 특정 URL 경로에 매핑된다. +2. **Service**: + - Service는 비즈니스 로직을 포함 + - Controller에서 요청을 받아와서 해당 요청에 대한 비즈니스 로직을 처리하거나, 데이터베이스와 상호작용하는 역할 + - Service는 코드를 재사용하고 애플리케이션의 모듈화를 촉진하는 데 사용 + - 주요 역할은 비즈니스 로직을 구현하고, 이 로직이 잘 작동하도록 하는 것 + - 스프링에서는 **`@Service`** 어노테이션을 사용하여 Service 클래스를 정의하며, 이러한 클래스는 주로 Controller와 Repository 사이에서 중재자 역할로 이루어짐. +3. **Repository**: + - Repository는 데이터베이스와 상호작용하여 데이터를 저장, 검색, 업데이트, 삭제하는 역할 + - 데이터에 접근하는 역할로, 데이터베이스와 직접 상호작용하는 코드를 캡슐화 + - 주로 데이터베이스와의 통신을 추상화하고 데이터 액세스 코드를 관리 + - 스프링에서는 **`@Repository`** 어노테이션을 사용하여 Repository 클래스를 정의하며, 이러한 클래스는 데이터베이스 연동을 위한 CRUD(Create, Read, Update, Delete) 작업을 수행 + + +즉, Controller는 클라이언트와 상호작용하고, Service는 비즈니스 로직을 처리하며, Repository는 데이터베이스와의 상호작용을 담당한다. + +### **(선택) 지난 세션에서 추가적으로 궁금했던 것들 자유롭게 기록** + +지난 세션이나 학습 pr을 공부하시면서 어 그럼 이건 뭐지..? 하는 궁금증이 생겨난다면, 더 깊이있게 학습하시고 소제목(###)을 추가적으로 달아서 정리해보세요!! From 14f48f978d13f3b13b64114e4c873035fdcda767 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 14 Nov 2023 22:00:41 +0900 Subject: [PATCH 7/9] =?UTF-8?q?docs:=208=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "week08/8\354\243\274\354\260\250.md" | 10 - .../\352\271\200\354\247\200\353\202\230.md" | 171 ++++++++++++++++++ 2 files changed, 171 insertions(+), 10 deletions(-) delete mode 100644 "week08/8\354\243\274\354\260\250.md" create mode 100644 "week08/\352\271\200\354\247\200\353\202\230.md" diff --git "a/week08/8\354\243\274\354\260\250.md" "b/week08/8\354\243\274\354\260\250.md" deleted file mode 100644 index c553a92..0000000 --- "a/week08/8\354\243\274\354\260\250.md" +++ /dev/null @@ -1,10 +0,0 @@ -# 8주차 학습 PR - -안녕하세요! 여러분 벌써 8주차라니, 15주차까지니까 벌써 반 정도 왔네요?? -이번 학습 PR은 심플하게 문항 딱 하나만 준비했습니다! -그러니 가능하면 딥하게!! 준비해주셔야 합니다~ 다음 세션 주제이기도 해요 ㅎ - -## HTTP 요청이 들어왔을 때 요청을 받고 응답하기 까지의 전 과정을 설명해주세요. -* 필수 포함 단어(필터, 인터셉터, dispatcherServlet) - -## (선택) 혹시 위 질문에 대한 답을 찾다가 새로운 개념들을 발견하면 정리해볼까요?? diff --git "a/week08/\352\271\200\354\247\200\353\202\230.md" "b/week08/\352\271\200\354\247\200\353\202\230.md" new file mode 100644 index 0000000..6234f5f --- /dev/null +++ "b/week08/\352\271\200\354\247\200\353\202\230.md" @@ -0,0 +1,171 @@ +# 8주차 학습 PR + +안녕하세요! 여러분 벌써 8주차라니, 15주차까지니까 벌써 반 정도 왔네요?? +이번 학습 PR은 심플하게 문항 딱 하나만 준비했습니다! +그러니 가능하면 딥하게!! 준비해주셔야 합니다~ 다음 세션 주제이기도 해요 ㅎ + +## HTTP 요청이 들어왔을 때 요청을 받고 응답하기 까지의 전 과정을 설명해주세요. +* 필수 포함 단어(필터, 인터셉터, dispatcherServlet) + +- 웹의 존재 이유는 정보 자원의 공유이다. 웹은 수많은 요청과 응답 사이클의 연속으로 이루어진다. +- 서버는 정보, 자원, 서비스를 제공하는 측. 즉, 요청을 받고 이에 응답하는 측이다. + - 예시로는 웹 서버들이 있다. +- 클라이언트는 정보, 자원, 서비스를 사용하는 측. 요청을 보내는 측이다. + - 예시로는 웹 브라우저들이 있다. +- `HTTP`란? + - HyperText Transfer Protocol의 약자이다. + - 컴퓨터들끼리 HTML 파일을 주고 받을 수 있도록 하는 약속, 소통 방식이다. +- 그렇다면 `HTML`이란? + - HyperText Markup Language의 약자이다. + - 문서와 문서가 링크로 연결되도록 하는 태그로 구성된 언어이다. 그 문서들이 웹브라우저 위에서 동작하도록 하는 언어가 HTML이다. + - HTML로 작성된 문서(웹페이지)를 주고 받을 수 있게 하는 통신규약이 바로 HTTP다. +- `Request` + - HTTP Request(요청)는 백엔드(서버)에서 데이터를 처리하기 위한 또는 가져오기 위한 메시지이다. 메시지의 구조는 크게 세 부분으로 구성되어 있다. + + > **1. Start Line** + > + > + > 요청의 첫번 째 줄이며, 시작 줄도 세 부분으로 구성되어있다. + > + > - HTTP Method: 해당 요청이 의도한 액션을 정의하는 부분. GET, POST, DELETE 가 주로 쓰임. + > - Request target: 해당 request 가 전송되는 목표 url + > - HTTP Version: 사용되는 HTTP 의 버전. 주로 1.1이 쓰인다.ex) GET /login HTTP/1.1GET 메서드로 login 이라는 요청 타겟에 HTTP 1.1 버전으로 요청을 보냄 + + > **2. Header** + > + > + > 해당 요청에 대한 추가 정보(메타 데이터)를 담고 있는 부분. + > + > - key : value 값으로 되어있다. 자주 사용되는 HEADER 의 정보는 아래와 같다. + > + > ``` + > Headers:{ + > HOST: 요청을 보내는 타켓의 주소. 웹사이트는 기본 주소 (ex: www.naver.com) + > User-Agent: 요청을 보내는 클라이언트에 대한 정보 (ex: chrome, firefox 등) + > Content-Type: 해당 요청이 보내는 메세지 body 타입 (ex: application/json 등) + > Content-Length: body 내용의 길이 + > Authorization: 회원 인증/인가를 처리하기 위해 로그인 토큰을 Authorization 에 담는다. + > } + > ``` + > + + > **3. Body** + > + > + > 해당 요청의 실제 내용. 주로 body 를 사용하는 메서드는 POST 이다. + > + > ``` + > body{ + > "email" : "aaa@aaa.com", + > "user_name" : "swd" + > } + > ``` + > +- `Response` + - 요청과 마찬가지로 Response도 메시지이다. + - HTTP 규약에 따른 응답의 구조도 크게 3부분으로 나뉜다. + + > **1. Start Line** + > + > + > 응답의 상태 줄. 응답은 요청에 대한 처리 상태를 클라이언트에게 알려주면서 시작한다. + > + > - **HTTP Version** - 요청의 HTTP버전과 동일 + > - **Status Code** - 응답 메세지의 상태 코드 + > - **Status Text** - 응답 메세지의 상태를 간략하게 설명해주는 텍스트ex) HTTP/1.1 404 Not Foundex) HTTP/1.1 200 SUCCESS + + > **2. Headers** + > + > + > 요청의 헤더와 동일하다. 응답의 추가 정보(메타 데이터)를 담고 있는 부분이다. + > + > **다만, 응답에서만 사용되는 헤더의 정보들이 있는데, 요청하는 브라우저의 정보가 담긴 User-Agent 대신 Server 헤더가 사용된다.** + > + + > **3. Body** + > + > + > 요청의 Body 와 일반적으로 동일하다. + > + > 요청의 메서드에 따라서 Body 가 항상 존재하지 않듯이, 응답도 응답의 형태에 Body 가 없을 수 있다. 주로 사용되는 Body 의 데이터 타입은 JSON(JavaScript Object Notation) 이다. + > + +## HTTP의 동작과정 + +> 서버 접속 -> 클라이언트 -> **요청** -> 서버 -> **응답** -> 클라이언트 -> 연결 종료 +> + +![image](https://github.com/COW-edu/cow-be-mission-api/assets/108182934/e2dbb184-cf8e-4b0b-b48a-4999f3996b02) +1. 사용자가 웹 브라우저에 URL 주소를 입력한다. +2. DNS 서버에 웹 서버의 호스트 이름을 IP 주소로 변경 요청한다. + - DNS 작동원리 + 1. 웹 브라우저에 `google.com`을 입력 + 2. `Local DNS`에게 Hostname(google.com)에 대한 IP 주소 요청 + 3. Local DNS에 IP 주소가 없다면 다른 DNS Name Server(Root DNS) 정보를 응답 + 4. `Root DNS` 서버에게 Hostname 에 대한 IP 주소를 요청 + 5. Root DNS 서버는 .com 도메인을 관리하는 TLD(Top-Level Domain) Name Server 정보 응답 + 6. `TLD`에게 Hostname에 대한 IP 주소 요청 + 7. TLD는 Hostname을 관리하는 `DNS Server` 정보 응답 + 8. [google.com](http://google.com) 도메인을 관리하는 DNS Server에게 Hostname에 대한 IP 주소를 요청 + 9. `DNS Serve`r는 Hostname 에 대한 IP 주소 응답 + 10. `Local DNS Server`는 응답으로 받은 Hostname에 대한 IP 주소를 캐싱하고 IP 주소 정보로 HTTP 요청 + + - [`google.com`](http://google.com) 으로 요청했지만, 실제로는 DNS 서버를 통해 알아낸 IP주소와 입력한 URL 정보가 함께 요청으로 전달된다. + - URL 정보와 전달받은 IP 주소는 HTTP Protocol을 사용하여 HTTP `Request Message`를 생성한다. + + ![image](https://github.com/COW-edu/cow-be-mission-api/assets/108182934/d597797f-9614-4b30-9357-d9ff7f762c1f) + +3. 웹서버와 TCP 연결을 시도한다. + - HTTP 요청 Message는 TCP Protocol을 사용하여 인터넷을 거쳐 해당 IP주소의 컴퓨터 Web Server로 전송된다. +4. 클라이언트가 서버에게 요청한다. + - Web Server 로 도착한 HTTP 요청 Message는 HTTP Protocol을 사용하여 URL 정보로 변환된다. + + > **HTTP Request Message = Request Header + 빈 줄 + Request Body** + > + > - Request Header + > - 요청 메소드 + 요청 URI + HTTP 프로토콜 버전 + > - `GET /background.png HTTP/1.0` `POST / HTTP 1.1` + > - Header 정보(key-value 구조) + > - 빈 줄 + > - 요청에 대한 모든 메타 정보가 전송되었음을 알리는 용도 + > - Request Body + > - GET, HEAD, DELETE, OPTIONS처럼 리소스를 가져오는 요청은 바디 미포함 + > - 데이터 업데이트 요청과 관련된 내용 (HTML 폼 콘텐츠 등) + - Web Server는 HTTP 요청을 받고, 바로 컨텐츠를 응답하거나 WAS에 요청을 전달한다. + - WAS에 요청이 전달되고, WAS에서 처리된 요청이 있다면 해당 컨텐츠를 응답한다. + - WAS 의 동작원리 + - Web Server 로부터 받은 요청과 관련된 `Servlet 을 메모리에 로딩` + - web.xml 을 참조하여 해당 Servlet 에 대한 Thread 생성 (Thread Pool 활용) + - HttpServletRequest, HttpServletResponse 객체를 생성하여 생성된 Servlet에 전달 + - Thread는 Servlet의 service() 호출 + - service() 는 요청에 맞는 `doGet()` or `doPost()` 호출 + - doGet() or doPost() 는 인자에 맞게 생성된 적절한 동적 컨텐츠를 Response 객체에 담아 WAS에 전달 + - WAS는 Response 객체를 HttpResponse 형태로 바꾸어 Web Server에 전달 + - 생성된 Thread를 종료하고, HttpServletRequest, HttpServletResponse 객체 제거 + + ![image](https://github.com/COW-edu/cow-be-mission-api/assets/108182934/c3e88471-eda0-401d-b3c5-85c085ab8195) + + - Servlet Filter + - 클라이언트의 요청이 Servlet Container에 도착하면, 먼저 설정된 필터들이 요청을 가로채어 필터 체인을 통과한다. + - 필터는 요청 로깅, 권한 검사, 문자 인코딩 설정 등의 작업을 수행한다. + - Dispatcher Servlet + - doGet() or doPost()를 통해 전달된 요청을 확인해서 적합한 Controller에 위임해주는 Front Controller를 거친다. + - Spring Interceptor + - Servlet Filter와 동일하게 웹 공통 관심사를 처리한다. + - Spring MVC 구조에 특화된 필터 기능을 제공한다. + - HandlerMapping을 통해 요청 URL에 매핑되는 Handler를 조회한다. + - 조회한 Handler를 실행할 수 있는 Handler Adapter를 조회한다. + - 앞서 조회한 Handler Adapter를 실행하면 Handler Adapter가 실제 Handler(Controller)를 실행한다. + - Handler Adapter는 Handler(Controller)가 반환하는 정보를 ModelAndView로 변환해서 반환한다. + +5. 서버가 클라이언트에게 데이터를 응답한다. + - 최종적으로 생성된 응답은 클라이언트로 전송되어 브라우저에 렌더링된다. + + > **HTTP Response Message = Response Header + 빈 줄 + Response Body** + > + > - Response HeaderHTTP 프로토콜 버전 + 응답 코드 + 응답 메시지ex. `HTTP/1.1 404 Not Found.`Header 정보(key-value 구조) + > - 빈 줄요청에 대한 모든 메타 정보가 전송되었음을 알리는 용도 + > - Response Body응답 리소스 데이터201, 204 상태 코드는 바디 미포함 +6. 서버 클라이언트 간 연결 종료 + +## (선택) 혹시 위 질문에 대한 답을 찾다가 새로운 개념들을 발견하면 정리해볼까요?? From 28933370020fa38077de483786ac39d66e53f4cf Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 21 Nov 2023 19:09:18 +0900 Subject: [PATCH 8/9] =?UTF-8?q?docs:=209=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- "\352\271\200\354\247\200\353\202\230.md" | 81 +++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 "\352\271\200\354\247\200\353\202\230.md" diff --git "a/\352\271\200\354\247\200\353\202\230.md" "b/\352\271\200\354\247\200\353\202\230.md" new file mode 100644 index 0000000..a7f296d --- /dev/null +++ "b/\352\271\200\354\247\200\353\202\230.md" @@ -0,0 +1,81 @@ +## Dispatcher Servlet이란? + +HTTP 프로토콜로 들어오는 모든 요청을 가장 먼저 받아 적합한 컨트롤러에 위임해주는 프론트 컨트롤러라고 정의할 수 있다. + +## Dispatcher Servlet이 요청을 받아 컨트롤러로 위임하는 과정 + +1. 서블릿 요청/응답을 HTTP 서블릿 요청/응답으로 변환 +2. HTTP Method에 따른 처리 작업 진행 +3. 요청에 대한 공통 처리 작업 진행 +4. 컨트롤러로 요청을 위임 + + 1) 요청에 매핑되는 HandlerExecutionChain 조회 + + 2) 요청을 처리할 HandlerAdapter 조회 + + 3) HandlerAdapter를 통해 컨트롤러 메소드 호출(Handler ExecutionChain 처리) + + +--- + +### 1. 서블릿 요청/응답을 HTTP 서블릿 요청/응답으로 변환 + +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/e10f6808-24ac-44aa-aaeb-33941fd18e55) + +HTTP 요청은 등록된 필터들을 거쳐 디스패처 서블릿이 처리하게 되는데, 가장 먼저 요청을 받는 부분은 부모 클래스인 HttpServlet에 구현된 service 메소드이다.
+service에서는 먼저 Servlet 관련 Request/Response 객체를 Http 관련 Request/Response로 캐스팅해준다. + +### 2. HTTP Method에 따른 처리 작업 진행 +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/25d7883e-e561-4e5f-97e2-a5870b3ab206) + +그리고 나서 HttpServletRequest 객체를 파라미터로 갖는 service 메소드를 호출한다. +
+요청 메소드에 따라 필요한 처리와 doX 메소드를 호출해준다. 그러면 doX 메소드를 오버라이딩하고 있는 자식 클래스인 FrameworkServlet로 다시 요청이 이어지게 된다. + +#### do X 메소드 구현 +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/cbc3591d-aba1-4429-be0d-0126fbbe2abb) + +각각의 doX 메소드에서는 Http Method에 맞는 작업을 한 후, 공통적으로 processRequest를 거치게 된다. + +### 3. 요청에 대한 공통 처리 작업 진행 +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/ef3d5c6c-4211-436a-8deb-4124d2c961df) + +processRequest에서는 request에 대한 공통 작업을 한 후, doService를 호출한다. + +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/262ed166-0be7-4a3b-abaa-a0075b4f795d) +자식 클래스인 DispatcherServlet의 doService 코드는 위와 같다. +doDispatch를 통해 HTTP 요청을 컨트롤러로 위임해준다. + +### 4. 컨트롤러로 요청을 위임 +[doDispatch 코드] +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/6a6f3cd7-a45b-4d96-82e2-30881b7334f8) +#### 1) 요청에 매핑되는 HandlerMapping(HandlerExecutionChain) 조회 +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/58d7488c-8d66-4fac-abec-be517fde714c) +getHandler에서는 HandlerMapping 목록을 순회하여 HandlerExecutionChain을 찾는다. +
+탐색을 통해 찾아진 HandlerMethod는 최종적으로 HandlerExecutionChain으로 반환된다.
+ +#### 2) 요청을 처리할 HandlerAdapter 조회 +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/ec14f293-3ff1-4f1d-80e6-348d11633515) +디스패처 서블릿은 HandlerExecutionChain을 직접 실행하지 않고, HandlerAdapter라는 어댑터 인터페이스를 통해 실행한다. 컨트롤러의 구현 방식에 상관없이 요청을 위임하도록 어댑터 패턴을 사용했다. doDispatch에서는 getHandlerAdapter를 통해 handlerAdapter를 조회한다. + +#### 3) HandlerAdapter를 통해 컨트롤러 메소드 호출 (HandlerExecutionChain 처리) + +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/585165c0-92e0-46a5-bbbc-fb987fb1d5f6) +HandlerAdapter를 통해 HandlerExecutionChain을 처리하는데, 내부적으로 인터셉터를 가지고 있어 공통적인 전/후처리 과정이 처리된다.
+적합한 HandlerAdapter가 HandlerExecutionChain을 모두 찾았으면 HandlerAdapter가 요청을 처리한다.
+요청의 종류에 따라 HandlerAdapter 구현체가 달라지고 그에 따른 전/후처리가 달라진다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/e55a8286-ac81-4aa0-bd7f-3aee898465f9) +RequestMappingHandlerAdapter의 handleInternal은 실제로 요청을 위임하는 invokeHandlerMethod를 호출한다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/03008066-a35c-4806-829a-a0d0917b5a4f) +InvokeHandlerMethod에서는 컨트롤러의 파라미터를 처리하는 ArgumentResolver와 반환값을 처리하는 ReturnValueHandler의 공통적인 전/후처리가 진행된다. 세팅이 끝나면 ServletInvocableHandlerMethod의 invokeAndHandle로 이어진다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/9a42ab48-384d-4e48-a92b-3f584d300e84) +invokAndHandle에서는 바로 부모 클래스인 InvocablehandlerMethod의 invokeForRequest로 이어진다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/a21e00d3-77d2-4a17-bf79-d05e44d3474b) +invokeForRequest에서는 메소드 호출을 위해 필요한 인자값을 처리한다. 그리고 doInvoke에서 만들어진 인자값을 통해 컨트롤러의 메소드를 호출한다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/eb5093e6-e5bc-47e7-b67e-4ef108b1ad3f) +doInvoke에서는 먼저 요청을 처리할 컨트롤러의 메소드 객체를 꺼내온다. 그리고 Method 객체의 invoke를 통해서 실제 컨트롤러로 위임을 해준다. +![image](https://github.com/COW-edu/COW-Spring-2/assets/108182934/9239bd61-af34-4118-99f9-12c494d122be) +컨트롤러에서 성공적으로 작업을 처리한 후에 ResponseEntity를 반환했다면 invokeAndHandle의 returnValue로 해당 객체가 온다.
+이후, returnValueHandler를 통해 후처리를 한다. 응답에 따라 다양한 형태로 처리하기 위해 리스트로 갖고 있다.
+ResponseEntity 객체를 반환한 경우에는 HandlerMethodeReturnValueHandler 구현체 중에서 HttpEntityMethodProcessor가 사용된다. 내부에서는 Response를 set 해주고, 응답 가능한 MediaType인지 검사한 후에 적절한 MessageConverter를 선택해 응답을 처리하고 결과를 반환한다. \ No newline at end of file From 649bcd84640a1f3696f7a60bc8c38bd6424a9fc8 Mon Sep 17 00:00:00 2001 From: "[jina4066]" <[jina4066@naver.com]> Date: Tue, 28 Nov 2023 23:39:38 +0900 Subject: [PATCH 9/9] =?UTF-8?q?docs:=2010=EC=A3=BC=EC=B0=A8=20=ED=95=99?= =?UTF-8?q?=EC=8A=B5=20PR=20=EB=93=B1=EB=A1=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../\352\271\200\354\247\200\353\202\230.md" | 0 .../\352\271\200\354\247\200\353\202\230.md" | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename "\352\271\200\354\247\200\353\202\230.md" => "week09/\352\271\200\354\247\200\353\202\230.md" (100%) rename "week10/10\354\243\274\354\260\250.md" => "week10/\352\271\200\354\247\200\353\202\230.md" (100%) diff --git "a/\352\271\200\354\247\200\353\202\230.md" "b/week09/\352\271\200\354\247\200\353\202\230.md" similarity index 100% rename from "\352\271\200\354\247\200\353\202\230.md" rename to "week09/\352\271\200\354\247\200\353\202\230.md" diff --git "a/week10/10\354\243\274\354\260\250.md" "b/week10/\352\271\200\354\247\200\353\202\230.md" similarity index 100% rename from "week10/10\354\243\274\354\260\250.md" rename to "week10/\352\271\200\354\247\200\353\202\230.md"