본문 바로가기
네이버클라우드/JAVA 웹 프로그래밍

JAVA 72일차 (2023-09-04) 자바 프로그래밍_70. Controller에서 비즈니스 로직 분리하기: 서비스 컴포넌트 도입_개인프로젝트 - 마트 관리 시스템

by prometedor 2023. 9. 4.
## 70. Controller에서 비즈니스 로직 분리하기: 서비스 컴포넌트 도입

- Controller에서 비즈니스 로직을 분리하는 이유
- 서비스 컴포넌트의 역할 이해

 

=>

ㄴ service 패키지에 MemberService 라는 이름으로 새로운 인터페이스 추가

=>

service/MemberService.java

ㄴ Member 관련 인터페이스 작성

 

 

 

=>

ㄴ service 패키지에 DefaultMemberService 라는 이름의 새로운 클래스 파일 추가

=>
service/DefaultMemberService.java

ㄴ MemberService 구현하기
ㄴ 구현 필요한 메서드 구현하기

=>

ㄴ [OK] 선택하여 필요한 메서드 모두 오버라이딩 하기

=>

service/DefaultMemberService.java

ㄴ MemberDao 생성자 추가

=>

=>
service/DefaultMemberService.java

=>
app-common/.../dao/MemberDao.java

ㄴ insert 메서드의 반환 값을 int 로 변경해주기

=>

app-common/.../dao/MemberDao.java

ㄴ BoardDao 도 MemberDao 와 마찬가지로 insert 메서드의 반환 값을 int 로 변경해주기

=>
service/DefaultMemberService.java

ㄴ MemberService 메서드 구현하기

=>

service/DefaultMemberService.java

ㄴ PlatformTransactionManager 추가

=>

ㄴ MemberAddController.java 에 있는 해당 코드 복사

=>

service/DefaultMemberService.java

ㄴ 복사한 코드 붙여넣기

ㄴ DefaultTransactionDefinition def를 사용하여 트랜잭션 속성을 정의하고, 이를 FlatformTransactionManager txManager를 통해 트랜잭션을 시작하고 status에 상태를 저장하도록 함

ㄴ 트랜잭션 동안 예외가 발생하면 txManager.rollback(status)를 호출하여 롤백하고, 예외가 발생하지 않으면 txManager.commit(status)를 호출하여 트랜잭션을 커밋하도록 함

=>

service/DefaultMemberService.java

ㄴ  트랜잭션을 처리하도록 해당 try~catch 문 추가

=>

service/DefaultMemberService.java

ㄴ 클래스의 인스턴스를 자동으로 생성하고 Bean으로 관리하도록 @Component 애노테이션 추가

=>
service/DefaultMemberService.java

ㄴ 보다 정확한 표현을 위해 @Service 라는 애노테이션으로 변경해줌

ㄴ @Service는 주로 비즈니스 로직을 처리하는 서비스 클래스를 나타냄

 

 

service/DefaultMemberService.java

ㄴ add 메서드의 코드 전체 복사하여 update 메서드에 복사한 코드 붙여넣기

=>

service/DefaultMemberService.java

ㄴ insert -> update 로 변경하기

=>

service/DefaultMemberService.java

ㄴ update 메서드의 코드 전체 복사하여 delete 메서드에 복사한 코드 붙여넣기

ㄴ update -> delete 로 변경

ㄴ member -> memberNo 로 변경

 

 


controller/MemberAddController.java

ㄴ MemberDao -> MemberService 로 변경

=>
controller/MemberAddController.java

ㄴ 이제 트랜잭션 처리는 DefaultMemberService 에서 하므로 해당 코드 제거

=>

controller/MemberAddController.java

ㄴ 생성자도 새로 추가해주기

=>

controller/MemberAddController.java

ㄴ 이제 트랜잭션 처리는 DefaultMemberService 에서 하므로 해당 코드 제거

=>

controller/MemberAddController.java

ㄴ memberDao.insert -> memberService.add 로 변경

ㄴ 이제 트랜잭션 처리는 DefaultMemberService 에서 하므로 txManager.commit(status) 코드 제거

=>

controller/MemberAddController.java

ㄴ 이제 트랜잭션 처리는 DefaultMemberService 에서 하므로 해당 코드 제거

=>

controller/MemberAddController.java

ㄴ Spring MVC에서 웹 요청을 처리하는 데 사용되는 컨트롤러 클래스를 나타내도록 @Controller 애노테이션으로 변경해줌

