- Outsider's Dev Story
- 흔한 개발자의 개발 노트
- 내 아이큐 80, 너도 80, 둘이 합쳐 160 - 내…
- 조대협의 블로그
- 자바캔(Java Can Do IT) / 최범균 님
- Sangon, Han – 개발자; 읽고 생각하고 쓰고 …
- The Evolution of the Web
- NAVER D2
- Dashboard - SLiPP
- ITWorld Korea - 테크놀로지 리더를 위한 글…
- OKKY - All That Developer
- 웹Frameworks
- 오픈튜토리얼스
- 위키독스 / 온라인 책 제작 공유 플랫폼 서비스
- 블로터
- IT OnAir
- 한 처음에 / 백창92
- Divide my knowledge / 완프최
- SERI.org
Bigfat
[Spring] 스프링이 지원하는 JdbcTemplate 사용하기 (게시판 구현) 본문
스프링 프레임워크가 지원하는 JdbcTemplate을 사용해보자
스프링이 제공하는 JdbcTemplate은 데이터베이스 접근 정보를 클래스에 담지 않는다. 그러므로 더이상 기존 프로젝트의 OracleDBConnector클래스는 필요가 없으며, **DaoImpl클래스에서 메서드마다 커넥션을 얻지 않아도 된다. 스프링은 이러한 **Template클래스와 같이 다양한 API를 제공하는데, 이를 PSA(Portable Service Abstractions, 쉬운 서비스 추상화) 기술이라고 한다(참고1).
우선 pom.xml에 아래와 같이 spring-jdbc에 대한 의존성을 추가한다. 이때 주의할 점은 스프링에 관련된 jar파일들의 버전은 항상 일치해야 한다. 그렇지 않으면 에러가 발생하니 유의하도록 하자. 아래와 같이 작성하면 <version>값을 pom.xml 상단부에 <org.springframework-version>엘리먼트의 값인 '4.3.7.RELEASE'와 동일하게 적용할 수 있다.
1 2 3 4 5 6 7 8 9 10 11 12 | <!-- Spring JDBC --> <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc --> <!-- <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>4.3.7.RELEASE</version> </dependency> --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>${org.springframework-version}</version> </dependency> | cs |
이제 /WEB-INF/spring/root-context.xml을 아래와 같이 작성한다. 개발자가 직접 작성한 클래스들은 애노테이션(@Component, @Controller, @Service, @Repository)으로 Beans에 등록시켜줄 수 있지만, 스프링이 제공하는 클래스들을 사용하기 위해서는 xml에 직접 등록하여 사용하여야 한다. 물론 @Configuration을 사용하여 xml이 아닌 Java코드로 컨테이너를 설정할 수도 있고(참고2), 이는 스프링 4.0부터 지향하는 방법이라고 한다.
DriverManagerDataSource클래스를 id가 dataSource인 Bean객체로 Beans에 등록한다. <property>의 name, value속성을 사용해 데이터베이스 접근 정보를 설정해준다. 스프링 4.3.7 API 문서에서 DriverManagerDataSource클래스를 검색해보면 url, username, password를 파라미터로 하는 생성자와 setDriverClassName메서드가 있는 것을 확인할 수 있다. <property>의 name속성은 set메서드와 연관되어 있고, value속성은 set메서드의 파라미터가 되는 것이다. 예를 들면, <property name="driverClassName" value="core.log.jdbc.driver.OracleDriver">은 DriverManagerDataSource.setDriverClassName("core.log.jdbc.driver.OracleDriver")와 같은 기능을 하는 것이다. url, username, password의 set메서드는 DriverManagerDataSource의 부모클래스인 AbstractDriverBasedDataSource에 선언되어 있다.
DriverManagerDataSource는 DataSource인터페이스를 구현한다. API문서에서 JdbcTemplate클래스를 찾아보면 DataSource를 파라미터로 받는 생성자가 있는 것을 확인할 수 있다. 아래 코드와 비교해보면 JdbcTemplate클래스를 id가 jdbcTemplate인 Bean객체를 등록하고 <constructor-arg>엘리먼트로 JdbcTemplate의 생성자의 파라미터로 dataSource를 전달한다. 이런 방법으로 의존성을 주입하게 된다. <property>의 name속성으로 dataSource를 줬다. 위의 설명에 비추어봤을 때 JdbcTemplate은 setDataSource메서드를 가지고 있어야 한다. 역시나 JdbcTemplate의 부모클래스인 JdbcAccessor클래스에 setDataSource메서드가 선언되어 있다. 토할 것 같다. 다시 정리해야겠다...
참고로 Bean을 구분하는 방법으로는 id속성, name속성, class속성이 있고, Bean을 찾는 순서도 나열한 순서대로다.
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 | <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- Root Context: defines shared resources visible to all other web components --> <!-- DriverManagerDataSource는 커넥션(connection pool)을 지원하지 않는다. --> <!-- 그러므로 이후엔 Apache가 제공하는 BasicDataSource를 사용한다. --> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="core.log.jdbc.driver.OracleDriver"></property> <property name="url" value="jdbc:oracle:thin:@127.0.0.1:1521:XE"></property> <property name="username" value="kyou"></property> <property name="password" value="1234"></property> </bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <constructor-arg> <ref bean="dataSource"/> </constructor-arg> <!-- 첫 번째 방법 --> <property name="dataSource" ref="dataSource"></property> <!-- 두 번째 방법 --> <!-- <property name="dataSource"> <ref bean="dataSource"/> </property> --> </bean> </beans> | cs |
스프링 MVC 구조로 게시판 구현하기 프로젝트에서 BBSDaoImpl클래스만 아래와 같이 변경해준다. @Autowired 애노테이션으로 root-context.xml에서 bean객체에 등록해준 JdbcTemplate의 의존성을 주입해준다. 메서드마다 Connection을 얻어줄 필요도, 예외 처리를 해줄 필요도 없고, 코드가 이전보다 간결해진 것을 알 수 있다.
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 | package com.edu.bbs.dao; import java.util.ArrayList; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.BeanPropertyRowMapper; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.stereotype.Repository; import com.edu.bbs.common.LoginStatus; import com.edu.bbs.dto.BBSDto; @Repository public class BBSDaoImpl implements BBSDao { @Autowired private JdbcTemplate jdbcTemplate; StringBuffer query; @Override public ArrayList<BBSDto> selectArticles(int startRow, int endRow) { query = new StringBuffer(); query.append("SELECT bbs.* "); query.append(" FROM (SELECT rownum AS row_num, bbs.* "); query.append(" FROM (SELECT article_number, id, title, depth, hit, write_date "); query.append(" FROM bbs "); query.append(" ORDER BY group_id DESC, pos "); query.append(" ) bbs "); query.append(" ) bbs "); query.append(" WHERE row_num BETWEEN ? AND ?"); return (ArrayList<BBSDto>) jdbcTemplate.query(query.toString(), new Object[]{startRow, endRow}, new BeanPropertyRowMapper<BBSDto>(BBSDto.class)); } @Override public int getArticleTotalCount() { // Spring이 알아서 예외 처리해준다. return jdbcTemplate.queryForObject("SELECT count(*) AS total_count FROM bbs", Integer.class); } @Override public BBSDto selectArticle(String articleNumber) { return (BBSDto) jdbcTemplate.queryForObject("SELECT * FROM bbs WHERE article_number = ?", new Object[] {articleNumber}, new BeanPropertyRowMapper<>(BBSDto.class)); } @Override public int upHit(String articleNumber) { return jdbcTemplate.update("UPDATE bbs SET hit = hit + 1 WHERE article_number = ?", articleNumber); } @Override public int loginCheck(String id, String pw) { String result = jdbcTemplate.queryForObject("SELECT pw FROM users WHERE id = ?", new Object[]{id}, String.class); int loginStatus = 0; if(result != null && result != "") { if(pw.equals(result)) loginStatus = LoginStatus.LOGIN_SUCCESS; else loginStatus = LoginStatus.PASS_FAIL; } else loginStatus = LoginStatus.NOT_MEMBER; return loginStatus; } @Override public int signUpIdCheck(String inputId) { // TODO Auto-generated method stub return 0; } @Override public int insertArticle(BBSDto article) { return jdbcTemplate.update("INSERT INTO bbs VALUES(bbs_seq.nextval, ?, ?, ?, bbs_seq.currval, 0, 0, 0, sysdate, ?)", article.getId(), article.getTitle(), article.getContent(), article.getFileName()); } public int upPos(int groupId, int pos) { return jdbcTemplate.update("UPDATE bbs SET pos = pos + 1 WHERE group_id = ? AND pos > ?", groupId, pos); } @Override public int replyArticle(BBSDto article) { this.upPos(article.getGroupId(), article.getPos()); return jdbcTemplate.update("INSERT INTO bbs VALUES(bbs_seq.nextval, ?, ?, ?, ?, ?, ?, 0, sysdate, ?)", article.getId(), article.getTitle(), article.getContent(), article.getGroupId(), article.getDepth() + 1, article.getPos() + 1, article.getFileName()); } @Override public int updateArticle(BBSDto article) { return jdbcTemplate.update("UPDATE bbs SET title=?, content=? WHERE article_number=?", article.getTitle(), article.getContent(), article.getArticleNumber()); } @Override public int deleteArticle(String articleNumber) { return jdbcTemplate.update("DELETE FROM bbs WHERE article_number = ?", articleNumber); } } | cs |
JdbcTemplate보다는 MyBatis를 훨씬 더 많이 사용하겠지만(뿐만아니라 Hibernate, JPA도 있고), 스프링 클래스를 Bean객체에 등록하고 의존성을 주입하는 것을 더욱 이해하기 위해 이 글을 올린다. 완벽히 이해된 것은 아닌 것 같다.
[Spring 의 시작, 프레임워크의 구성요소와 동작원리 참고1]
[Spring java Code 기반 설정 참고2]
[[Spring 레퍼런스] 13장 JDBC를 사용한 데이터 접근 #1 참고]
[Getting List<String> using JdbcTemplate, Stack Overflow 참고]
'Java > web' 카테고리의 다른 글
[Spring] MyBatis 사용하기, MapperFactoryBean (게시판 구현) (0) | 2017.04.24 |
---|---|
[Spring] 스프링이 지원하는 iBATIS 사용하기 (게시판 구현) (1) | 2017.04.19 |
[Spring] 스프링 MVC 구조로 게시판 구현하기 (댓글 제외) (0) | 2017.04.18 |
[Spring] Overview of Spring MVC Architecture (0) | 2017.04.18 |
[Spring] 스프링 프로젝트 생성 및 웹 애플리케이션 실행하기 (0) | 2017.04.17 |