크롬, 사파리, 엣지와 같이 웹페이지, 이미지, 비디오등의 컨텐츠를 송/수신하고 표현해주는 소프트웨어
브라우저의 역할 : 컨텐츠를 송/수신, 컨텐츠를 표현
브라우저는 메세지가 OSI 7 계층을 거쳐 랜선을 통해 0과 1로 변경되어 흘러갈 수 있도록 도와주는 응용프로그램이자, 클라이언트와 상호작용해서 요청을 보내는 응용프로그래밍 계층의 첫 출발점
DNS(Domain Name Server)란?
IP주소 대신 abcdefg.com과 같은 도메인 이름 을 입력해서 원하는 웹 사이트로 이동하게 해주는 역할
요청을 받아줄 서버의 IP주소(192.168.0.123)와 도메인 이름을 사이를 중개해주는 중개 서버
HTTP란 ??
멀리 떨어져서 서로에 대한 정보가 없는 메세지의 송/수신자가 서로 필요한 요청과 응답을 할 수 있도록 미리 규약을 정해놓은 것을 프로토콜이라고 하고, 웹 상에서는 HTTP 라는 프로토콜을 통해서 데이터를 송/수신 하고 있다.
API(application programming interface)
다른 소프트웨어 시스템과 통신하기 위해 따라야 하는 규칙
개발자는 다른 애플리케이션이 프로그래밍 방식으로 애플리케이션과 통신할 수 있도록 API를 표시하거나 생성한다.
웹 API는 클라이언트와 웹 리소스 사이의 게이트웨이라고 생각할 수 있다.
인터페이스(interface)
서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다.
즉, 사용자가 기기를 쉽게 동작시키는데 도움을 주는 시스템을 의미한다.
컴퓨팅에서 컴퓨팅 시스템끼리 정보를 교환하는 공유 경계이다. 이러한 교환은 소프트웨어, 컴퓨터 하드웨어, 주변기기, 사람간에 이루어질 수 있으며, 서로 복합적으로 이루어질 수도 있다.
RESTful API란?
Representational State Transfer(REST)는 API 작동 방식에 대한 조건을 부과하는 소프트웨어 아키텍처입니다. REST는 처음에 인터넷과 같은 복잡한 네트워크에서 통신을 관리하기 위한 지침으로 만들어졌습니다. REST 기반 아키텍처를 사용하여 대규모의 고성능 통신을 안정적으로 지원할 수 있습니다. 쉽게 구현하고 수정할 수 있어 모든 API 시스템을 파악하고 여러 플랫폼에서 사용할 수 있습니다.
서버의 api가 적절하게 http를 준수하며 잘 설계되어있으면 RESTful 하게 설계되어 있다는 것
예를들어 api의 리소스 식별자를 ex - (”/”) 중복 없이 고유하게 잘 만들고,
해당 api에 적절하게 http메서드를 사용했다면, RESTful하게 설계했다고 볼 수 있다.
데이터베이스
데이터베이스는 데이터를 “효율적으로 성능 좋게” 다루기 위해 존재합니다.
즉 더 많이 저장하기 위해서가 아니라, 저장 조회 수정 삭제등을 더 빠르고 효율적으로 처리하기 위해서, “성능상의 이점”을 얻기 위해서 사용한다고 생각하면 좋을 것 같습니다.
이러한 맥락에서 데이터를 사용,활용하는 주체에 따라서 더 효율적인 방법이 각각 다르다 보니 다양한 형식의 데이터베이스가 존재하게 됩니다.
결론
결론적으로 서버 개발에서 그래도 가장 많이 하는 일은, “새로운 정보”와 “기존의 정보”를 가지고 “정해진 로직”을 수행하는 일
시험 난이도는 이번주 과제를 마쳤더라면 누구나 할 수 있을정도로 쉬웠지만, 하면서 예기치않은 오류를 봐서 당황 ㅎㅎ
이번 글 마지막에 처음 봤던 오류 메시지 + 시도했던 방법들도 같이 정리해보려 한다.
+ 같이 오류를 해결해주신 모든 분들 ( 은솔님, 소영님, 미경님, 윤재님, ...) 감사합니다 !!!
+ 그리고 코드 전체 주석을 달고 하나씩 풀어보면서 해결해 보라고 팁을 주신 지성님도 감사합니다 !!!
시험 과제
작성한 코드
제출해야하는 과제는 조회기능인 GET이지만, 테스트를 위해 POST부분 까지 같이 작성했다.
1. Controller
2. DTO
RequestDto
ResponseDto
3. Service
POST
GET
4. Entity
5. Repository
h2 - console
구현해야 하는 대로 잘 작성이 되는 것을 볼 수 있다.
트러블 슈팅 1 - 인텔리제이 run 실행 버튼이 활성화 되지 않았던 문제
1. 발생한 문제 ( 아래는 콘솔창에 떴던 에러 메세지이다.)
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController' defined in file [/Users/chaleejin/Desktop/hanghaetest/out/production/classes/com/sparta/hanghaetest/controller/MemberController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberService' defined in file [/Users/chaleejin/Desktop/hanghaetest/out/production/classes/com/sparta/hanghaetest/service/MemberService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'memberRepository' defined in com.sparta.hanghaetest.repository.MemberRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc(); Reason: Failed to create query for method public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc()! No property 'modifiedAt' found for type 'Member'; nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc()! No property 'modifiedAt' found for type 'Member'
너무 길어서 앞부분만 보고 자세히 보지 않았는데, 꼼꼼히 봤더라면 해결되었을 문제였다.
아래는 위의 에러 내용이다. 빨간색 부분으로 에러가 발생했던 주요 이유를 표시해보았다.
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberController' defined in file [/Users/chaleejin/Desktop/hanghaetest/out/production/classes/com/sparta/hanghaetest/controller/MemberController.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'memberService' defined in file [/Users/chaleejin/Desktop/hanghaetest/out/production/classes/com/sparta/hanghaetest/service/MemberService.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'memberRepository' defined in com.sparta.hanghaetest.repository.MemberRepository defined in @EnableJpaRepositories declared on JpaRepositoriesRegistrar.EnableJpaRepositoriesConfiguration: Invocation of init method failed; nested exception is org.springframework.data.repository.query.QueryCreationException: Could not create query for public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc(); Reason: Failed to create query for method public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc()! No property 'modifiedAt' found for type 'Member';nested exception is java.lang.IllegalArgumentException: Failed to create query for method public abstract java.util.List com.sparta.hanghaetest.repository.MemberRepository.findAllByOrderByModifiedAtDesc()! No property 'modifiedAt' found for type 'Member'
2. 시도한 방법
2-1. Preferences - Build - Build and run using 설정 Gradle 에서 IntelliJ IDEA로 바꿔주기
2-2. 해당 파일이 들어있는 디렉토리(파일)에서 물리적으로 out폴더를 삭제하고, 인텔리제이에서 Build - Rebuild 해주기
2-3. 인텔리제이 파일 - Invaildate Cashes - 모든 사항 체크 후 - 캐쉬삭제 해주기
2-4 인텔리제이에서 파일을 열 때, build.gradle 파일로 열어주기.
2-5 Application 파일을 다른 디렉토리로 이동했다가 다시 원위치 시켜보기
위 방법 모두 통하지 않았다. 왜냐, 근본 적인 문제가 아니었기 때문 ^^
나는 단지 실행버튼이 활성화 되지 않는 것에만 집중해서 구글링을 했고, 다른 분들도 그 부분으로 도와주셨는데, 에러 메세지의 맨 끝 부분에서 확인할 수 있듯이 사실은 상속에 관한 문제였다.
3. 해결한 방법
알고보니 Entity Member 클래스에서 Timestamped 클래스 상속을 해주지 않아서 발생했던 문제였다......
바부 ...... ㅎㅎㅎㅎ 도움을 주신 모든 분들에게 다시 한번 감사의 말씀을 전합니다 ㅎㅎㅎ !!
트러블 슈팅 2 - Web server failed to start. Port 8080 was already in use.!
Java 진영에서 ORM(Object-Relational Mapping) 기술 표준으로 사용하는 인터페이스 모음
자바 어플리케이션에서 관계형 데이터베이스를 사용하는 방식을 정의한 인터페이스
인터페이스 이기 때문에 Hibernate, OpenJPA 등이 JPA를 구현함
참고로, JPA는 수정 메소드를 제공하지 않는다. 하지만 당연히 수정은 필요하기 때문에 JPA는 데이터 수정시, 매핑된 객체(테이블 데이터)를 조회해서 값을 변경 후 커밋하면 DB 서버에 UPDATE 문을 전송하여 UPDATE를 실행한다.
추가적으로 알아둬야 할 것은, 스프링에서 흔히 사용하는 것으로 알고있는 JPA는, JPA를 이용하는 spring-data-jpa 프레임워크이지 JPA는 아니다.
🔐 Controller, Service, Repository 가 무엇인가요?
< 간단 정리 >
컨트롤러 : @Controller (프레젠테이션 레이어, 웹 요청과 응답을 처리함)
로직 처리 : @Service (서비스 레이어, 내부에서 자바 로직을 처리함)
외부I/O 처리 : @Repository (퍼시스턴스 레이어, DB나 파일같은 외부 I/O 작업을 처리함)
Controller
Spring Framework의 Controller는 사용자가 화면(View)단에서 입력이나 어떤 이벤트를 했을 경우, 그 이벤트에 맞는 화면(View)이나 비지니스 로직(Model)을 실행할 수 있도록 업데이트 해주는 역할을 한다. 즉, Model과 View를 연결해주는 다리 역할이라고 할 수 있다.
서버에서 기능별 URL이라는 API를 개설해 놓았고, 클라이언트는 필요한 정보를 얻기 위해 적절한 API에 요청한다. Controller는 이런 창구 역할을 하는 API들을 모아놓은 클래스라고 할 수 있다.
Front-end에서 들어오는 클라이언트 측의 요청이 가장 먼저 서버 측과 맞닿는 부분
Client의 요청을 받았을 때 그 요청에 대해 실제 업무를 수행하는 Service를 호출
클라이언트가 보낸 데이터가 있다면 Service를 호출할 때 전달하기 쉽게 데이터의 가공
모델의 업무 수행이 완료되면 그 결과를 바탕으로 화면을 구성하도록 View에 전달
@Controller 어노테이션을 사용하여 만들어진 컨트롤러 클래스에 라우팅(Routing)할 수 있도록 요청 URL에 대해 해당하는 메소드를 매핑해줄 수 있도록 하기 위해 @RequestMapping 어노테이션을 사용한다.
Service
Service : Controller의 요청을 받아 알맞은 정보를 가공 Controller에게 재전달한다.
Service는 위에서 언급했듯이 Repository에서 얻어온 정보를 바탕으로 자바 문법을 이용하여 가공 후 다시 Controller에게 정보를 보내는 곳이다.
클라이언트 즉 controller 쪽에서 바로 데이터베이스에 접근하여 정보를 얻고 가공해서 가져가는 것은 위험하다.
정보를 직접 CRUD하고 가공하는 과정에서 테이블에 저장된 원본의 정보가 손상될 우려가 크기 때문이다.
따라서 정보 변동의 위험이 큰 로직은 Service에서 진행한다.
추가로 이때 원본의 데이터를 사용하는 것이 아니라 데이터베이스에서 추출한 정보의 복사본인 DTO를 만들어서 로직을 조작한다.
Repository
Repository는 직역해도 '저장소'로 데이터베이스와 깊은 연관이 있음을 알 수 있다.
데이터단에 직접 매칭되는 Entity라는 것이 있는데, 이 Entity를 통해 데이터 테이블이 생성이 되면, 받아온 정보를 데이터베이스(ex. MySQL, mariaDB)에 저장하고 조회하는 기능을 수행한다.
Repository : Entity에 의해 생성된 DB에 접근하는 메서드를 사용하기위한 interface이다.
JPA를 상속받음으로써 기본적인 CRUD의 동작(함수 사용)이 가능해진다.
JpaRepository<대상 엔티티, Entity에 접근할 객체의 Type>
🔐 restAPI의 put 과 patch 는 어떤 차이점이 있을까요? 어떤 경우에 사용하면 좋을까요?
PUT
자원를 변경할 때에 사용하는 방식이다. CRUD에서 U. Update에 해당하며, DB에서도 Update에 해당한다.
참고로 PUT은 자원을 모두 대체(replace)하는 메소드이다. 요청한 URL 아래에 해당 자원이 존재하지 않으면 POST와 마찬가지로 새로운 자원으로써 저장한다. 만약 요청한 URL 아래에 해당 자원이 존재하면 기존에 존재하던 자원을 새롭게 요청으로 들어간 정보로 자원 전체를 대체한다. 만약 PUT을 사용하여 일부만 변경하고자 하여 자원의 전체 상태를 완전하지 못한 상태로 전송한다면 일부가 null값으로 변경될 수 있다.
PATCH
PATCH 역시 데이터를 변경할 때 사용한다. 하지만 PUT과 PATCH는 서로 대체제 관계가 아니며, 다른 정의와 규약을 가지고 있다. PATCH 요청은 자원에 대한 부분적인 수정을 적용하기 위한 메소드이다. 따라서 필요한 정보에 대해서만 요청할 수 있다.
🔑 스프링 Bean이란?
스프링의 특징에는 제어의 역전(IoC / Invention Of Control)이 있다.
제어의 역전이란, 간단히 말해서 객체의 생성 및 제어권을 사용자가 아닌 스프링에게 맡기는 것이다. 객체에 IoC가 적용된 경우에는 이러한 객체의 생성과 사용자의 제어권을 스프링에게 넘기게 되며 스프링의 DI(Dependency Injection) Container에 의하여 관리 당하는 자바 객체를 사용자는 사용하게 된다. 이 객체를 '빈(bean)'이라 한다.
🔑 RESTful 하다?
REST의 정의
Representational State Transfer의 약자자원의 이름(자원의 표현)으로 구분하여 자원의 상태(정보)를 주고 받는 모든 것을 의미
1. HTTP URL을 통해 자원(Resource)를 명시하고
2. HTTP Method(POST, GET, PUT, DELETE)를 통해
3. 해당 자원에 대한 'CRUD Operation'을 적용하는 것을 의미한다.
REST의 구성 요소
1.자원(Resource) : HTTP URL
모든 자원에 고유한 ID가 존재하고, 이 자원은 서버에 존재한다.
자원을 구별하는 ID는 '/groups/:group_id'와 같은 HTTP URL이다.
Client는 URL을 이용해서 자원을 지정하고 해당 자원의 상태(정보)에 대한 조작을 서버에 요청한다.
2.행위(Verb) : HTTP Method
HTTP 프로토콜의 Method를 사용한다.
HTTP 프로토콜은 GET, POST, PUT, DELETE와 같은 메서드를 제공한다.
3.표현(Representations) : HTTP Message Pay Load
클라이언트가 자원의 상태(정보)에 대한 조작을 요청하면 서버는 이에 적절한 응답(Representation)을 보낸다.
REST에서 하나의 자원은 JSON, XML, TEXT, RSS등 여러 형태의 Representation으로 나타내어 질 수 있다.
JSON 혹은 XML을 통해 데이터를 주고 받는 것이 일반적이다.
RESTful 이란 ?
RESTful은 일반적으로 REST라는 아키텍처를 구현하는 웹 서비스를 나타내기 위해 사용되는 용어이다.즉, 'REST API'를 제공하는 웹 서비스를 'RESTful'하다고 할 수 있다.
RESTful은 REST를 REST답게 쓰기 위한 방법으로, 누군가가 공식적으로 발표한 것은 아니다.즉, REST 원리를 따르는 시스템은 RESTful이란 용어로 지칭된다.
RESTful 하지 못한 경우
CRUD 기능을 모두 POST로만 처리하는 API
REST API의 설계 규칙을 지키지 못한 경우
REST API 설계 규칙
URL는 동사보다는 명사를, 대문자보다는 소문자를 사용해야 한다.
마지막에 슬래시(/)를 포함하지 않는다.
언더바 대신 하이폰을 사용한다.
파일확장자는 URL에 포함하지 않는다.
행위를 포함하지 않는다.
🔑 의존성이란?
사용하는 방법을 보면 라이브러리 == dependency ? 라는 의문이 생긴다. 라이브러리를 사용하는데 왜 dependency를 추가하는 것이라고 할까. 클래스 A가 다른 클래스 또는 인터페이스 B를 사용할 때 A가 B에 의존하는 관계가 된다. B가 없으면 작동할 수 없는 A를 dependant라고 하며, 의존의 대상이 되는 B를 dependency라고 한다. 또한 의존대상 B가 변하면 그것이 A에 영향을 미친다.
코드를 짤 때 라이브러러의 기능을 작성한 클래스가 사용하게 되면 라이브러리에 의존하게 되므로 라이브러리는 dependency가 되며, 작성한 클래스는 dependant가 된다.
그래서 dependency와 라이브러리가 같은 것 이라고 할 수 없지만 라이브러리를 사용하는 것이 dependency 즉, 의존성을 늘리게 되는 행동이기 때문에 라이브러리를 사용하는 것을 dependency를 추가한다고 표현하는 것이다.
🔑 @Transactional
Transaction ?
데이터베이스의 상태를 변경하는 작업 또는 한번에 수행되어야 하는 연산들을 의미한다.
begin, commit 을 자동으로 수행해준다.
예외 발생 시 rollback 처리를 자동으로 수행해준다.
Transaction 4 가지 성실
원자성(Atomicity) : 한 트랜잭션 내에서 실행한 작업들은 하나의 단위로 처리한다. 즉, 모두 성공 또는 모두 실패.
일관성(Consistency) : 트랜잭션은 일관성 있는 데이타베이스 상태를 유지한다. (data integrity 만족 등.)
격리성(Isolation) : 동시에 실행되는 트랜잭션들이 서로 영향을 미치지 않도록 격리해야한다.
영속성(Durability) : 트랜잭션을 성공적으로 마치면 결과가 항상 저장되어야 한다.
Transaction 처리 방법
스프링에서는 간단하게 어노테이션 방식으로 @Transactional을 메소드, 클래스, 인터페이스 위에 추가하여 사용하는 방식이 일반적이다. 이 방식을 선언적 트랜잭션이라 부르며, 적용된 범위에서는 트랜잭션 기능이 포함된 프록시 객체가 생성되어 자동으로 commit 혹은 rollback을 진행해준다.
🔑 DAO, DTO, VO 란?
< 간단 정리>
DAO : 이름 그대로 DB에 접근하기 위한 객체이다. 서비스와 DB를 연결하기 위한 중간 다리의 역할을 한다. Mybatis를 기준으로 예시를 작성한다.
DTO : 말 그대로 '데이터 전송 객체'이다. 뷰에서 컨트롤러로 넘어오는 데이터를 담거나, 컨트롤러에서 서비스로 넘기는 데이터를 담거나 할 때 사용할 수 있다. 로직을 가지지 않고, 데이터 객체에 대한 정보만 담고 있다.
VO : VO는 값 그 자체를 나태는 객체이다. DTO와 반대로 로직을 포함할 수 있으며, VO의 경우 특정 값 자체를 표현하기 때문에 불변성의 보장을 위해 생성자를 사용하여야 한다. 서로 다른 이름을 갖는 VO 인스턴스라도 모든 속성 값이 같다면 두 인스턴스는 같은 객체인 것이 핵심이다.
DAO
DAO(Data Access Object)는 데이터베이스의 data에 접근하기 위한 객체.DataBase에 접근 하기 위한 로직 & 비지니스 로직을 분리하기 위해 사용한다.
DAO의 경우는 DB와 연결할 Connection 까지 설정되어 있는 경우가 많다.
그래서 현재 많이 쓰이는 Mybatis 등을 사용할 경우 커넥션풀까지 제공되고 있기 때문에 DAO를 별도로 만드는 경우는 드물다.
DAO는 오버헤드를 줄이기 위해 사용된다. 오직 1개의 커넥션만을 이용하여 다수의 사용자들의 생성, 조회, 수정 , 삭제 등의 DB I/O역할을 모두 수행하기 때문에 애플리케이션의 안정된 운용을 보장해 준다.
DTO(Data Transfer Object)는계층 간 데이터 교환을 하기 위해 사용하는 객체로, DTO는 로직을 가지지 않는 순수한 데이터 객체(getter & setter 만 가진 클래스)이다.
여기서 getter/setter 이외에 다른 로직이 필요 없는 이유를 좀 더 자세히 살펴보자면, 만약 DTO가 데이터 전달 만을 위한 객체라고 한다면 완전히 데이터 '전달' 용도로만 사용하기 때문에 getter/setter로직만이 필요하지 다른 로직이 필요하지 않은 것이다.
유저가 입력한 데이터를 DB에 넣는 과정을 보면,
유저가 자신의 브라우저에서 데이터를 입력하여 form에 있는 데이터를 DTO에 넣어서 전송한다.
해당 DTO를 받은 서버가 DAO를 이용하여 데이터베이스로 데이터를 집어넣는다.
VO
VO(Value Object) 값 오브젝트로써 값을 위해 쓰인다. (VO는 값 그 자체를 나태는 객체이다.)
DTO와 반대로 로직을 포함할 수 있으며, VO의 경우 특정 값 자체를 표현하기 때문에 불변성의 보장을 위해 생성자를 사용하여야 한다.
read-Only 특징(사용하는 도중에 변경 불가능하며 오직 읽기만 가능)을 가진다.
DTO와 유사하지만 DTO는 setter를 가지고 있어 값이 변할 수 있다.
VO는 서로 다른 이름을 갖는 VO 인스턴스라도 모든 속성 값이 같다면 두 인스턴스는 같은 객체인 것이 핵심이다.
반면, DTO는 서로 다른 이름을 갖는 두 DTO인스턴스가 속성 값이 같더라도 두 인스턴스는 다른 객체라는 점에서 차이가 있다.
이번 글은 과제를 하면서 작성한 코드를 이해하고자 내멋대로 주석을 달아본 글이기 때문에, 정답이 아닐 수 있으며 ! 정신 건강을 헤칠수도 있습니다 ^__^
1. HanghaememoApplication
@EnableJpaAuditing
스프링 부트의 Entry 포인트인 실행 클래스에 @EnableJpaAuditing 어노테이션을 적용하여 JPA Auditing을 활성화 해준다.
생성일자와 수정일자를 자동으로 등록할 수 있는 기능 외에도 EnableJpaAuditing 에는 다양한 기능이 있다.
이 중 auditorAwareRef 는 @CreatedBy, @LastModifiedBy 과 함께 생성한 사람, 수정한 사람을 자동으로 저장해준다.
@SpringBootApplication
스프링 부트의 가장 기본적인 설정을 선언해 주는 어노테이션. 해당 어노테이션을 보면 아래와 같은 어노테이션이 다시 선언되어 있다.
@Configuration, @EnableAutoConfiguration, @ComponentScan 3가지를 하나의 애노테이션으로 합친 것이다.
@ComponentScan은 @component 어노테이션 및 @Service, @Repository, @Controller 등의 어노테이션을 스캔하여 Bean으로 등록해주는 어노테이션이다.
@EnableAutoConfiguration은 사전에 정의한 라이브러리들을 Bean으로 등록해 주는 어노테이션이다. 사전에 정의한 라이브러리들 모두가 등록되는 것은 아니고 특정 Condition(조건)이 만족될 경우에 Bean으로 등록한다.
2. Entity ( Memo, Timestamped)
entity 에서 실제 DB의 테이블과 매칭될 객체들을 명시해준다.
Entity/Memo
@Entity 어노테이션으로 명시한 부분DB 테이블에 들어갈 항목들Service에서 사용할 생성자를 명시해준다.
Entity/Timestamped
3. Controller
Client와 Service 를 연결하는 역할이라고 할 수 있다. 이 과정에서 반환값을 Dto에 담았다. (Delete 부분 제외)
@RestController는 @Controller에 @ResponseBody가 추가된 것. 당연하게도 RestController의 주용도는 Json 형태로 객체 데이터를 반환하는 것
@RequiredArgsConstructor : 이 어노테이션은 초기화 되지않은 final 필드나, @NonNull 이 붙은 필드에 대해 생성자를 생성해 준다. 주로 의존성 주입(Dependency Injection) 편의성을 위해서 사용되곤 한다.
내가 이해한 바는, 컨트롤러는 클라이언트와 서비스를 연결해 주는 곳이라는 것.
필요한 작업 (메소드)는 서비스클래스에서 처리가 되기 때문에 컨트롤러에서 클라이언트로 부터 받은 requestDto를 서비스에 전달하면 서비스클래스의 메소드가 필요한 작업을 처리하고, 다시 컨트롤러를 통해 클라이언트로 responseDto 형태의 값을 전달한다고 이해하면 되려나 ( ? )
4. Dto ( MemoRequestDto, MemoResponseDto )
Dto는 약간 포장지에 감싸져있는 데이터인 것 같다.
클라이언트에서 받은 정보를 바로 DB에 저장하고 그걸 다시 클라이언트 쪽으로 전달하게 된다면, 보안상 위험한 부분이 있을 수 있고 나중에 SQL의 join 기능을 사용할 때 문제가 될 수도 있기 때문에, 필요한 데이터가 안전하게 포장되어 있는 것 이라고 이해했다. 아닐 수도 ^_^
MemoRequestDto
클라이언트에서 입력을 받아 저장되는 데이터들
MemoResponseDto
클라이언트 쪽에서 요청이 들어왔을 때 꺼내서 보여지는 데이터들.
password는 빠진 것을 볼 수 있다.
5. Service
Service는 컨트롤러에서 받아온 데이터 정보를 잘 가공해 DB와 연결된 Repository에 전달 하기도하고, 다시 DB에서 Repository로 보내준 데이터를 가공하여 컨트롤러쪽으로 보내는 역할을 하는 곳이다. 비지니스 로직을 담당하는 곳이기 때문에 메소드들이 모여있는 곳이기도 하다.
@Service : 해당 클래스가 비즈니스 로직을 담은 Service 클래스임을 명시합니다. @Component 어노테이션을 사용해도 상관 없지만 @Sevice 어노테이션에 @Component 어노테이션의 기능이 포함되어 있고 @Service를 사용함으로써 해당 클래스가 Service의 역할을 하는 것을 명확하게 알 수 있습니다.
@RequiredArgsConstructor : 이 어노테이션은 초기화 되지않은 final 필드나, @NonNull 이 붙은 필드에 대해 생성자를 생성해 줍니다. 주로 의존성 주입(Dependency Injection) 편의성을 위해서 사용되곤 합니다.
게시글 POST 메소드 부분
@Transactional이 붙은 메서드는 메서드가 포함하고 있는 작업 중에 하나라도 실패할 경우 전체 작업을 취소
데이터베이스를 다룰 때 트랜잭션을 적용하면 데이터 추가, 갱신, 삭제 등으로 이루어진 작업을 처리하던 중 오류가 발생했을 때모든 작업들을 원상태로 되돌릴 수 있다. 이 기능을 하는 어노테이션이 바로 @Transactional
게시글 전체조회 GET 메소드 부분
게시글 선택 조회 GET 메소드 부분
게시글 수정 PUT 메소드 부분
게시글 삭제 DELETE 메소드 부분
6. Repository
Repository는 Entity에 의해 생성된 DB에 접근하는 메서드를 사용하기위한 interface를 말한다. 저장소와 직접적으로 연결되어 있어 Service에서 필요한 데이터를 DB에서 Entity 클래스로 받아와 다시 Dto로 전달하는 곳이다.
아직 쿼리형식은 공부하지 않았는데, 강의에서 나온대로 쿼리형식으로 지정이 되어있다.
인터페이스란 무엇일까 ?
인터페이스란 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다. 컴퓨팅에서 컴퓨터 시스템끼리 정보를 교환하는 공유 경계이다.
일단 이번 과제에 작성된 코드를 쭉 한번 살펴봤다.
아직 모르는 개념도 많고 어노테이션도 많고 그 외 이해가 되지 않는 부분이 더 많지만, 대략적인 흐름을 알 수 있었던 것 같다.
개발자마다 순서가 조금씩 다르긴 한데, 보통 entity를 먼저 만들고, 그다음 controller를 만들고, 그다음 Repository, 다음 Service와 Dto를 만드는 것 같다. 기술매니저님이 서비스의 규모가 커질 수록 Dto의 수가 늘어나는 것은 당연한 일이기 때문에, Dto를 만드는 것을 불편해 하지 말라고 하셨다. 이번엔 간단한 프로젝트라 두개의 Dto로 끝나긴 했지만, 앞으로 실전 프로젝트를 위해선 원하는 형식의 Dto를 설계하는 법도 공부해야 할 것 같다.