Spring | 스프링 퀵 스타트 | 비즈니스 컴포넌트 실습 1/2

파과·2022년 8월 11일

BOARD 테이블과 관련된 비즈니스 컴포넌트 구성

  1. BoardVO
  2. BoardDAO
  3. BoardService
  4. BoardServiceImpl

오라클DB를 이용한다.


BoardVO 클래스

Value Object - 레이어와 레이어 사이에서 관련 데이터를 한꺼번에 주고받을 목적으로 사용하는 클래스. DTO(Data Transfer Object)라고도 한다.
여기서는 롬복을 이용해 Getter, Setter, ToString 메소드를 선언한다.

롬복 라이브러리 추가

pom.xml에 다음을 추가한다.

<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.24</version>
  <scope>provided</scope>
</dependency>

BoardVO 클래스

package com.springbook.biz.board;

import java.sql.Date;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;

//VO (Value Object)
@Getter
@Setter
@ToString
public class BoardVO {

	private int seq;
	private String title;
	private String writer;
	private String content;
	private Date regDate;
	private int cnt;
	
}

DAO 클래스

오라클 JDBC 드라이버 받기

pom.xml에 다음을 추가한다.
(repository는 dependency와 별개로 추가해야 함에 주의한다)

<repositories>
  <repository>
    <id>oracle</id>
    <name>ORACLE JDBC Repository</name>
    <url>http://www.datanucleus.org/downloads/maven2/</url>
  </repository>
</repositories>
<dependencies>

  <!-- oracle driver -->
  <dependency>
    <groupId>oracle</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.3</version>
  </dependency>

JDBC Utility 클래스

모든 DAO 클래스에서 공통으로 사용할 JDBCUtil 클래스를 작성해 Connection 획득과 해제 작업을 공통으로 처리한다.

package com.springbook.biz.common;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class JDBCUtil {

	public static Connection getConnection() {
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			return DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "sqs", "1234");
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}

	public static void close(PreparedStatement stmt, Connection conn) {
		if (stmt != null) {
			try {
				if (!stmt.isClosed())
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		if (conn != null) {
			try {
				if (!conn.isClosed())
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				conn = null;
			}
		}
	}

	public static void close(ResultSet rs, PreparedStatement stmt, Connection conn) {
		if (rs != null) {
			try {
				if (!rs.isClosed())
					rs.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				rs = null;
			}
		}
		if (stmt != null) {
			try {
				if (!stmt.isClosed())
					stmt.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		if (conn != null) {
			try {
				if (!conn.isClosed())
					conn.close();
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				conn = null;
			}
		}
	}
}

BoardDAO 클래스

데이터베이스 연동을 담당하는 클래스. CRUD 메소드가 구현되어야 한다. 오라클 JDBC드라이버인 ojdbc가 필요하다.

클래스 객체를 스프링 컨테이너가 생성할 수 있도록 클래스 선언부에 @Repository 어노테이션을 설정. DAO클래스에는 @Component보다 @Repository를 사용하는 것이 적합하다.

package com.springbook.biz.board.impl;

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

import org.springframework.stereotype.Repository;

import com.springbook.biz.board.BoardVO;
import com.springbook.biz.common.JDBCUtil;

//DAO(Data Access Object)
@Repository("boardDAO")
public class BoardDAO {

	//JDBC 관련 변수
	private Connection conn = null;
	private PreparedStatement stmt = null;
	private ResultSet rs = null;
	
	//SQL 명령어들
	private final String BOARD_INSERT = "insert into board(seq, title, writer, content) values((select nvl(max(seq), 0)+1 from board),?,?,?)";
	private final String BOARD_UPDATE = "update board set title=?, content=? where seq=?";
	private final String BOARD_DELETE = "delete board where seq=?";
	private final String BOARD_GET = "select * from board where seq=?";
	private final String BOARD_LIST = "select * from board order by seq desc";
	
	//CRUD 기능의 메소드 구현
	//글 등록
	public void insertBoard(BoardVO vo) {
		System.out.println("===> JDBC로 insertBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_INSERT);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getWriter());
			stmt.setString(3, vo.getContent());
			stmt.executeUpdate();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(stmt, conn);
		}
	}
	
	//글 수정
	public void updateBoard(BoardVO vo) {
		System.out.println("===> JDBC로 updateBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_UPDATE);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getContent());
			stmt.setInt(3, vo.getSeq());
			stmt.executeUpdate();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(stmt, conn);
		}
	}
	
	//글 삭제
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> JDBC로 deleteBoard() 기능 처리");
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_DELETE);
			stmt.setInt(1, vo.getSeq());
			stmt.executeUpdate();
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(stmt, conn);
		}
	}
	
	//글 상세 조회
	public BoardVO getBoard(BoardVO vo) {
		System.out.println("===> JDBC로 getBoard() 기능 처리");
		BoardVO board = null;
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_GET);
			stmt.setInt(1, vo.getSeq());
			rs = stmt.executeQuery();
			if(rs.next()) {
				board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				board.setCnt(rs.getInt("CNT"));
			}
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(rs, stmt, conn);
		}
		return board;
	}
	
	//글 목록 조회
	public List<BoardVO> getBoardList(BoardVO vo){
		System.out.println("===> JDBC로 getBoardList() 기능 처리");
		List<BoardVO> boardList = new ArrayList<BoardVO>();
		try {
			conn = JDBCUtil.getConnection();
			stmt = conn.prepareStatement(BOARD_LIST);
			rs = stmt.executeQuery();
			while(rs.next()) {
				BoardVO board = new BoardVO();
				board.setSeq(rs.getInt("SEQ"));
				board.setTitle(rs.getString("TITLE"));
				board.setWriter(rs.getString("WRITER"));
				board.setContent(rs.getString("CONTENT"));
				board.setRegDate(rs.getDate("REGDATE"));
				board.setCnt(rs.getInt("CNT"));
				boardList.add(board);
			}
		}catch(Exception e) {
			e.printStackTrace();
		}finally {
			JDBCUtil.close(rs, stmt, conn);
		}
		return boardList;
	}
}

