Tiny Bunny [Spring] Service와 ServiceImpl - 솜님의 블로그
솜님의 블로그
카테고리
작성일
2024. 10. 10. 15:31
작성자
겨울솜사탕

BoardController에 글 목록 페이지로 보내는 메서드가 있다.

	@RequestMapping("/boardList.do")
	public String boardList(Model model, BoardDTO boardDTO,BoardDAO boardDAO) throws Exception {

		// 글 제목 + 내용 데이터가 넘어옴
		List<BoardDTO> datas = new ArrayList<BoardDTO>();
		datas=boardDAO.selectAll(boardDTO);


		model.addAttribute("boardList", datas);
		// 데이터가 있으므로 포워드
		return "boardList";
	}

 

여기서 받는 인자는

Model, DTO, DAO가 있다.

 

  • Model - view에서 씀
  • DTO - view에서 쓸 수 있음
  • DAO - view에서 사용하지 않음

현재 인자를 다 view에 보내주고 있다.

그럼 굳이 DAO를 매개변수로 쓸 필요가 있는지 알아보자.

 


1. 굳이 DAO가 매개변수 자리에 있어야 하나?

 

2. 무언가를 인자(매개변수)로 삼으면 자연스럽게 결합도가 높아지게 된다.

 

우리는 그동안 결합도를 낮추기 위해 DAO의 인자를 DTO로 맞춰주었다.

현재 코드의 경우 DAO를 사용하지 않는데 들어가 있으므로 결합도가 높아져 있는 상태이다.

 

개발을 하게 되면 변동이 가장 심한 것 중 하나가 DBMS다.

예를 들어, DBMS에 따라 DAO명이 다른 경우 ▼

  • MySQL BoardDAO
  • Oracle BoardOracleDAO
  • MariaDB BoardMariaDAO

현재 메서드마다 DAO를 받고 있으므로 인자에 들어있는 DAO를

BoardDAO → BoardOracleDAO 이런 식으로 다 바꿔줘야 한다.

 

1)

이를 개선하기 위해 BoardDAO를 멤버변수로 빼서 인자에서 제거한다.

하지만 DBMS가 변경되면, 멤버변수명을 변경해줘야 하므로

여전히 코드 변경 해야하고 + 컴파일해야 하니까 결합도가 여전히 높다.

 

2)

DAO는 주입이 되어야 하는 대상이어서 Service를 멤버변수로 위치시킨다.

private BoardService boardService;

Service : DAO를 멤버변수로 삼고 있다는 것이 특징이다.

이렇게 하면 이관작업시 Controller의 변경사항이 없기 때문에 컴파일을 안 해도 되고,

결합도가 낮아진다는 것을 알 수 있다!

 

 

🍀정리
- DAO가 결합도만 높이는데 굳이 인자로 받아와야 하나?
- 그래서 멤버변수로 뺐더니 컴파일을 해야해서 여전히 결합도가 높다.
- 그래서 DAO를 가져다 쓰는 Service를 썼더니 결합도를 낮춰줄 수 있었다.
- 따라서 Service는 이러한 이유 때문에 DAO와 메서드 시그니쳐를 맞추는 것이 매우 중요하다!

 

 

// BoardController

package com.koreait.app.view.board;

import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import com.koreait.app.biz.board.BoardDTO;
import com.koreait.app.biz.board.BoardService;


@Controller("board")
public class BoardController{

	@Autowired
	private BoardService boardService;

	// 글 작성 페이지
	@RequestMapping("/boardWritePage.do")
	public String boardWritePage() throws Exception {

		// 글 작성하는 페이지로 이동만 시켜줌
		return "redirect:boardWrite.jsp";

	}

	// 글 작성
	@RequestMapping("/boardWrite.do")
	public String boardWrite(BoardDTO boardDTO) throws Exception {

		// 메서드 인자값으로 DTO, DAO 객체를 받아와서 Spring 컨테이너가 new 해줌. 
		boolean flag=boardService.insert(boardDTO);


		// 3. 페이지 이동 == 네비게이션
		// 이동할때 ViewResolver가 .jsp를 해주기 때문에 jsp를 붙이지 않아도 된다.
		// 따라서 다른 Action으로 보낼 땐 .do, 페이지로 이동할때는 이름만...

		if(flag) { // 글 작성 성공시
			return "main";
		}
		// 글 작성 실패시 다시 글 작성 페이지로
		return "redirect:boardWrite.jsp";
	}