ㄴ 보다 정확한 표현을 위해 @Controller 라는 애노테이션으로 변경해줌

 


나머지 MemberXxxController 도 동일한 방법으로 처리해주도록함

=>
controller/MemberDeleteController.java

package bitcamp.report.controller;

import bitcamp.report.service.MemberService;
import org.springframework.stereotype.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller("/member/delete")
public class MemberDeleteController implements PageController {

  MemberService memberService;

  public MemberDeleteController(MemberService memberService) {
    this.memberService = memberService;
  }

  @Override
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

    try {
      if (memberService.delete(Integer.parseInt(request.getParameter("no"))) == 0) {
        throw new Exception("해당 번호의 회원이 없습니다!");
      } else {
        return "redirect:list";
      }

    } catch (Exception e) {
      request.setAttribute("refresh", "2;url=list");
      throw e;
    }
  }

}

 

 

controller/MemberDetailController.java

package bitcamp.report.controller;

import bitcamp.report.service.MemberService;
import org.springframework.stereotype.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller("/member/detail")
public class MemberDetailController implements PageController {

  MemberService memberService;

  public MemberDetailController(MemberService memberService) {
    this.memberService = memberService;
  }

  @Override
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
    request.setAttribute("member", memberService.get(Integer.parseInt(request.getParameter("no"))));
    return "/WEB-INF/jsp/member/detail.jsp";
  }
}

 

 

controller/MemberListController.java

package bitcamp.report.controller;

import bitcamp.report.service.MemberService;
import org.springframework.stereotype.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller("/member/list")
public class MemberListController implements PageController {

  MemberService memberService;

  public MemberListController(MemberService memberService) {
    this.memberService = memberService;
  }

  @Override
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
    request.setAttribute("list", memberService.list());
    return "/WEB-INF/jsp/member/list.jsp";
  }

}

 

 

controller/MemberUpdateController.java

package bitcamp.report.controller;

import bitcamp.report.service.MemberService;
import bitcamp.report.service.NcpObjectStorageService;
import bitcamp.report.vo.Member;
import org.springframework.stereotype.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;

@Controller("/member/update")
public class MemberUpdateController implements PageController {

  MemberService memberService;
  NcpObjectStorageService ncpObjectStorageService;

  public MemberUpdateController(MemberService memberService, NcpObjectStorageService ncpObjectStorageService) {
    this.memberService = memberService;
    this.ncpObjectStorageService = ncpObjectStorageService;
  }

  @Override
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

    try {
      Member member = new Member();
      member.setNo(Integer.parseInt(request.getParameter("no")));
      member.setName(request.getParameter("name"));
      member.setPhone(request.getParameter("phone"));
      member.setPassword(request.getParameter("password"));
      member.setPosition(request.getParameter("position").charAt(0));

      Part photoPart = request.getPart("photo");
      if (photoPart.getSize() > 0) {
        String uploadFileUrl = ncpObjectStorageService
            .uploadFile("bitcamp-nc7-bucket-25", "member/", photoPart);
        member.setPhoto(uploadFileUrl);
      }


      if (memberService.update(member) == 0) {
        throw new Exception("회원이 없습니다.");
      } else {
        return "redirect:list";
      }

    } catch (Exception e) {
      request.setAttribute("refresh", "2;url=list");
      throw e;
    }
  }

}

 

 

 

 

=>

ㄴ service 패키지에 BoardService 라는 이름으로 새로운 인터페이스 추가

=>

service/BoardService.java

ㄴ Board 관련 인터페이스 작성

=>

service/BoardService.java

ㄴ list 제외한 나머지 메서드의 category 제거하기

=>

service/BoardService.java

ㄴ delete 메서드의 리턴값 int 로 변경

 

 

=>

ㄴ service 패키지에 DefaultBoardService 라는 이름의 새로운 클래스 파일 추가

=>
service/DefaultBoardService.java

ㄴ BoardService 구현하기
ㄴ 구현 필요한 메서드 구현하기

=>

ㄴ [OK] 선택하여 필요한 메서드 모두 오버라이딩 하기

=>

service/DefaultBoardService.java

ㄴ @Service 애노테이션 추가해주기

=>
service/DefaultBoardService.java

ㄴ BoardService, PlatformTransactionManager 추가 후 생성자 추가

=>

controller/BoardAddController.java

ㄴ 해당 코드 복사하기

=>

service/DefaultBoardService.java

ㄴ 복사한 코드 붙여넣기

=>

controller/BoardAddController.java

ㄴ 해당 코드 복사

=>

