티스토리 뷰

우선, 기본적으로 Spring 프레임워크는 제어의 역행 구조를 가지고 있기 때문에, 다음과 같은 구조로 프로젝트가 실행된다.

                                                     

좌: Presentatino-layer, 우: business-layer

이 때, 일반적인 Dynamic Web Project 였다면, Controller 가 각 엑션을 구현받은 클래스들을 호출하여 사용하지만, Spring은 이를 Controller, Service, DAO, VO 등의 객체를 Spring Container가 자동으로 생성하도록 어노테이션을 통하여 설정할 수 있다.

 

어노테이션 위치 의미
@Service ~ServiceImpl 해당 클래스는 비즈니스 로직을 처리하는 Service 클래스이다.
@Repository ~DAO 해당 클래스는 DB 연동을 처리하는 DAO 클래스이다.
@Controller ~Controller 해당 클래스는 사용자의 요청을 제어하는 Controller 클래스이다.

간단하게 DB와 연동해서 CRUD 기능만 구현한 예제 프로젝트를 하나 보면서 이해해보자. 

 

우선, 파일의 구조는 다음과 같다.

 

 

◎JDBCUtil.java

DB Connection 객체 관리를 위한 클래스

package com.choonham.test2.common;

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

public class JDBCUtil {

	public JDBCUtil() {
	}
	
	/** 1.  데이터베이스 접속 객체 반환 **/
	public static Connection getConnection() {
		try{
			
			Class.forName("oracle.jdbc.driver.OracleDriver");
			//추후 변경 예정
			
			String url = "jdbc:oracle:thin:@127.0.0.1:1521:XE";
			
			return DriverManager.getConnection(url, "choonham", "6725");
			
		} catch(Exception e){
			e.printStackTrace();
		}
		return null;
	}
	
	/** 각 자원 해제 메서드**/
	public static void close(Statement 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(Statement stmt, Connection conn, ResultSet rs){
		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;
			}
		}
		
		if(rs != null) {
			try{
				if(!rs.isClosed()){
					rs.close();
				}
			} catch(Exception e){
				e.printStackTrace();
			} finally{
				rs = null;
			}
		}
	}

}
 

 

 

◎BoardService.java (interface)

CRUD 기능에 관련된 메서드를 가지고 있는 인터페이스이다.

package com.choonham.test2.board;

import java.util.List;

/** CRUD 에 관련된 메서드 **/
public interface BoardService {
	
	// 글 등록
	void insertBoard(BoardVO vo);
	
	//글 수정
	void updateBoard(BoardVO vo);
	
	//글 삭제
	void deleteBoard(BoardVO vo);
	
	//글 목록
	List<BoardVO> getBoardList(BoardVO vo);
	
	//글 상세
	BoardVO getBoard(BoardVO vo);
}

 

◎BoardVO.java

package com.choonham.test2.board;

import java.sql.Date;

public class BoardVO {

	private int seq;
	private String title;
	private String writer;
	private String content;
	private Date regDate;
	private int cnt;
	
	public BoardVO() {
		// TODO Auto-generated constructor stub
	}

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

	@Override
	public String toString() {
		return "BoardVO [seq=" + seq + ", title=" + title + ", writer=" + writer + ", content=" + content + ", regDate="
				+ regDate + ", cnt=" + cnt + "]";
	}

}

◎BoardDAO.java

실제로 DB 연관 메서드의 기능을 작성해놓은 DAO 클래스이다. (따로 인터페이스로 구현을 하거나, 받지는 않는다.)

package com.choonham.test2.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.choonham.test2.board.BoardVO;
import com.choonham.test2.common.JDBCUtil;

/** 테이블에 데이터를 실제로 접근 **/

@Repository("boardDAO")
public class BoardDAO {

	//JDBC 관련 변수
	private Connection conn = null;
	private PreparedStatement pstmt = 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 order by seq desc";
	
	//CRUD 기능의 메서드 구현
	