	// 글 목록 페이지
	@RequestMapping("/boardList.do")
	public String boardList(Model model, BoardDTO boardDTO) throws Exception {

		// 글 제목 + 내용 데이터가 넘어옴
		List<BoardDTO> datas = new ArrayList<BoardDTO>();
		datas=boardService.selectAll(boardDTO);

		model.addAttribute("boardList", datas);
		// 데이터가 있으므로 포워드, 
		return "boardList";
	}
}

 

// BoardService

package com.koreait.app.biz.board;

import java.util.List;

// DAO와 메서드 시그니쳐를 동일하게 하기 위한 인터페이스 파일
public interface BoardService {

	List<BoardDTO> selectAll(BoardDTO boardDTO);
	BoardDTO selectOne(BoardDTO boardDTO);
	boolean insert(BoardDTO boardDTO);
	boolean update(BoardDTO boardDTO);
	boolean delete(BoardDTO boardDTO);
	
}

 

// BoardServiceImpl

package com.koreait.app.biz.board;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

// 인터페이스인 BoardService의 구현체(실현체)
@Service("boardService")
public class BoardServiceImpl implements BoardService{

	// DAO를 사용해야 하므로 멤버변수로 선언
	@Autowired
	private BoardDAO boardDAO;
	
	
	@Override
	public List<BoardDTO> selectAll(BoardDTO boardDTO) {
		return this.boardDAO.selectAll(boardDTO);
	}

	@Override
	public BoardDTO selectOne(BoardDTO boardDTO) {
		return this.boardDAO.selectOne(boardDTO);
	}

	@Override
	public boolean insert(BoardDTO boardDTO) {
		return this.boardDAO.insert(boardDTO);
	}

	@Override
	public boolean update(BoardDTO boardDTO) {
		return this.boardDAO.update(boardDTO);
	}

	@Override
	public boolean delete(BoardDTO boardDTO) {
		return this.boardDAO.delete(boardDTO);
	}

}

BoardServiceImpl는 BoardService의 실현체(구현체)이다.

여기서는 DAO를 사용해야 하므로 멤버변수로 두고 @Autowired 어노테이션을 달아준다.

 

// BoardDAO

package com.koreait.app.biz.board;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.springframework.stereotype.Repository;

import com.koreait.app.biz.common.JDBCUtil;
import com.koreait.app.biz.member.MemberDTO;

@Repository
public class BoardDAO {
	
	private final String SELECTALL = "SELECT * FROM BOARD";
	private final String SELECTONE = "SELECT NUM,CONTENT FROM BOARD WHERE NUM=?";
	private final String INSERT = "INSERT INTO BOARD(TITLE,CONTENT) VALUES(?,?)";
	private final String UPDATE = "UPDATE BOARD SET TITLE=?,CONTENT=? WHERE NUM=?";
	private final String DELETE = "DELETE FROM BOARD WHERE NUM=?";
	
	
	public List<BoardDTO> selectAll(BoardDTO boardDTO){
		
		List<BoardDTO> datas=new ArrayList<BoardDTO>();
		Connection conn=JDBCUtil.connect();
		PreparedStatement pstmt;
		
		try {
			pstmt = conn.prepareStatement(SELECTALL);
			ResultSet rs=pstmt.executeQuery();
			
			while(rs.next()) {
				System.out.println("board.selectAll rs.next 시작");
				BoardDTO data = new BoardDTO();
				data.setContent(rs.getString("CONTENT")); // 내용
				data.setTitle(rs.getString("TITLE")); // 제목
				datas.add(data);
			}
			System.out.println("board.selectAll datas로그 : ["+datas+"]");
			
		} catch (SQLException e) {
			System.out.println("SQL문 실패..");
			e.printStackTrace();
		}		
		
		return datas;
	}
	
	
	
