1-9 Mustache, Service, Blog (리팩토링하기)

Blog (리팩토링하기)
홍윤's avatar
Aug 22, 2024
1-9 Mustache, Service, Blog (리팩토링하기)
 
 

1.Mustache 문법

💡
Mustache 문법
  1. {{key}} -> 출력할 때 사용한다. EL표현식과 같다.
2.for문 if문 (연산X) 컬렉션 {{#컬렉션}} {{/컬렉션}} -> 반복문 오브젝트 {{#오브젝트}} {{/오브젝트}} -> 존재하면 혹은 null이면 처리 Boolean {{#Boolean}} {{/Boolean}} -> true 실행 false 실행안함
session -> num=1 {{#model.user.id == sessionUser.id}}
 
3.컬렉션 타입이 단순 자료형이면 . 컬렉션<String> --> {{#컬렉션}} {{.}} {{/컬렉션}}
컬렉션<Board(Object)> --> {{#컬렉션}} {{title}} {{/컬렉션}}

2.Service 설명

💡
  1. Board -> User(FK) Lazy 전략 순수하게 Board Select하면, User는 Select가 안됨!!
  1. OpenInView = true C - S - R (o) (o) (o) (o) (o) (o)
  1. OpenInView = false C - S - R (o) (o) (o) (x) (o) (o)
notion image
 
notion image

3. User(Package 변경 및 수정)

notion image
 

1. UserRequest

1. loginDTO 만들기

@Data public static class loginDTO{ private String username; private String password; }
 

2.joinDTO 만들기

@Data public static class joinDTO{ private String username; private String password; private String email; //DTO를 -> UserObject로 바꿔준다. public User toEntity(){ return User.builder().username(username).password(password).email(email).build(); }

 

2. UserRepository

loginDTO

@RequiredArgsConstructor // final이 붙은 애들의 생성자를 만들어준다,. @PostMapping("/login") public String login(UserRequest.loginDTO loginDTO) { User sessionUser = userRepository.findByUsernameAndPassword(loginDTO.getUsername(),loginDTO.getPassword()); session.setAttribute("sessionUser", sessionUser); return "redirect:/board"; }
  • login(UserRequest.loginDTO loginDTO: 메소드는 ‘loginDTO’라는 객체를 인자로 받고 객체에는 사용자가 입력한 ‘username’ 과 ‘password’가 들어있다.
 

joinDTO

//회원가입 하고 난 후 @PostMapping("/join") public String join(UserRequest.joinDTO joinDTO) { //insert 하는 모든 것들은 toEntitiy로 하면 된다. userRepository.save(joinDTO.toEntity()); return "redirect:/login-form";
  • ‘joinDTO.toEntity()’는 ‘joinDTO’ 객체를 ‘Entity’ 객체로 변환하고 데이터베이스에 저장될 실제 데이터 구조를 의미한다.
  • userRepository.save(joinDTO.toEntity())’는 변환된 ‘Entity’ 객체를 데이터베이스에 저장한다. 즉 새로운 사용자를 데이터베이스에 추가한다.

 
 

4.Board(Package 변경 및 수정)

notion image

1. BoardController

// subtitle=제목1&postContent=내용1 //board/save 를 붙이 이유는 https 1.0버전으로 하려고 그리고 자바스크립트 등 라이브러리 X ,순순한 스프링 프로그램으로만 만들려고 @PostMapping("/board/save") public String save(BoardRequest.saveDTO saveDTO) { // 스프링 기본전략 = x-www-form-urlencoded 파싱 User sessionUser = (User) session.getAttribute("sessionUser"); // 인증 체크 필요함 if(sessionUser == null) { throw new RuntimeException("로그인이 필요합니다."); } boardRepository.save(saveDTO.toEntity(sessionUser)); return "redirect:/board"; }
  • ‘User sessionUser = (User) session.getAttribute(”sessionUser”)는 현재 로그인한 사용자의 정보를 세션에서 가져온다
  • ‘boardRepository.save(saveDTO.toEntity(sessionUser)) 는 ‘SaveDTO’ 객체를 엔티티로 변환한 후, 현재 로그인한 사용자 정보와 함께 데이터베이스에 게시글을 저장한다.

2. BoardRepository

// insert 하기 @Transactional public void save(Board board) { em.persist(board); }
  • em.persist(board): ‘EntityManager’ 객체(’em’)를 사용하여 ‘board’ 객체를 데이터베이스에 영구 저장(persist)한다. 데이터베이스에서 새로운 레코드를 추가 한 것이다. 메소드는 트랜잭션을 적용하여 ‘board’객체를 데이터베이스에 안전하게 저장하는 기능을 수행합니다.

3. BoardRequest

package shop.mtcoding.blog.board; import lombok.Data; import shop.mtcoding.blog.user.User; public class BoardRequest { @Data public static class saveDTO{ private String title; private String contnet; public Board toEntity(User sessionUser){ return Board.builder(). title(title) .content(contnet) .user(sessionUser) .build(); } } }
  • BoardRequest 클래스는 게시글 저장 요청과 관련된 데이터를 담고 있는 내부 클래스를 포함한다.
  • Board.builder(): 빌더 패턴을 사용하여 ‘board’ 객체를 생성하고, ‘title’, ‘content’, ‘user’ 정보를 이용해 ‘board’객체를 초기화한다.

4. BoardResponse

package shop.mtcoding.blog.board; import lombok.Data; import shop.mtcoding.blog.user.User; public class BoardResponse { //응답 DTO //화면에 필요한 데이터를 만든 것. @Data public static class DtailDTO{ private Integer boardId; private String title; private String content; private boolean isOwner; private Integer userId; private String username; public DtailDTO(Board board, User sessionUser) { this.boardId = board.getId(); this.title = board.getTitle(); this.content = board.getContent(); this.isOwner = false; if(board.getUser().getId() == sessionUser.getId()) { isOwner = true; // 권한 체크 } this.userId = board.getUser().getId(); this.username = board.getUser().getUsername(); } } }
  • DtailDTO(Board board, User sessionUser) 생성자: 이 생성자는 ‘board’객체와 현재 로그인한 사용자 정보(’sessionUser’)를 인자로 받아, DTO 객체를 초기화합니다.’boardId”, ‘title’, ‘content’는 각각 ‘board’객체의 ID, 제목, 내용에서 가져옵니다.
  • ‘isOwner’필드는 현재 로그인한 사용자가 해당 게시글의 작성자인지 여부를 판단합니다. 만약 ‘board’ 객체의 ‘user’ID와 ‘sessionUser의 ID가 같다면, ‘isOwner’를 ‘true’로 설정하여 사용자가 게시글의 작성자임을 표시합니다.
  • ‘userId'와 ‘username’은 게시글 작성자의 정보를 담습니다.
 
 

비즈니스 로직

💡
비즈니스 로직은 애플리케이션이 특정한 비즈니스 문제를 해결하기 위해 수행하는 핵심 작업을 의미합니다. 즉, 비즈니스 로직은 사용자가 기대하는 기능을 구현하는 규칙, 절차, 데이터 처리 방법 등을 정의합니다. 서비스 계층(Service Layer)이 이러한 비즈니스 로직을 담당하며, 컨트롤러(Controller)나 데이터 접근 계층(Repository)과 구분됩니다.

비즈니스 로직의 주요 역할

  1. 도메인 규칙 적용: 비즈니스 로직은 애플리케이션의 도메인(비즈니스 영역)에 대한 규칙을 적용합니다. 예를 들어, 쇼핑몰에서는 "상품 재고가 없으면 구매할 수 없다"는 규칙이 있을 수 있습니다.
  1. 데이터 처리: 비즈니스 로직은 데이터의 생성, 수정, 삭제, 조회를 담당합니다. 여기에는 여러 데이터를 조합하여 계산하거나, 특정 조건에 따라 데이터를 필터링하는 작업 등이 포함됩니다.
  1. 결과 반환: 비즈니스 로직은 최종적으로 결과를 반환합니다. 이 결과는 일반적으로 컨트롤러로 전달되어 사용자가 볼 수 있는 형태로 제공됩니다.
  1. 트랜잭션 관리: 비즈니스 로직에서는 여러 데이터베이스 작업이 원자적으로 처리되도록 트랜잭션 관리를 수행합니다. 즉, 하나의 작업이 실패하면 전체 작업을 롤백하여 데이터의 일관성을 유지합니다.
notion image

비즈니스 로직의 예시

위에서 설명한 BoardService 클래스의 상세보기 메서드는 비즈니스 로직의 좋은 예시입니다.
java코드 복사 public BoardResponse.DtailDTO 상세보기(int id, User sessionUser) { // 게시글을 ID로 조회하고, 해당 게시글이 존재하는지 확인 Board board = boardRepository.findById(id); // 조인(Board - User) 포함, 절대 null 일수 가 없다. // 게시글과 사용자 정보를 바탕으로 DTO를 생성하여 반환 return new BoardResponse.DtailDTO(board, sessionUser); }
이 메서드가 수행하는 주요 비즈니스 로직:
  1. 데이터 조회: 특정 ID를 가진 게시글을 데이터베이스에서 조회합니다.
  1. 권한 확인: DtailDTO 객체를 생성할 때, 현재 사용자가 해당 게시글의 작성자인지 확인합니다.
  1. 결과 반환: 게시글의 상세 정보를 담은 DTO를 반환하여, 컨트롤러가 이를 사용자에게 전달할 수 있도록 합니다.

왜 비즈니스 로직이 중요한가?

  1. 유지보수성: 비즈니스 로직을 서비스 계층으로 분리하면, 코드의 변경이 필요한 경우 이를 한 곳에서 관리할 수 있어 유지보수가 쉬워집니다.
  1. 재사용성: 동일한 비즈니스 로직을 여러 곳에서 재사용할 수 있습니다. 예를 들어, 게시글 조회 로직은 여러 컨트롤러에서 사용할 수 있습니다.
  1. 책임 분리: 컨트롤러는 요청과 응답을 처리하는 데 집중하고, 비즈니스 로직은 서비스 계층에서 처리하도록 하면 코드가 더 명확해집니다.
비즈니스 로직을 올바르게 관리하고 구현하는 것은 애플리케이션의 성공적인 운영에 매우 중요합니다.
 

5. BoardService

package shop.mtcoding.blog.board; //C -> S -> R import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import shop.mtcoding.blog.user.User; @RequiredArgsConstructor @Service public class BoardService { private final BoardRepository boardRepository; //DI 끝 //2개 리턴을 못한다. //비즈니스 로직에는 Controller가 해줄 필요가 없다. public BoardResponse.DtailDTO 상세보기(int id, User sessionUser) { Board board = boardRepository.findById(id); // 조인(Board - User) 포함, 절대 null 일수 가 없다. return new BoardResponse.DtailDTO(board, sessionUser); } }
  • @Service: 이 클래스가 서비스 계층의 역활을 한다는 것을 나타내고 서비스 계층은 비즈니스 로직을 처리하는 곳이다.
  • DI(Dependency Injection: ‘private final BoardRepository boardRepository’는 의존성 주입(DI)으로, 스프링이 ‘BoardRepository’를 자동으로 주입하여 사용한다.
  • Board board = boardRepository.findById(id): 주어진 ID로 게시글을 조회합니다. 이 과정에서 ‘board’와 ‘user’ 간의 조인이 포함되어 있으면, 결과는 null이 될 수 없다.
Share article

Uni