service/DefaultBoardService.java

ㄴ 복사한 코드 붙여넣기

=>

service/DefaultBoardService.java

=>

controller/BoardAddController.java

ㄴ BoardDao -> BoardService 로 변경

=>
controller/BoardAddController.java

ㄴ 트랜잭션 처리는 이제 DefaultBoardService 에서 해주므로 해당 코드 제거

=>

controller/BoardAddController.java

ㄴ 생성자 새로 추가해주기

=>

controller/BoardAddController.java

ㄴ 생성자를 직접 추가하는 대신 @Autowired 애노테이션을 이용하기

=>

controller/BoardAddController.java

ㄴ Spring MVC에서 웹 요청을 처리하는 데 사용되는 컨트롤러 클래스를 나타내도록 @Controller 애노테이션으로 변경해줌

ㄴ 보다 정확한 표현을 위해 @Controller 라는 애노테이션으로 변경해줌

=>

controller/BoardAddController.java

ㄴ 트랜잭션 처리는 이제 DefaultBoardService 에서 해주므로 해당 코드 제거

=>

controller/BoardAddController.java

ㄴ 트랜잭션 처리는 이제 DefaultBoardService 에서 해주므로 해당 코드 제거

=>

controller/BoardAddController.java

ㄴ boardDao.insert -> boardService.add 로 변경

=>

controller/BoardAddController.java

ㄴ 트랜잭션 처리는 이제 DefaultBoardService 에서 해주므로 해당 코드 제거

 

 

 

나머지 BoardXxxController 도 동일한 방식으로 수정해주도록 함

=>

그 전에 MemberXxxController 도 생성자를 자동으로 생성해주는 @Autowired 방식으로 변경

=>

controller/MemberAddController.java

 

controller/MemberDeleteController.java

 

controller/MemberDetailController.java

 

controller/MemberListController.java

 

controller/MemberUpdateController.java

 

 

DefaultBoardService, BoardXxxController 추가로 수정하기

=>

service/DefaultBoardService.java

ㄴ add 메서드의 전체 코드 복사하기

=>

service/DefaultBoardService.java

ㄴ 복사한 코드를 delete 메서드에 붙여넣기

=>

controller/BoardDeleteController.java

ㄴ 해당 게시글의 첨부파일을 삭제하는 코드 복사

=>
service/DefaultBoardService.java

ㄴ 복사한 코드 붙여넣은 후 b.getNo() 대신 boardNo 이용하기

=>
app-common/.../dao/BoardDao.java

ㄴ Board board 대신 int no 이용하기

=>

app-common/.../dao/BoardDao.java

ㄴ Board board 대신 int no 이용하기

=>

app-common/.../dao/BoardDao.java

ㄴ category 를 받지 않도록 하고, category 를 받지 않으면 받은 파라미터가 no 밖에 없으므로 @Param 제거

=>

resources/.../BoardDao.xml

ㄴ parameterType 를 int 로 설정하여 추가

=>

resources/.../BoardDao.xml

ㄴ category를 받지 않으므로 해당 코드 제거

=>
resources/.../BoardDao.xml

ㄴ parameterType 를 board 대신 int 로 변경

=>

resources/.../BoardDao.xml

ㄴ parameterType 를 board 대신 int 로 변경

=>
resources/.../BoardDao.xml

ㄴ #{viewCount} 대신 view_count + 1 를 이용하여 조회수 증가 시키기

=>
resources/.../BoardDao.xml

ㄴ category를 받지 않으므로 해당 코드 제거

=>
resources/.../BoardDao.xml

ㄴ parameterType 를 board 대신 int 로 변경

=>

resources/.../BoardDao.xml

ㄴ category를 받지 않으므로 해당 코드 제거

=>

resources/.../BoardDao.xml

ㄴ 작성자도 로그인한 사람인 loginUser 를 이용하므로 해당 코드 제거

 


service/DefaultBoardService.java

ㄴ 해당 코드는 필요 없으므로 제거

=>
service/DefaultBoardService.java

ㄴ insert(board) -> delete(boardNo) 로 변경

=>

controller/BoardDeleteController.java

=>

controller/BoardDeleteController.java

ㄴ HTTP 요청 파라미터를 통해 게시물 번호(no)를 전달받아 boardService를 사용하여 해당 게시물을 검색하도록 함

=>

service/DefaultBoardService.java

ㄴ boardNo를 사용하여 boardDao의 findBy 메서드를 호출하여 해당 게시물을 검색하고 반환하도록 함

=>

service/BoardService.java

