Conversation
| @GetMapping | ||
| public String list(Model model) { | ||
| model.addAttribute("posts", postService.getAllPosts()); | ||
| return "list"; | ||
| } |
There was a problem hiding this comment.
SSR 방식을 사용하셨네요! 저도 서버 단에서 view까지 다룰 수 있다는 점에서 SSR을 선호합니다. CSR방식과 SSR방식의 장단점이 무엇일까요?
There was a problem hiding this comment.
SSR 방식
사용자가 웹페이지를 요청했을 때,
서버에 필요한 데이터와 HTML을 모두 합쳐서 완성된 페이지를 만들어 서용자게에 제공
pros
- 빠른 초기 로딩 속도
완성된 형태의 페이지를 빠르게 받기 가능 - 검색 엔진 최적화
검색 엔진이 HTML 쉽게 분석하고 파악 가능
cons
- 서버 부하 증가
서버가 일일이 페이지를 민들어야 함 - 페이지 이동 시 blinking
페이지 이동 때마다 전체 페이지를 서버로부터 다시 받아오기 때문에 화면이 깜빡일 수 있음
CSR 방식
사용자가 웹페이지를 요청했을 때,
서버는 아주 기본적인 HTML 뼈대와 javascript 파일만 보내줌.
사용자의 웹 브라우저는 그 javascript를 실행해서 데이터를 서버에 다시 요청하고 데이터를 받아 동적으로 페이지를 완성
pros
- 초기 로딩 후 빠른 인터렉션
한 번 페이지 받아오면 부분적 업데이트 - 서버 부하 감소
서버는 데이터 제공하는 역할에만 집중, 화면을 그리는 일은 브라우저가 담당
cons
- 느린 초기 로딩 속도
처음에 javascript 파일과 데이터를 모두 다운로드 - 검색 엔진 최적화의 어려움
초기에 내용이 거의 없는 HTML을 받아 검색 엔진이 분석하고 파악하기에 어려움
Code Review SSR
-
postService.getAllPosts()
서버에서 미리 모든 게시물 데이터를 가져와 -
model.addAttribute(...)
이 데이터를 list라는 이름의 View(HTML)에 전달
완성된 list 페이지를 사용자에게 반환
|
|
||
| 분리해서 사용하는 이유 | ||
| - Entity 객체의 변경을 피하기 위함 | ||
| - 클라이언트와 통신하는 ResponseDTO나 RequestDTO는 요구사항에 따라 자주 변경 | ||
| - 어떤 요청에서는 특정 값이 추가되거나 없을 수 있어서 분리해서 관리 No newline at end of file |
There was a problem hiding this comment.
내용 정리 좋습니다! entity랑 dto를 분리하는 이유를 한 가지 더 설명드리면, entity는 DB의 table을 정의하는 일종의 스키마 역할을 하게 됩니다. 따라서 table 정의 및 매핑 관련된 설정은 entity에 두고, 외부 입력 값 검증이나 변환은 DTO에서 책임지도록 하는 것이 책임 분리 관점에서 더 적절합니다.
| private String title; | ||
| private String content; | ||
| private String author; | ||
|
|
||
| private LocalDateTime createdAt; | ||
| private LocalDateTime updatedAt; |
There was a problem hiding this comment.
entity에서 DB 스키마 관련 제약조건을 추가해서 더 안전하게 구성할 수 있습니다!
null 값이 들어가면 안 되는 속성에 @Column(nullable = false)을 추가하면 의도치 않게 DB에 null값이 들어가는 것을 원천적으로 차단할 수 있습니다.
// e.g.
@Column(nullable = false, length = 255)
private String title;| @@ -0,0 +1,22 @@ | |||
| 데이터베이스와 직접적으로 맞닿는 핵심적인 클래스 | |||
| - entity를 기준으로 테이블 생성 | |||
| - Builder 패턴을 사용해서 필요한 값만 넣음 | |||
There was a problem hiding this comment.
Builder 패턴의 경우 호불호가 갈리는 편입니다. Builder를 쓰면 선택적으로 필드를 구성할 수 있다는 장점이 있지만, 컴파일 때 필수 필드에 모두 유효한 값이 들어갔는지 체크하기 어렵다는 단점도 있습니다. 이 점 고려하셔서 사용하시면 될 것 같습니다!
| @Transactional(readOnly = true) | ||
| public class PostService { | ||
| private final PostRepository postRepository; | ||
|
|
||
| // 생성자 | ||
| public PostService(PostRepository postRepository) { | ||
| this.postRepository = postRepository; | ||
| } | ||
|
|
||
| public List<PostEntity> getAllPosts() { | ||
| return postRepository.findAll(); | ||
| } | ||
|
|
||
| public PostEntity getPost(Long id) { | ||
| return postRepository.findById(id).orElseThrow(); | ||
| } | ||
|
|
||
| @Transactional | ||
| public PostEntity createPost(PostEntity postEntity) { | ||
| return postRepository.save(postEntity); | ||
| } |
There was a problem hiding this comment.
@Transactional(readOnly = true), @Transactional 분리해서 잘 적용해주셨네요!
| save | ||
| - 새 엔터티 저장 | ||
| - id가 없으면 persist, 있으면 merge |
There was a problem hiding this comment.
오.. 혹시 영속성 계층, 1차 캐시 등 JPA 관련해서 따로 공부하신 적이 있으신가요?
There was a problem hiding this comment.
과제 하면서 사용한 레퍼런스를 통해 해당 기능을 알게 됐습니다. 스프링부트에 대한 지식이 아직 부족해서 더 공부해보겠습니다!
* Update README.md * feat(comment) : 댓글 API 개발 완료 * chore(gradle) : lombok,h2 의존성 추가 * chore(gradle) : JPA 의존성 추가 * feat(entity) : 게시글 엔티티 설계 * chore(gradle) : JPA -> JDBC 의존성 추가 및 삭제 * fix(entity) : JPA 어노테이션 제거 * chore(entity): 엔티티 좋아요 수 필드명 수정 * feat(repo) : JDBC Template를 통해서 CRUD 구현 * feat(service) : 서비스 계층 개발 - 기존 repo가 findById 시에 int를 인자로 받아 Long으로 수정 * style(entity) : 가독성 향상을 위한 띄어쓰기 * feat(controller) : CRUD API 설계 완료 * feat(h2): h2 설정, 스키마 sql로 작성 - h2 url, 사용자 작성 - JPA와 다르게 JDBC는 직접 DDL을 작성 * style(sql) : 들여쓰기 * feat(exception) : 사용자 정의 예외 추가, * feat(Post) : 게시판 작성 로직 생성, DTO 및 API 정의 * feat(Get) : 게시물 단일 조회, 모든 게시글 조회 로직 생성, DTO 및 API 정의 * feat(Get) : 게시물 수정 로직 생성, DTO 및 API 정의 * feat(update) : 게시물 수정 로직 생성, DTO 및 API 정의 * chore(import) : 의존성 추가 * fix(save) : SQL 오류 수정 및 수정 시간 오류 해결 * chore: 카멜케이스 적용 * chore : 카멜 케이스 적용 * fix(JPA) : JDBC에서 JPA로 패러다임 변경 - jpa 의존성 추가 - SQL 로 처리하던 로직을 jpa를 통해 처리 * feat: 댓글 엔티티 추가 * feat: 엔티티 연관관계 매핑 - 게시글 : 댓글 일대다 - 대댓글(댓글에 댓글 추가) 일대다 * feat: 엔티티, 컨트롤러, 서비스, 리포지터리 생성 * feat(dto) : 댓글 수정 및 생성용 Dto 와 메소드 개발 * feat(CRUD) : 댓글 CRUD 로직 개발 * feat(comment) : 댓글 생성 API 개발 완료 - Dto 엔티티 변환 로직을 통해서 댓글에 post 값 할당 * feat(comment) : 댓글 조회, 수정, 삭제 구현 - 조회시에는 연관된 게시물에 댓글을 조회하도록 설정 - 수정, 삭제 URL은 조금더 고민해보기 * feat(reply) : 대댓글 작성 로직 및 API 개발 * fix(comment) : 댓글 조회 API 오류 해결 - 댓글 조회시, 같은 게시글에 달린 대댓글이 중복으로 조회되는 문제 해결 - 댓글 중 parent(부모댓글) 이 null 값인 것들만 조회하도록 수정 * chore : 사용하지 않는 병수 및 의존성 제거 * fix(post) : 게시글 조회 API 오류 해결 - 게시글도 댓글과 마찬가지로 조회시, 같은 게시글에 달린 대댓글이 중복으로 조회되는 문제 해결 - 댓글 중 parent(부모댓글) 이 null 값인 것들만 조회하는 메소드를 게시글 service에도 적용 * chore: 사용되지 않는 메소드 리턴 제거 * chore : validation 의존성 추가 * feat : Dto 에 validation 추가 * feat: 댓글 API,유효성 검증 실패시 예외처리 추가 - validation 실패시 발생하는 MethodArgumentNotValidException은 try-catch로는 잡히지 않아, 전역 핸들러 추가 * chore: 미사용 메소드 삭제 * chore: import 정리 * chore: 경고 제거 --------- Co-authored-by: tomchccom <dreamkms2014@gmail.com> * feat(test): 게시글 단위, 통합 테스트 구현 (#2) * chore(gradle) : lombok,h2 의존성 추가 * chore(gradle) : JPA 의존성 추가 * feat(entity) : 게시글 엔티티 설계 * chore(gradle) : JPA -> JDBC 의존성 추가 및 삭제 * fix(entity) : JPA 어노테이션 제거 * chore(entity): 엔티티 좋아요 수 필드명 수정 * feat(repo) : JDBC Template를 통해서 CRUD 구현 * feat(service) : 서비스 계층 개발 - 기존 repo가 findById 시에 int를 인자로 받아 Long으로 수정 * style(entity) : 가독성 향상을 위한 띄어쓰기 * feat(controller) : CRUD API 설계 완료 * feat(h2): h2 설정, 스키마 sql로 작성 - h2 url, 사용자 작성 - JPA와 다르게 JDBC는 직접 DDL을 작성 * style(sql) : 들여쓰기 * feat(exception) : 사용자 정의 예외 추가, * feat(Post) : 게시판 작성 로직 생성, DTO 및 API 정의 * feat(Get) : 게시물 단일 조회, 모든 게시글 조회 로직 생성, DTO 및 API 정의 * feat(Get) : 게시물 수정 로직 생성, DTO 및 API 정의 * feat(update) : 게시물 수정 로직 생성, DTO 및 API 정의 * chore(import) : 의존성 추가 * fix(save) : SQL 오류 수정 및 수정 시간 오류 해결 * chore: 카멜케이스 적용 * chore : 카멜 케이스 적용 * fix(JPA) : JDBC에서 JPA로 패러다임 변경 - jpa 의존성 추가 - SQL 로 처리하던 로직을 jpa를 통해 처리 * feat: 댓글 엔티티 추가 * feat: 엔티티 연관관계 매핑 - 게시글 : 댓글 일대다 - 대댓글(댓글에 댓글 추가) 일대다 * feat: 엔티티, 컨트롤러, 서비스, 리포지터리 생성 * feat(dto) : 댓글 수정 및 생성용 Dto 와 메소드 개발 * feat(CRUD) : 댓글 CRUD 로직 개발 * feat(comment) : 댓글 생성 API 개발 완료 - Dto 엔티티 변환 로직을 통해서 댓글에 post 값 할당 * feat(comment) : 댓글 조회, 수정, 삭제 구현 - 조회시에는 연관된 게시물에 댓글을 조회하도록 설정 - 수정, 삭제 URL은 조금더 고민해보기 * feat(reply) : 대댓글 작성 로직 및 API 개발 * fix(comment) : 댓글 조회 API 오류 해결 - 댓글 조회시, 같은 게시글에 달린 대댓글이 중복으로 조회되는 문제 해결 - 댓글 중 parent(부모댓글) 이 null 값인 것들만 조회하도록 수정 * chore : 사용하지 않는 병수 및 의존성 제거 * fix(post) : 게시글 조회 API 오류 해결 - 게시글도 댓글과 마찬가지로 조회시, 같은 게시글에 달린 대댓글이 중복으로 조회되는 문제 해결 - 댓글 중 parent(부모댓글) 이 null 값인 것들만 조회하는 메소드를 게시글 service에도 적용 * chore: 사용되지 않는 메소드 리턴 제거 * chore : validation 의존성 추가 * feat : Dto 에 validation 추가 * feat: 댓글 API,유효성 검증 실패시 예외처리 추가 - validation 실패시 발생하는 MethodArgumentNotValidException은 try-catch로는 잡히지 않아, 전역 핸들러 추가 * chore: 미사용 메소드 삭제 * chore: import 정리 * chore: 경고 제거 * feat(test) : post 단위, 통합 테스트 구현 --------- Co-authored-by: tomchccom <dreamkms2014@gmail.com> --------- Co-authored-by: tomchccom <dreamkms2014@gmail.com>

과제 1
게시글 CRUD 구현하기