[Spring] Spring 공부 정리-2

업데이트:

실습은 Spring Quick Start:채규태 교재를 바탕으로 진행했습니다.

1. applicationContext.xml 만들기

src/main/resource 폴더를 우클릭 > New > Other > Spring Bean Configuration File 선택, 이름은 applicationContext로 생성합니다.

2. BoardService 전체 구조

getter-setter
오늘 작성할 프로그램의 최종 구조입니다.

3. BoardVO.java 작성

Value Object. VO는 데이터를 한꺼번에 주고받기 위해 사용하는 클래스입니다.
src/main/java 밑에 com.springbook.biz.board 패키지를 생성하고 해당 패키지 아래에 BoardVO.java를 작성합니다.
작성하실 때, 멤버 변수까지만 작성하고 소스코드 우클릭 -> Source -> Generate Getters/Setters, Generate toString을 이용하시면 편하게 작성하실 수 있습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.springbook.biz.board;

import java.sql.Date;

// VO(Value Object) = DTO(Data Transfer Object)
public class BoardVO {
	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;
	}
	@Override
	public String toString() {
		return "BoardVO [seq=" + seq + ", title=" + title + ", writer=" + writer + ", content=" + content + ", regDate="
				+ regDate + ", cnt=" + cnt + "]";
	}
	
}

getter-setter

위의 멤버 변수명이 어디서 본 것 같지 않나요? 저번 시간에 작성한 board 테이블의 속성들과 같습니다.
boardVO.java는 여러 데이터를 한번에 보내기 위해 작성합니다. title, writer, content와 같은 정보를 따로따로 보내면 정말 귀찮겠죠??

4. pom.xml에서 JDBC 드라이버 추가하기

JDBC 드라이버는 MySQL과 Java를 연동하기 위해 설치합니다. 스프링 프로젝트에는 Maven이란 편리한 기능이 있는데, Maven에 원하는 dependency를 추가해주면 IDE가 자동으로 다운로드해줍니다. 이를 이용해 JDBC 드라이버를 다운로드 받아보겠습니다.
pom.xml을 열고 아래 코드를 추가해줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
	<dependencies>
		~생략~
	
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
    		<groupId>mysql</groupId>
    		<artifactId>mysql-connector-java</artifactId>
    		<version>8.0.20</version> <!-- 자신의 버전과 맞게! -->
		</dependency>
		
		~생략~
	</dependencies>

이렇게 dependencies 태그 사이에 해당 코드를 추가합니다. 그러면 IDE가 자동으로 mysql-connector(JDBC)를 다운로드 받게 됩니다.
Libraries 탭에 가보시면 mysql-connector-java-x.x.xx가 다운로드되신걸 볼 수 있습니다.

5. JDBCUtill 클래스 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.springbook.biz.common;

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

public class JDBCUtill {
	
	public static Connection getConnection() {
		try {
			Class.forName("com.mysql.cj.jdbc.Driver");
			return DriverManager.getConnection("jdbc:mysql://localhost:3306/springmvc?serverTimezone=UTC", "아이디", "비밀번호");
		} 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 (SQLException e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		
		if (conn != null) {
			try {
				if(!conn.isClosed()) conn.close();
			} catch (SQLException 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 (SQLException e) {
				e.printStackTrace();
			} finally {
				rs = null;
			}
		}
		
		if (stmt != null) {
			try {
				if(!stmt.isClosed()) stmt.close();
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				stmt = null;
			}
		}
		
		if (conn != null) {
			try {
				if(!conn.isClosed()) conn.close();
			} catch (SQLException e) {
				e.printStackTrace();
			} finally {
				conn = null;
			}
		}
	}
	
}

아이디 비밀번호 부분만 변경하여 복사 붙여넣기 해줍니다.

6. DAO 클래스 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.springbook.biz.board.impl;

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.springbook.biz.board.BoardVO;
import com.springbook.biz.common.JDBCUtill;

//DAO (Data Access Object)

/*
 * Repository: DB연동할때 발생하는 예외를 변환해주는 특별한 기능이 추가되어있음. Component보다 기능이 많음.
 */
@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 cnt from (select ifnull(max(seq), 0)+1 as cnt FROM board) as tmpquery) , ? , ? , ? )";
	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_SELECT = "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 = JDBCUtill.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 {
			JDBCUtill.close(stmt, conn);
		}
	}
	
	//글 수정
	public void updateBoard(BoardVO vo) {
		System.out.println("===> JDBC로 updateBoard() 기능 처리");
		try {
			conn = JDBCUtill.getConnection();
			stmt = conn.prepareStatement(BOARD_UPDATE);
			stmt.setString(1, vo.getTitle());
			stmt.setString(2, vo.getContent());
			stmt.setInt(3, vo.getSeq());
			stmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtill.close(stmt, conn);
		}
	}
	
	//글 삭제
	public void deleteBoard(BoardVO vo) {
		System.out.println("===> JDBC로 deleteBoard() 기능 처리");
		try {
			conn = JDBCUtill.getConnection();
			stmt = conn.prepareStatement(BOARD_DELETE);
			stmt.setInt(1, vo.getSeq());
			stmt.executeUpdate();
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtill.close(stmt, conn);
		}
	}
	
	//글 상세 조회
	public BoardVO selectBoard(BoardVO vo) {
		System.out.println("===> JDBC로 selectBoard() 기능 처리");
		BoardVO board = null;
		try {
			conn = JDBCUtill.getConnection();
			stmt = conn.prepareStatement(BOARD_SELECT);
			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 (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtill.close(rs, stmt, conn);
		}
		return board;
	}
	
	//글 목록 조회
	public List<BoardVO> selectBoardList(BoardVO vo){
		System.out.println("===> JDBC로 selectBoardList() 기능 처리");
		List<BoardVO> boardList = new ArrayList<BoardVO>();
		try {
			conn = JDBCUtill.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 (SQLException e) {
			e.printStackTrace();
		} finally {
			JDBCUtill.close(rs, stmt, conn);
		}
		return boardList;
	}
	
}

7. Service 인터페이스 작성

방금 만든 BoardDAO에서 Alt+Shift+T 를 누르고 Extract Interface를 선택합니다.
Interface Name을 BoardService로 지정하고 함수들을 모두 체크해준 뒤 Generate @Override annotation을 체크 해제합니다.
생성된 interface 파일을 biz.board 아래로 이동시킵니다. 또한 BoardDAO에 추가된 implements BoardService를 지워줍니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 selectBoard(BoardVO vo);

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

}

8. BoardServiceImpl 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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") //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 selectBoard(BoardVO vo) {

		return boardDAO.selectBoard(vo);
	}

	@Override
	public List<BoardVO> selectBoardList(BoardVO vo) {

		return boardDAO.selectBoardList(vo);
	}

}

9. ApplicationContext에 스캔 추가하기

ApplicationContext.xml에서 Context namespace를 추가합니다.
그리고 <context:component-scan base-package=”com.springbook.biz”/> 를 beans 태그 사이에 넣어주면 끝!

10. BoardServiceClient 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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.selectBoardList(vo);
		for (BoardVO board : boardList) {
			System.out.println("---> " + board.toString());
		}
		
		// 5. Spring 컨테이너 종료
		container.close();
	}

}

아직 웹페이지를 작성하지 않았기 때문에 java Application으로 작성이 잘 되었는지 확인합니다.
getter-setter

댓글남기기