ㄴ 조회수 증가 관련 인터페이스 추가

=>
service/DefaultBoardService.java

ㄴ 구현되지 않은 메서드 구현하도록 함

=>

=>
service/DefaultBoardService.java

ㄴboardDao 객체를 사용하여 updateCount 메서드를 호출하도록 함

=>
service/DefaultBoardService.java

ㄴ delete 메서드의 해당 코드 복사

=>

service/DefaultBoardService.java

ㄴ 복사한 코드 붙여넣기

=>

controller/BoardDetailController.java

ㄴ 해당 코드 복사

=>

controller/BoardDetailController.java

ㄴ 복사한 코드 붙여넣기

=>

controller/BoardDetailController.java

ㄴ 코드 수정

 

 

controller/BoardDeleteController.java

ㄴ 작성자는 여기서 다루지 않으므로 제거

ㄴ category 는 받지 않으므로 제거

=>

controller/BoardDeleteController.java

ㄴ 가져온 게시글 b가 null인 경우 또는 해당 게시글을 작성한 사용자의 번호가 현재 로그인한 사용자의 번호와 다른 경우, 예외를 발생시키도록 함

=>

controller/BoardDeleteController.java

ㄴ 이제 트랜잭션은 여기서 다루지 않으므로 txManager.commit(status) 코드 제거

ㄴ boardService.delete(b.getNo()) 를 이용하여 게시글을 삭제하도록 함

=>

controller/BoardDeleteController.java

ㄴ 이제 트랜잭션은 여기서 다루지 않으므로 해당 코드 제거

=>

controller/BoardDeleteController.java

ㄴ @Component -> @Controller 로 애노테이션 변경

 

 

controller/BoardDetailController.java

ㄴ @Component -> @Controller 로 애노테이션 변경

=>

controller/BoardDetailController.java

ㄴ category 받지 않으므로 해당 코드 제거

=>

controller/BoardDetailController.java

ㄴ boardDao.findBy(category, no) 대신 boardService.get(no) 이용하기

=>

controller/BoardDetailController.java

ㄴ board.setViewCount(board.getViewCount() + 1) 대신 increaseViewCount 를 이용하여 조회수 증가시키도록 하기

=>

controller/BoardDetailController.java

ㄴ 해당 코드 필요 없으므로 제거

=>

controller/BoardDetailController.java

ㄴ 트랜잭션 처리는 여기서 하지 않으므로 해당 코드 제거

 

 

BoardFileDeleteController.java

ㄴ @Component -> @Controller 로 변경하기

=>

BoardFileDeleteController.java

ㄴ category 받지 않으므로 해당 코드 제거

=>

service/BoardService.java

ㄴ getAttachedFile 메서드 규칙 추가

=>

service/DefaultBoardService.java

ㄴ 구현되지 않은 메서드 추가

=>

=>

service/DefaultBoardService.java

ㄴ 파일 번호 fileNo를 기반으로 해당 파일 정보를 검색하는 메서드 추가

=>

controller/BoardFileDeleteController.java

ㄴ boardDao.findFileBy 대신 boardService.getAttachedFile 이용하기

=>

controller/BoardFileDeleteController.java

ㄴ BoardDao.findBy 대신 boardService.get 메서드 이용

=>
controller/BoardFileDeleteController.java

ㄴ BoardDao.deleteFile 대신 boardService.deleteAttachedFile 메서드 이용

=>

controller/BoardFileDeleteController.java

ㄴ 예외 문구 변경

=>
controller/BoardFileDeleteController.java

ㄴ 트랜잭션은 여기서 처리하지 않으므로 txManager.commit(status); 코드 제거

ㄴ category 는 받지 않으므로 category=" + category + "& 코드 제거

=>

controller/BoardFileDeleteController.java

ㄴ 트랜잭션은 여기서 처리하지 않으므로 txManager.rollback(status); 코드 제거

ㄴ category 는 받지 않으므로 category=" + request.getParameter("category") + "& 코드 제거

 

 

controller/BoardListController.java

package bitcamp.report.controller;

import bitcamp.report.service.BoardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Controller("/board/list")
public class BoardListController implements PageController {

  @Autowired
  BoardService boardService;

  @Override
  public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {

    try {
      request.setAttribute("list", boardService.list(Integer.parseInt(request.getParameter("category"))));
      return "/WEB-INF/jsp/board/list.jsp";

    } catch (Exception e) {
      request.setAttribute("refresh", "1;url=/");
      throw e;
    }
  }

}

=>