BoardService 인터페이스

  • DAO클래스에서 Alt + Shift + T → Extract Interface 선택
  • 이름 BoardService
  • Select All
  • @Override 체크 안함
  • Generate method comments 체크

만들고 나니 BoardDAO와 같은 폴더라서 biz.board폴더로 옮겨뒀다.

인터페이스 생성 후 BoardDAO에 자동으로 추가된 implements BoardService 부분은 지워야 한다!

package com.springbook.biz.board;

import java.util.List;

import com.springbook.biz.board.BoardVO;

public interface BoardService {

	//CRUD 기능의 메소드 구현
	//글 등록
	void insertBoard(BoardVO vo);

	//글 수정
	void updateBoard(BoardVO vo);

	//글 삭제
	void deleteBoard(BoardVO vo);

	//글 상세 조회
	BoardVO getBoard(BoardVO vo);

	//글 목록 조회
	List<BoardVO> getBoardList(BoardVO vo);

}

Service 구현 클래스

BoardService 인터페이스를 구현한 BoardServiceImpl 클래스.

  • BoardService 인터페이스의 모든 추상 메소드를 Overriding오버라이딩

  • 클래스 선언부에 객체 생성을 위한 @Service 선언

  • 클라이언트 프로그램에서 boardService라는 이름으로 객체 요청할 수 있도록 아이디 설정

  • DB연동이 포함된 비즈니스 로직 처리를 위해 BoardDAO타입의 객체를 멤버변수로 가짐 - 이 변수에 BoardDAO타입의 객체를 의존성 주입하기 위해 @Autowired 설정

package com.springbook.biz.board.impl;

import java.util.List;

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

import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;

@Service("boardService")
public class BoardServiceImpl implements BoardService {

	@Autowired
	private BoardDAO boardDAO;

	@Override
	public void insertBoard(BoardVO vo) {
		boardDAO.insertBoard(vo);
	}

	@Override
	public void updateBoard(BoardVO vo) {
		boardDAO.updateBoard(vo);
	}

	@Override
	public void deleteBoard(BoardVO vo) {
		boardDAO.deleteBoard(vo);
	}

	@Override
	public BoardVO getBoard(BoardVO vo) {
		return boardDAO.getBoard(vo);
	}

	@Override
	public List<BoardVO> getBoardList(BoardVO vo) {
		return boardDAO.getBoardList(vo);
	}
}



BoardService 컴포넌트 테스트하기

1. 스프링 설정 파일 수정

다음 코드를 추가

<context:component-scan base-package="com.springbook.biz"></context:component-scan>

2. 클라이언트 작성 및 실행

BoardServiceClient 클래스를 src/test/java/com/springbook/biz 폴더에 작성한다.

package com.springbook.biz;

import java.util.List;

import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.springbook.biz.board.BoardService;
import com.springbook.biz.board.BoardVO;

public class BoardServiceClient {

	public static void main(String[] args) {
		//1. Spring 컨테이너를 구동한다.
		AbstractApplicationContext container = new GenericXmlApplicationContext("applicationcontext.xml");
		
		//2. Spring 컨테이너로부터 BoardServiceImpl 객체를 Lookup한다.
		BoardService boardService = (BoardService) container.getBean("boardService");
		
		//3. 글 등록 기능 테스트
		BoardVO vo = new BoardVO();
		vo.setTitle("임시 제목");
		vo.setWriter("홍길동");
		vo.setContent("임시 내용........");
		boardService.insertBoard(vo);
		
		//4. 글 목록 검색 기능 테스트
		List<BoardVO> boardList = boardService.getBoardList(vo);
		for (BoardVO board : boardList) {
			System.out.println("---> " + board.toString());
		}
		
		//5. Spring 컨테이너 종료
		container.close();
	}
}

에러 1

파일을 제대로 import하지 못하는 에러가 났다.

BoardService cannot be resolved to a type

test폴더 밑에 com.springbook.biz.board 패키지를 만들지 않고 파일만 생성해서 나타난 오류였다.

에러 2 : 실행 결과가 제대로 나오지 않음

===> JDBC insertBoard() 기능 처리
DB 연결 완료

실행 결과가 딱 이렇게만 나왔다.
롬복이 ToString 처리를 제대로 못한 것 같다.
BoardVO에서 lombok의 @ToString을 지우고 Source > Generate to ToString을 사용해 다시 만들었다.

그래도 안 된다.

이유를 알아냈다. 오라클DB에서 테이블 생성하고 나서 커밋을 안해서였다...

COMMIT

0개의 댓글