	public BoardDTO selectOne(BoardDTO boardDTO) {
		BoardDTO data = new BoardDTO();
		System.out.println("board.selectOne 시작");
		// 1,2단계
		Connection conn = JDBCUtil.connect();
		PreparedStatement pstmt=null;
		
		// 3단계
		try {
			// SQL문을 읽어올 준비를 한다.
			pstmt = conn.prepareStatement(SELECTONE);
			// 찾을 데이터를 1번 파라미터에 넣어준다.
			pstmt.setInt(1, boardDTO.getNum()); // 글 번호
			// select 타입 : executeQuery - ResultSet 객체 반환
			ResultSet rs = pstmt.executeQuery();

			// next() 메서드로 한 줄씩 읽어온다.
			if(rs.next()) {
				System.out.println("board.selectOne rs.next() 시작");
				data.setNum(rs.getInt("NUM")); // 글 번호
				data.setTitle(rs.getString("TITLE")); // 글 제목
				data.setContent(rs.getString("CONTENT")); //글 내용
			}
			System.out.println("board.selectOne data로그 : ["+data+"]");
			
		} catch (SQLException e) {
			System.out.println("SQL문 에러");
			e.printStackTrace();
		}
		
		// 4단계
		JDBCUtil.disconnect(pstmt, conn);
		System.out.println("board.selectOne 종료");
		return  data;
	}
	
	
	
	public boolean insert(BoardDTO boardDTO) {
		
		System.out.println("board.insert 시작");
		// 1,2단계
		Connection conn = JDBCUtil.connect();
		PreparedStatement pstmt=null;
		
		// 3단계
		try {
			// SQL문을 읽어올 준비를 한다.
			pstmt = conn.prepareStatement(INSERT);
			pstmt.setString(1, boardDTO.getTitle()); //글 제목
			pstmt.setString(2, boardDTO.getContent()); // 글 내용
			
			// insert : executeUpdate - 정수 반환
			int result = pstmt.executeUpdate();
			System.out.println("board.insert result : " + result);
			
			// 변경된 행 수가 0보다 작거나 같다면
			if(result<=0) {
				System.out.println("board.insert 변경된 행 수 없음");
				return false;
			}
			System.out.println("board.insert 행 변경 성공");
			
		} catch (SQLException e) {
			System.out.println("SQL문 에러");
			e.printStackTrace();
			return false;
		}
		
		// 4단계
		JDBCUtil.disconnect(pstmt, conn);
		System.out.println("board.insert 종료");
		
		return true;
	}
	
	
	
	public boolean update(BoardDTO boardDTO) {
		
		System.out.println("board.update 시작");
		// 1,2단계
		Connection conn = JDBCUtil.connect();
		PreparedStatement pstmt=null;
		
		// 3단계
		try {
			// SQL문을 읽어올 준비를 한다.
			pstmt = conn.prepareStatement(UPDATE);
			pstmt.setString(1, boardDTO.getTitle()); //글 제목
			pstmt.setString(2, boardDTO.getContent()); // 글 내용
			pstmt.setInt(3, boardDTO.getNum()); // 글 번호
			
			// insert : executeUpdate - 정수 반환
			int result = pstmt.executeUpdate();
			System.out.println("board.update result : " + result);
			
			// 변경된 행 수가 0보다 작거나 같다면
			if(result<=0) {
				System.out.println("board.update 변경된 행 수 없음");
				return false;
			}
			System.out.println("board.update 행 변경 성공");
			
		} catch (SQLException e) {
			System.out.println("SQL문 에러");
			e.printStackTrace();
			return false;
		}
		
		// 4단계
		JDBCUtil.disconnect(pstmt, conn);
		System.out.println("board.update 종료");
		
		return true;
	}
	
	
	
	public boolean delete(BoardDTO boardDTO) {
		System.out.println("board.delete 시작");
		// 1,2단계
		Connection conn = JDBCUtil.connect();
		PreparedStatement pstmt=null;
		
		// 3단계
		try {
			// SQL문을 읽어올 준비를 한다.
			pstmt = conn.prepareStatement(DELETE);
			pstmt.setInt(1, boardDTO.getNum()); // 글 번호
			
			// insert : executeUpdate - 정수 반환
			int result = pstmt.executeUpdate();
			System.out.println("board.delete result : " + result);
			
			// 변경된 행 수가 0보다 작거나 같다면
			if(result<=0) {
				System.out.println("board.delete 변경된 행 수 없음");
				return false;
			}
			System.out.println("board.delete 행 변경 성공");
			
		} catch (SQLException e) {
			System.out.println("SQL문 에러");
			e.printStackTrace();
			return false;
		}
		
		// 4단계
		JDBCUtil.disconnect(pstmt, conn);
		System.out.println("board.delete 종료");
		
		return true;
	}

}

BoardDAO에 @Repository 어노테이션을 달아준다.