service/DefaultBoardService.java

ㄴ 목록을 출력하는 메서드 추가

 

 

service/DefaultBoardService.java

ㄴ add 메서드의 전체 코드를 복사

=>
service/DefaultBoardService.java

ㄴ update 메서드에 복사한 코드 붙여넣기

=>

service/DefaultBoardService.java

ㄴ insert -> update 로 변경

=>

service/DefaultBoardService.java

ㄴ count > 0  조건을 추가

=>

controller/BoardUpdateController.java

ㄴ boardDao -> boardService 로 변경

=>

resources/.../BoardDao.xml

ㄴ category 를 사용하지 않으므로 해당 코드 제거

ㄴ 작성자는 loginUser 로 관리하므로 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ 작성자는 여기서 셋팅할 필요가 없으므로 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ boardService.get 메서드를 통해 board 객체를 가져오도록 함

=>

controller/BoardUpdateContorller.java

ㄴ 작성자와 로그인한 사람의 번호가 다를 경우 "게시글이 존재하지 않거나 변경 권한이 없습니다." 문구를 출력하도록 함
=>

controller/BoardUpdateContorller.java

ㄴ 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ category 는 이용하지 않으므로 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ if 문 안에 있던 boardService.update(board) 코드를 if 문 밖으로 빼주기

=>

controller/BoardUpdateContorller.java

ㄴ if 문 제거

=>

controller/BoardUpdateContorller.java

ㄴ 트랜잭션은 여기서 처리하지 않아도 되므로 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ 트랜잭션은 여기서 처리하지 않아도 되므로 해당 코드 제거

=>

controller/BoardUpdateContorller.java

ㄴ category 는 사용하지 않으므로 해당 코드 제거

 

 

controller/HomeController.java

ㄴ @Component -> @Controller 로 변경

 

 

LoginController.java

ㄴ @Component -> @Controller 로 변경

=>

LoginController.java

ㄴ 생성자 직접 생성하는 대신 @Autowired 이용하기

ㄴ MemberDao -> MemberService 로 변경

=>
LoginController.java

ㄴ memberDao.findByPhoneAndPassword 대신 memberService.get 이용하기

=>

LogoutController.java

=>

App 실행

=>

=>

ㄴ 로그인 선택

=>

ㄴ 로그인 정보 입력 후 [로그인] 선택

=>

ㄴ 로그인 정상적으로 실행됨을 확인

=>

ㄴ 회원 선택 시 회원 목록 정상적으로 출력됨을 확인

=>

ㄴ 게시글 선택 시 게시글 목록 정상적으로 출력됨을 확인

=>

ㄴ 새 글 선택 후 내용 입력 및 첨부파일 등록 후 [등록] 선택

=>

=>

ㄴ 정상적으로 등록됨을 확인

=>

ㄴ 게시글 내용 변경 후 [변경] 선택

=>

ㄴ 오류 발생

=>

WEB-INF/jsp/board/list.jsp

ㄴ category 제거해주기

=>
WEB-INF/jsp/board/detail.jsp

ㄴ category 제거해주기

 

 

service/DefaultBoardService.java

ㄴ deleteAttachedFile 메서드 구현해주기

=>

App 재실행

=>

ㄴ 첨부파일 [삭제] 선택

=>

ㄴ 첨부파일 정상적으로 삭제됨을 확인

=>
게시글 삭제 오류

=>

WEB-INF/jsp/board/detail.jsp

ㄴ category=${board.category}& 을 다시 추가해주고 param -> board 로 변경해주기

=>

App 재실행

=>

=>

ㄴ 게시글 [삭제] 선택

=>

ㄴ 게시글이 정상적으로 삭제됨을 확인

=>

=>

ㄴ 게시글 변경 후 [변경] 선택

=>

ㄴ 오류 발생

=>

controller/BoardUpdateController.java

ㄴ request.getParameter("category") 대신 board.getCategory() 이용하기

=>

resources/.../BoardDao.xml

ㄴ parameterType 을 int 가 아닌 board 로 변경

=>

App 재실행

=>

=>

ㄴ 로그인 후 게시글 내용 변경 후 [변경] 선택

=>

ㄴ 게시글이 정상적으로 변경됨을 확인

 

 

WEB-INF/jsp/board/detail.jsp

ㄴ 날짜 데이터를 출력하기 위해 ${simpleDateFormatter.format(board.createdDate)} 대신 fmt 태그 라이브러리 이용하기

=>

ㄴ 날짜 데이터가 정상적으로 출력됨을 확인