Tiny Star

구/스프링

비즈니스 컴포넌트 실습 1

흰둥아 2020. 10. 3. 22:21

이번 시간에는 일반적으로 프로젝트에서 사용하는 구조로 비즈니스 컴포넌트를 구현한 후, 스프링의 Dependency Lookup과 Dependency Injection을 점검해보도록 한다.

 

- BoardService 컴포넌트 구조

 

 

BoardService 컴포넌트 클래스 다이어그램

 

 

실습 파일들의 위치와 프로젝트 구조

 

 

- Value Object 클래스 작성

board.sql
CREATE TABLE BOARD(
	SEQ NUMBER(5) PRIMARY KEY,
    TITLE VARCHAR(200),
    WRITER VARCHR(20),
    CONTENT VARCHAR2(2000),
    REFDATE DATE DEFAULT SYSDATE,
    CNT NUMBER(5) DEFAULT 0
);

 

 

boardVO.java
package com.springbook.biz.board;

import java.sql.Date;

// VO(Value Object) 클래스는 레이어와 레이어 사이에서 관련된 데이터를 한꺼번에 주고받을 목적으로 사용하는 클래스
public class BoardVO {
	// Board 테이블에 포함된 칼럼과 같은 이름의 멤버 변수를 private 접근 제한자로 선언한다.
	// 그리고 private 멤버 변수에 접근하는 Getter/Setter 메소드를 선언하면 VO 클래스는 마무리된다.
	private int seq;
	private String title;
	private String writer;
	private String content;
	private Date regDate;
	private int cnt;
	
	public int getSeq() {
		return seq;
	}
	public void setSeq(int seq) {
		this.seq = seq;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getWriter() {
		return writer;
	}
	public void setWriter(String writer) {
		this.writer = writer;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public Date getRegDate() {
		return regDate;
	}
	public void setRegDate(Date regDate) {
		this.regDate = regDate;
	}
	public int getCnt() {
		return cnt;
	}
	public void setCnt(int cnt) {
		this.cnt = cnt;
	}
	
	
	// 옵션으로 toString() 메소드도 생성해 놓으면 나중에 VO 객체의 값을 출력할 때 요긴하게 사용할 수 있다.
	@Override
	public String toString() {
		return "BoardVO [seq=" + seq + ", title=" + title + ", writer=" + writer + ", content=" 
						+ content + ", regDate=" + regDate + ", cnt=" + cnt + "]";
	}
	
}

 

 

- DAO 클래스 작성

pom.xml
~ 생략 ~

<dependencies>
        <!-- H2 데이터베이스 -->
        <dependency>
        	<groupId>com.h2database</groupId>
        	<artifactId>h2</artifactId>
        	<version>1.4.200</version>
        </dependency>
        
        <!-- Spring -->
        <dependency>
        	<groupId>org.springframwork</groupId>
            
            ~ 생략 ~

h2 드라이버가 Maven Dependencies에 추가된 것을 확인

 

 

 

JDBCUtil.java
package com.springbook.biz.common;

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

public class JDBCUtil {
	// 당분간 Mybatis 같은 프레임워크를 사용하기 전까지는 데이터베이스 연동 처리를 JDBC로 할 것이다.
	// 따라서 모든 DAO 클래스에서 공통으로 사용할 JDBCUtil 클래스를 작성하여 Connection 획득과 해제 작업을 공통으로 처리하도록 한다.
	public static Connection getConnection() {
		try {
		     Class.forName("org.h2.Driver");
		     return DriverManager.getConnection("jdbc:h2:tcp://localhost/~/test", "sa", "");
		} 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.java
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  {
	// BoardVO 객체를 매개변수와 리턴타입으로 사용하면서 BOARD 테이블과  CRUD 기능을 처리할 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;
	}
}

 

 

- Service 인터페이스 작성

BoardService.java
package com.springbook.biz.board;

import java.util.List;

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 구현 클래스 작성

BoardServiceImpl.java
package com.springbook.biz.board.impl;

// BoardService 인터페이스를 구현한 BoardServiceImpl 클래스는 BoardService 인터페이스의 모든 추상 메소드를 재정의하여 구현해야 한다.
// 그리고 클래스 선언부에 객체 생성을 위한 @Service가 선언되어 있으며, 
// 클라이언트 프로그램에서 boardService라는 이름으로 객체를 요청할 수 있도록 아이디도 설정했다.
// BoardServiceImpl는 데이터베이스 연동이 포함된 비즈니스 로직처리를 위해서 BoardDAO타입의 객체를 멤버변수로 가지고 있다.
// 그리고 이 변수에 BoardDAO 타입의 객체를 의존성 주입하기 위해서 변수 위에 @Autowired를 설정했다.

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 BoardServiceImlp implements BoardService{
	@Autowired
	private BoardDAO boardDAO;
	
	public void insertBoard(BoardVO vo) {
		boardDAO.insertBoard(vo);
	}
	
	public void updateBoard(BoardVO vo) {
		boardDAO.updateBoard(vo);
	}
	
	public void deleteBoard(BoardVO vo) {
		boardDAO.deleteBoard(vo);
	}
	
	public BoardVO getBoard(BoardVO vo) {
		return boardDAO.getBoard(vo);
	}
	
	public List<BoardVO> getBoardList(BoardVO vo) {
		return boardDAO.getBoardList(vo);
	}
}

 

 

- BoardService 컴포넌트 테스트

applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
			http://www.springframework.org/schema/beans/spring-beans.xsd
			http://www.springframework.org/schema/context 
			http://www.springframework.org/schema/context/spring-context-4.2.xsd">

	<!-- 컴포넌트 스캔 범위를 'com.springbook.biz' 패키지로 지정했으므로 BoardServiceInpl 클래스와 BoardDAO 클래스가
	스캔 범위에 포함되어 객체가 생성될것이다. 그리고 의존성 주입도 적정하게 처리될 것이다. -->
	<context:component-scan base-package="com.springbook.biz">
	</context:component-scan>

</beans>

 

 

BoardServiceClient.java
package com.springbook.biz.board;

import java.util.List;

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

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();
	}
}

 

 

실행결과

top