Spring

[AOP] JDBC Template_DAO2

amoomar 2022. 4. 6. 11:35
반응형

 

 

포스팅의 목차는 다음과 같다.

1. what?_JDBC Template가 무엇인가
   1) 라이브러리 추가
   2) DAO의 생성

2. how?_적용 방법

 

 


 

 

1. what?_JDBC Template가 무엇인가

 

동일X, 유사한 코드의 반복인 패턴에서 자주 사용되는 방식을 템플릿 패턴이라고 한다.


템플릿 패턴 : 반복되거나 복잡한 알고리즘을 캡슐화 하여 재사용이 용이해진다.


JDBC Template: 유사하게 반복되는 DB관련 로직을 Template클래스에서 제공받고, 개발자는 설정과 설정값(SQL구분, 매핑)들만 신경쓰면 된다.

 

 


 


2. how?_적용 방법

 

1) 라이브러리 추가

"커넥션 확보"가 목적이다.

pom.xml에서 라이브러리를 추가한 후 로딩 후 Maven Dependencies에 정상적으로 jar파일이 추가되었는지 확인한다.

설정 확인

 

 

코드는 하단에 첨부하였다.

<!-- =============스프링 JDBC를 위한 DBCP================ -->
	<dependency>
		<groupId>commons-dbcp</groupId>
		<artifactId>commons-dbcp</artifactId>
		<version>1.4</version>
	</dependency>
<!-- ============================================== -->

 

 

 


 

 

2) DataSource생성

해당 개념은 오라클 사용시 개발자가 직접 확보하고 있었다. 데이터 베이스 커넥션을 위해 클릭해서 오라클을 작동시키는 행위와 같다.

사진 첨부

 

 

마찬가지로 JDBC Template이 DB연동을 하려면 커넥션을 확보해야하는데, JDBC Template가 사용할 DataSource를 스프링 컨테이너가 생성할 수 있도록 <bean>처리를 해주어야한다. 이외에도 model과 연관된 여러 방식들을 확인해 볼 예정인데, 앞으로 DB관련된 연동을 위해서는 필수적인 클래스이다.

추가

 

DataSource의 클래스 위치를 지정해주고, 연결 해제 메서드를 추가해준다. 이후 멤버변수로 속해있을 driverClassName과 url, username, password의 value를 설정해준다. 이러한 설정을 통해 setter를 통해 DI를 하고 있음을 알 수 있다.

 

코드는 아래와 같다.

 

	<!-- DataSource 설정 -->
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><!-- destroy-method로 연결해제 메서드 추가 -->
   	<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
   	<property name="url" value="jdbc:mysql://localhost:3306/hamdb"/>
   	<property name="username" value="root"/>
   	<property name="password" value="12341234"/>
   </bean>

 

 


 

 

3) DAO의 생성

방법은 두가지 이다.

1) JDBCTemplate의 모습을 정해놓은 클래스가 존재하는데, 이를 상속받아서 만드는 방법이 있다.
2) JDBCTemplate을 <bean>으로 생성하여 DI를 통해 만드는 방법이 있다.(내가 원래 만들어야하긴 하는데, 이미 갖고있는게 있을테니 그걸 가져다 사용한다.)

 

1번 방식은 잘 사용되지 않는 추세이기 때문에, 2번 방식의 내용만을 다루었다.

 

 

① <bean>생성과 DI

DI를 실행할때, dataSource로 이전에 생성해두었던 dataSource를 가져와 사용하는 것을 확인할 수 있다.

<?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"
	xmlns:aop="http://www.springframework.org/schema/aop"
	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
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">

	<!-- DataSource 설정 -->
   <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><!-- destroy-method로 연결해제 메서드 추가 -->
   	<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
   	<property name="url" value="jdbc:mysql://localhost:3306/hamdb"/>
   	<property name="username" value="root"/>
   	<property name="password" value="12341234"/>
   </bean>

	<!-- JDBCTemplate생성 -->
	<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

	<context:component-scan base-package="com.test.app"/>
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy><!-- 초기설정 -->

</beans>

 

 

만일 해당 코드에서 jdbcTemplate의 bean부분에서 오류가 발생한다면 pom.xml에 아래의 코드를 추가하여 해결해 볼 수 있다.

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>${org.springframework-version}</version>
</dependency>

 

 


 

② dao 내용 추가

DAO파일은 JdbcTemplate를 멤버변수로 둔다. 이때 @Autowired를 활용하여 멤버변수가 DI되도록 한다. 또한 해당 클래스의 초기화 또한 @Repository를 통해 실시한다.(이때 기존에 사용되던 dao의 repository는 삭제한다.)

 

sql문을 상단에 배치하여 각 메서드에 sql문과 삽입할 vo를 설정해주어야 한다.

package com.test.app.board.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.test.app.board.BoardVO;

@Repository("boardDAO2") // 컴포넌트 대신 ! DB와 관련된 작업을 하는 컴포넌트
public class BoardDAO2 {
	//Spring에서 제공하는 JDBC, 즉 JDBCTemplate
	
	@Autowired //타입을 확인하여 xml에 이게 존재하는지를 보러 감
	private JdbcTemplate jdbcTemplate;
	
	private final String BOARD_INSERT="insert into board (title, writer, content) values(?,?,?)";
	private final String BOARD_SELECTONE="select * from board where bid=?";
	private final String BOARD_SELECTALL="select * from board order by bid desc";
	private final String BOARD_UPDATE="update board set title=?,content=? where bid=?";
	private final String BOARD_DELETE="delete board where bid=?";
	private final String BOARD_SELECTALL_SEARCH_TITLE = "select * from board where title like '%'|| ? ||'%'";
	private final String BOARD_SELECTALL_SEARCH_WRITER = "select * from board where writer like '%'|| ? ||'%'";
	private final String BOARD_SELECTALL_SEARCH_CONTENT = "select * from board where content like '%'|| ? ||'%'";
	
