yu-jin-song님의 게시판 구현 게시물을 참고하였습니다.
프로젝트명: noticeBoard
의존관계 설정
그리고 Preferences 가서 gradle 검색해서 둘 다 인텔리제이로 바꿔주고 annotation 검색해서 맨 위 체크박스 체크해주기
📁 파일구조
: 행위와 데이터를 둘 다 아우르는 도메인 개념 모델
즉, 데이터는 어떤 형식으로 저장되며 데이터 CRUD는 어떻게 구상하는지에 대한 것
도메인 클래스에서 쿼리가 담는 xml과 쿼리의 결과를 담는 클레스의 역할을 모두 수행
: 실제 DB의 테이블과 매칭될 클래스
(Entity class)
JPA를 사용할 경우 이 엔티티 클래스의 수정을 통해 DB 데이터에 작업한다.
Entity 클래스에서는
setter
메소드 대신@Builder
를 통해 제공되는 빌더 클래스를 사용하기생성자와 빌더 클래스의 역할은 생성 시점에 값을 싣는 것이다.
생성자와 빌더 클래스의 차이로는 코드 실행 전 값을 싣을 필드를 명확히 지정하는 것이 불가능하지만 빌더 클래스는 코드 실행 전 값을 싣을 필드를 명확히 인지 할 수 있다.그리고 setter를 사용하면 값이 쉽게 변경되어 객체의 일관성을 보장할 수 없고 그 의도를 파악하기 힘드므로 대신 Builder를 사용하기
추후 수정
@Builder
: 해당 클래스의 빌더 패턴 클래스 생성
생성자 상단에 선언시 생성자에 포함된 필드만 빌더에 포함된다.
: JPA에서의 DB Layer 접근자
인터페이스 생성 후 JpaRepository<Entity 클래스, PK 타입>
을 extends로 상속받으면 기본적인 CRUD 메소드가 자동 생성된다.
@Repository
를 추가할 필요가 없다.
추후 수정
API를 생성하기 위해서는 Dto
(Request 데이터 수신), Controller
(API 요청 수신), Service
(트랜잭션, 도메인 기능 간 순서 보장) 클래스가 필요하다.
⚠️ Service
클래스는 비즈니스 로직을 처리하지 않는다.
트랜잭션, 도메인 간 순서 보장의 역할만을 수행한다.
웹 어플리케이션 최상단로 외부 요청을 처리, 올바른 응답을 반환하고, 다른 계층에서 발생한 예외도 처리한다.
인증을 관리하고 권한 없는 사용자의 인가를 거부하는 역할을 수행하며 컨트롤러, JSP와 같은 뷰 템플릿 영역이라고 생각하면 된다.
트랜잭션에 대한 경계 역할을 하며 어플리케이션과 인프라 서비스 모두를 포함한다.
어플리케이션 서비스는 서비스 계층의 공개 API를 공급하며 트랜잭션의 경계 역할과 응답을 책임진다.
Controller와 DAO의 중간 영역에서 많이 사용되며 @Transactional
, @Service
에 사용되는 영역이라고 생각하면 된다.
가장 낮은 계층으로 데이터 스토리지 계층과 통신하는 역할을 수행한다.
데이터베이스와 같이 데이터 저장소에 접근하는 영역이다. (Ex. DAO)
: Data Transfer Object
단순히 데이터를 저장하는 컨테이너로 서로 다른 프로세스와 어플리케이션 계층 간 데이터를 전달하는데 사용된다.
Domain Service: 작업을 제공하는 상태 비저장 클래스
엔티티로 전체 라이프 사이클 동안 변경되지 않는 개체이다.
Value Object로 속성이나 사물을 설명한다.
즉, Web Layer는 데이터 전송 객체만 처리해야 하고, Service Layer는 데이터 전송 객체를 메소드 매개 변수로 사용해 도메인 모델 객체를 처리할 수 있어야 하고, Repository Layer는 엔티티를 메소드 매개변수로 가져올 수 있고 엔티티를 반환한다.
추후 수정
Dto 클래스를 보면 Entity 클래스와 거의 유사하다.
Entity 클래스는 데이터베이스와 맞닿은 핵심 클래스이며 이를 기준으로 테이블이 생성/스키마 변경이 일어나고 수많은 클래스나 비즈니스 로직들이 동작한다.
이로써 여러 클래스에 영향이 미친다.
사소한 기능 변경은 빈번한데 이를 위해 Entity 클래스를 변경하는 것은 불필요한 큰 공사를 필요로 한다.
반면 Dto 클래스는 view를 위한 클래스로 자주 변경되어도 DB 자체에 영향을 미치지 않기 때문에 사용된다.
그러므로 Entity 클래스와 Controller에서 사용할 Dto 클래스는 꼭 분리하여 사용해야 한다.
추후 수정
추후 수정
@Transactional(readOnly = true) public List<BoardListResponseDto> searchAllDesc() { return boardRepository.findAllByOrderByIdDesc() .stream() .map(BoardListResponseDto::new) .collect(Collectors.toList()); // return boardRepository.findAllDesc().stream() // .map(BoardListResponseDto::new) // .collect(Collectors.toList()); }
boardRepository.findAllByOrderByIdDesc().stream()
: boardRepository 결과로 넘어온 Board의 stream을
.map(BoardListResponseDto::new)
: map을 통해 BoardListResponseDto로 변환해
.collect(Collectors.toList());
: List로 반환
JpaRepository에서 delete 메소드를 기본으로 지원함
추후 수정