	//글 등록
	public void insertBoard(BoardVO vo) {
		try{
			conn = JDBCUtil.getConnection();
			pstmt = conn.prepareStatement(BOARD_INSERT);
			pstmt.setString(1,  vo.getTitle());
			pstmt.setString(2,  vo.getWriter());
			pstmt.setString(3,  vo.getContent());
			pstmt.executeUpdate();
			
		} catch(Exception e) {
			e.printStackTrace();
		} finally{
			JDBCUtil.close(pstmt, conn);
		}
	}
	
	//글 수정
		public void updateBoard(BoardVO vo) {
			try{
				conn = JDBCUtil.getConnection();
				pstmt = conn.prepareStatement(BOARD_UPDATE);
				pstmt.setString(1,  vo.getTitle());
				pstmt.setString(2,  vo.getContent());
				pstmt.setInt(3,  vo.getSeq());
				pstmt.executeUpdate();
			} catch(Exception e) {
				e.printStackTrace();
			} finally{
				JDBCUtil.close(pstmt, conn);
			}
		}
		
		//글 삭제
		public void deleteBoard(BoardVO vo) {
			try{
				conn = JDBCUtil.getConnection();
				pstmt = conn.prepareStatement(BOARD_DELETE);
				pstmt.setInt(1,  vo.getSeq());
				pstmt.executeUpdate();
			} catch(Exception e) {
				e.printStackTrace();
			} finally{
				JDBCUtil.close(pstmt, conn);
			}
		}
		
		//글 목록
		public List<BoardVO> getBoardList(BoardVO vo) {
			
			List<BoardVO> boardList = new ArrayList<BoardVO>();
			
			try{
				conn = JDBCUtil.getConnection();
				pstmt = conn.prepareStatement(BOARD_LIST);
				rs = pstmt.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);
				}
				
				pstmt.executeUpdate();
			} catch(Exception e) {
				e.printStackTrace();
			} finally{
				JDBCUtil.close(pstmt, conn);
			}
			return boardList;
		}
		
		//글 상세
		public BoardVO getBoard(BoardVO vo) {
			
			BoardVO board = null;
			
			try{
				conn = JDBCUtil.getConnection();
				pstmt = conn.prepareStatement(BOARD_GET);
				pstmt.setInt(1, vo.getSeq());
				rs = pstmt.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(pstmt, conn);
			}
			return board;
		}
	public BoardDAO() {
		
	}
}

 

◎BoardServiceImpl.java

BoardService 인터페이스를 구현받아서 BoardDAO를 호출해, 관련 메서드를 실행하게끔 하는 클래스

package com.choonham.test2.board.impl;

import java.util.List;

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

import com.choonham.test2.board.BoardService;
import com.choonham.test2.board.BoardVO;

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

	@Autowired
	private BoardDAO boardDAO;
	
	public BoardServiceImpl() {
	}

	@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 List<BoardVO> getBoardList(BoardVO vo) {
		return boardDAO.getBoardList(vo);
	}

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

}

◎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:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	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">
		
	<context:component-scan base-package="com.choonham.test2"></context:component-scan>
</beans>

이제 Main에서 값을 넣어주고 Insert 메서드를 시험삼아 호출해보면, 데이터가 정상적으로 DB에 삽입이 된다.

 

◎Main

package com.choonham.test2.board;

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

public class BoardServiceClient {

	public static void main(String[] args) {
		AbstractApplicationContext container = new GenericXmlApplicationContext("applicationContext.xml");
		
		BoardService boardService = (BoardService)container.getBean("boardService");

		BoardVO vo = new BoardVO();
		vo.setTitle("임시 제목");
		vo.setWriter("춘햄");
		vo.setContent("임시 내용");
		
		boardService.insertBoard(vo);
		
		container.close();
	}

}

 

스프링의 전체적인 제어 구조를 한번 훑어보기 위한 예제를 풀어봤는데... 아직 직관적으로 데이터의 흐름이 보이는 단계가 아니라서, 조금 낯설다...

Comments