	public void insertBoard(BoardVO vo) {
		jdbcTemplate.update(BOARD_INSERT, vo.getTitle(), vo.getWriter(), vo.getContent());
	}

	public BoardVO getBoard(BoardVO vo) {
		Object[] args= {vo.getBid()};
		return jdbcTemplate.queryForObject(BOARD_SELECTONE,args, new BoardRowMapper()); //검색결과가 한개이므로
	}

	public List<BoardVO> getBoardList(BoardVO vo) {
		return jdbcTemplate.query(BOARD_SELECTALL, new BoardRowMapper()); //검색결과가 두개 이상이므로
	}

	public void updateBoard(BoardVO vo) {
		Object[] args= {vo.getTitle(), vo.getContent(), vo.getBid()};
		jdbcTemplate.update(BOARD_UPDATE, args);
	}

	public void deleteBoard(BoardVO vo) {
		jdbcTemplate.update(BOARD_DELETE, vo.getBid());
	}
}


// RowMapper
class BoardRowMapper implements RowMapper<BoardVO>{

	@Override
	public BoardVO mapRow(ResultSet rs, int rowNum) throws SQLException {
	      BoardVO data=new BoardVO();
	      data.setBid(rs.getInt("bid"));
	      data.setContent(rs.getString("content"));
	      data.setTitle(rs.getString("title"));
	      data.setWriter(rs.getString("writer"));
	      return data;
	}
	
}

 

이때, jdbcTemplate에 활용되고있는 메서드와 RowMapper에 대한 내용을 정리해보았다.

 

 

 

 

 JDBC Template에서 사용하는 메서드

 

 

1) update() - executeupdate()와 같다고 볼 수 있다.
INSERT, UPDATE, DELETE를 사용하기 위해서는 ?가 필요하다. 해당 값을 어떻게 전달할 수 있을까?

- 인자를 쭉 연결하는 방법 : jdbcTemplate.update(SQL, vo.getXXxx(), vo.getXXxxx(),...);
- 아규먼트로 한 번에 연결하는 방법: Object[] args={vo.getXXxx(), vo.getXXxxx(),...} / jdbcTemplate.update(SQL, args);

2) queryForInt() - executequery()와 같다고 볼 수 있다.
SELECT류의 사용을 위해 사용되는 메서드이다. 정수 output에 대해 사용한다.
SELECT : select count(*) from 테이블명 where 조건절;

3) queryForObject() - executequery()
SELECT류의 사용을 위해 사용되는 메서드이다. 모든 output에 대해 사용한다. 단, 아웃풋이 반드시 한개이다.
SELECT: select * from 테이블명 where 조건절;
⚽︎검색결과가 없거나, 두개 이상이면 예외 발생 ex) 로그인
검색결과를 자바객체(vo)로 변경해주는 설정이 필요한데, RowMapper가 그 설정이다.


*) RowMapper : 어떤 테이블의 결과를 어떤 VO로 볼지에 대한 설정이다. 테이블:VO = 1:1이어야한다.

4) query()
SELECT류의 사용을 위해 사용되는 메서드이다. 검색 결과가 여러개일때(return이 List일때) 사용된다. RowMapper를 검색 결과만큼 사용한다.

 

 

 

MemberDAO2의 내용도 추가해보았다. 로그인이 실패하더라도 에러가 발생하지 않도록 구현하였다.

package com.test.app.member.impl;

import java.sql.ResultSet;
import java.sql.SQLException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import com.test.app.member.MemberVO;

@Repository("memberDAO")
public class MemberDAO2 {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	private final String MEMBER_INSERT="insert into member values(?,?,?,?)";
	private final String MEMBER_SELECTONE="select * from member where id=?";
	private final String MEMBER_SELECTALL="select * from member";
	private final String MEMBER_UPDATE="update member set password=?,name=?,role=? where id=?";
	private final String MEMBER_DELETE="delete from member where id=?";
	
	public MemberVO getMember(MemberVO vo) { //로그인 실패시 에러가 발생하지 않고 프로그램 정상 종료 되도록
		Object[] args= {vo.getId()};
		
		MemberVO data=null;
		
		try {
			data=jdbcTemplate.queryForObject(MEMBER_SELECTONE, args, new MemberRowMapper());
		}catch (Exception e) {
			System.out.println("MemberDAO2_에러발생");
		}
		
		return data;
	}

	public void insertMember(MemberVO vo) {
		Object[] args= {vo.getId(), vo.getName(), vo.getPassword(), vo.getRole()};
		jdbcTemplate.update(MEMBER_INSERT, args);
	}

	public void updateMember(MemberVO vo) {
		Object[] args= {vo.getPassword(), vo.getName(), vo.getRole(), vo.getId()};
		jdbcTemplate.update(MEMBER_UPDATE, args);
	}

	public void deleteMember(MemberVO vo) {
		jdbcTemplate.update(MEMBER_DELETE, vo.getId());
	}
}

// RowMapper
class MemberRowMapper implements RowMapper<MemberVO>{

	@Override
	public MemberVO mapRow(ResultSet rs, int rowNum) throws SQLException {
		MemberVO data=new MemberVO();
		data.setId(rs.getString("id"));
		data.setPassword(rs.getString("password"));
		data.setName(rs.getString("name"));
		data.setRole(rs.getString("role"));
		return data;
	}
	
}

 

 


 

 

 

반응형