티스토리 뷰

Spring

[Spring]JDBC 연동

dev23 2024. 8. 17. 15:31
반응형

JDBC(Java Database Connectivity)

- JDBC(Java Database Connectivity) 자바 데이터 접근 기술의 근간이라 정도로 대부분의 개발자가 쉽게 이해할 있어 많이 사용하는 데이터 액세스 기술이다.

- 그러나 시간이 지남에 따라 SQL문이 복잡해지면서 개발이나 유지관리에 어려움이 생기기 시작했다.

- 특히 Conneciton 객체 같은 공유 리소스를 제대로 처리해 주지 않으면 버그를 발생시키는 원인이 되곤 했다.

 

- 스프링에서 제공하는 JDBC 이러한 기존 JDBC 장점과 단순함을 유지하면서 단점을 보완했다.

- 간결한 API뿐만 아니라 확장된 JDBC 기능도 제공한다.

- 실제 개발 시에는 스프링 JDBC보다는 마이바티스나 하이버네이트 같은 DB연동 관련 프레임워크를 사용한다.

 

- 다음은 예제에 사용하는 파일 목록이다.

파일 설명
web.xml ContextLoaderListener 이용해 설정 XML 파일들을 읽어 들인다.
action-servlet.xml 스프링에서 필요한 여러 가지 빈을 설정한다.
action-dataSource.xml 스프링 JDBC 설정에 필요한 정보를 설정한다.
jdbc.properties DB 연결 정보를 저장한다.
action-service.xml 서비스 생성을 설정한다.

 

* WebContent/WEB-INF/ web.xml

 - 개의 XML 파일에서 모든 빈을 설정하면 복잡해서 관리하기 어려우므로 빈의 종류에 따라 XML 파일에

나누어 설정한다. 그러면 톰캣 실행 web.xml에서 스프링의 ContextLoaderListener를 이용해 빈 설정 XML 파일들을 읽어들인다.

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
	<listener>
		<listener-class>
			<!-- 여러 설정 파일을 읽어 들이기 위해 스프링의 ContextLoaderlistener를 설정한다. -->
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			<!-- 애플리케이션 실행 시 ContextLoaderListener로 해당 위치의 설정 파일을 읽어 들인다. -->
			/WEB-INF/config/action-service.xml
			/WEB-INF/config/action-dataSource.xml
		</param-value>
	</context-param>
	
	<servlet>
		<servlet-name>action</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>action</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>
</web-app>

 

* WebContent/WEB-INF/action-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

<!-- 컨트롤러에서ModelAndView 인자로 뷰이름이 반환되면 InternalResourceViewResolver의 프로퍼티 prefix 속성에 지정된 /test 폴더에서
	ModelAndView 인자로넘어온 뷰이름에 해당되는 JSP를 선택해 DispatcherServlet으로 보낸다. -->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
	<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
	<property name="prefix" value="/views/" />
	<property name="suffix" value=".jsp" />
</bean>

<!-- memberController 빈에 methodNameResolver 빈과 memberResolver 빈을 주입한다. -->
<bean id="memberController" class="com.spring.member.controller.MemberControllerImpl">
	<property name="methodNameResolver">
		<ref local="methodResolver" />
	</property> 
	<property name="memberService" ref="memberService" />
</bean>

<bean id="methodResolver" class="org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver">
	<property name="mappings">
		<props>
			<prop key="/member/listMembers.do">listMembers</prop>
			<prop key="/member/addMember.do">addMember</prop>
			<prop key="/member/memberForm.do">memberForm</prop>
			<prop key="/member/memberDetail.do">memberDetail</prop>
		</props>
	</property>
</bean>

<bean id="urlMapping" class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
	<property name="mappings">
		<props>
			<prop key="/member/*.do">memberController</prop>
		</props>
	</property>
</bean>
</beans>

 

* WebContent/WEB-INF/config/action-service.xml

- 해당 파일에서 memberService 빈을 설정하도록 한다.

- 데이터베이스와 연동할 때 필요한 memberDAO 빈을 주입하는 기능을 한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- memberService 빈의 memberDAO 속성에 memberDAO 빈을 주입한다. -->
    <bean id="memberService" class="com.spring.member.service.MemberServiceImpl">
        <property name="memberDAO" ref="memberDAO" />
    </bean>
</beans>

 

* WebContent/WEB-INF/config/action-dataSource.xml

 - 파일은 스프링에서 사용할 데이터베이스 연동 정보를 설정한다.

- 먼저 jdbc.properties 파일에서 DB 연결정보를 가져온 연결 정보를 이용해 스프링에서 제공하는
SimpleDriverDataSoure id dataSource 빈을 생성한다. 그리고 dataSource 빈을 memberDAO 빈으로 주입한다.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <!-- PropertyPlaceholderConfigurer 는 클래스 빈으로 등록하면 외부의 프로퍼티에 저장된 정보를 스프링 설정파일에서 사용할 수 있다. -->
    <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/config/jdbc.properties</value>
            </list>
        </property>
    </bean>

    <!-- jdbc.properties 파일의 4가지설정 정보로 스프링의 SimpleDriverDataSource 빈 생성 시 DB에 연결한다. -->
    <bean id="dataSource" class="org.springframework.jdbc.datasource.SimpleDriverDataSource">
        <property name="driverClass" value="${jdbc.driverClassName}" />
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <!-- 생성된 dataSource빈을 memberDAO 빈에 주입한다. -->
    <bean id="memberDAO" class="com.spring.member.dao.MemberDAOImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

 

* WebContent/WEB-INF/config/jdbc.properties

- 데이터베이스 연결 정보를 작성한다.

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/[DB]
jdbc.username=root
jdbc.password=pwd

 

 

JdbcTemplate을 이용한 회원 정보 조회

- JdbcTemplate을 이용한 회원 조회 과정은 다음과 같다.

회원 조회 과정

 

- DAO 클래스에서 실제 스프링의 JDBC 기능을 제공하는 클래스는 JdbcTemplat이다.

JdbcTemplate 클래스에서 제공하는 SQL 관련 메서드

기능 메서드
insert, update,  delete 관련 메서드 int update(String query)
int update(String query, Object[] args)
int update(String query, Object[] args, int[] argTypes)
select 기능 메서드 int queryForInt(String query)
int queryForInt(String query, Object[] args)
long queryForLong(String query)
int queryForLong(String query, Object[] args)
Object queryForObject(String query, Class requiredType)
List queryForList(String query)
List queryForList(String query, Object[] args)

* MemberController.java

- 자신의 속성 memberService 설정 파일에서 생성된 memberService 빈을 주입하기 위해 반드시 setter

구현해야 한다.

package com.spring.member.controller;

import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.multiaction.MultiActionController;

import com.spring.member.service.MemberService;

public class MemberControllerImpl extends MultiActionController{
        private MemberService memberService;
        public void setMemberService(MemberService memberService) {
                this.memberService = memberService;
        }
        
        public ModelAndView listMembers(HttpServletRequest request, HttpServletResponse response) throws Exception{
                String viewName = getViewName(request);
                List membersList = memberService.listMembers();
                ModelAndView mav = new ModelAndView(viewName);
                mav.addObject("membersList",membersList);
                return mav;
        }
        
        private  String getViewName(HttpServletRequest request) throws Exception {
              String contextPath = request.getContextPath();
              String uri = (String)request.getAttribute("javax.servlet.include.request_uri");
              if(uri == null || uri.trim().equals("")) {
                 uri = request.getRequestURI();
              }
              
              //http://localhost:port/member/listMember.do로 요청시
              int begin = 0;  //
              if(!((contextPath==null)||("".equals(contextPath)))){
                 begin = contextPath.length();  // 전체 요청명 의 길이를 구함
              }

              int end;
              if(uri.indexOf(";")!=-1){
                 end=uri.indexOf(";");  //요청 uri에 ';'가 있을 경우 ';'문자 위치를 구함
              }else if(uri.indexOf("?")!=-1){
                 end=uri.indexOf("?");   //요청 uri에 '?'가 있을 경우 '?' 문자 위치를 구함
              }else{
                 end=uri.length();
              }

              //http://localhost:8090/member/listMember.do로 요청시 먼저 '.do'를 제거한 http://localhost:8090/member/listMember를 구한 후,
              //다시 http://localhost:8090/member/listMember에서 역순으로 첫번째 '/' 위치를 구한 후, 그 뒤의 listMember를 구한다.
              String fileName=uri.substring(begin,end);
              if(fileName.indexOf(".")!=-1){
                 fileName=fileName.substring(0,fileName.lastIndexOf("."));  //요청명에서 역순으로 최초 '.'의 위치를 구한후, '.do' 앞에까지의 문자열을 구함
              }
              if(fileName.lastIndexOf("/")!=-1){
                 fileName=fileName.substring(fileName.lastIndexOf("/"),fileName.length()); //요청명에서 역순으로 최초 '/'의 위치를 구한후, '/' 다음부터의 문자열을 구함  
              }
              return fileName;
           }

}

 

* MemberSerivce.java

package com.spring.member.service;

import java.util.List;

public interface MemberService {
	public List listMembers();
}

 

* MemberServiceImpl.java

- 자신의 속성인 memberDAO 빈을 주입하기 위해 setter 구현한다.

package com.spring.member.service;

import java.util.List;

import com.spring.member.dao.MemberDAO;

public class MemberServiceImpl implements MemberService{
	private MemberDAO memberDAO;
	public void setMemberDAO(MemberDAO memberDAO) {
		this.memberDAO = memberDAO;
	}
	
	@Override
	public List listMembers() {
		return memberDAO.selectAllMembers();
	}
}

 

* MemberDAO.java

package com.spring.member.dao;

import java.util.List;

import org.springframework.dao.DataAccessException;

import com.spring.member.vo.MemberVO;

public interface MemberDAO {
	public List selectAllMembers();
	public int addMember(MemberVO memberVO) throws DataAccessException;
}

 

* MemberDAOImpl.java

- 자신의 속성 jdbcTemplate에 dataSource 빈을 주입하기 위해 setter를 이용한다.

package com.spring.member.dao;

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

import javax.sql.DataSource;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import com.spring.member.vo.MemberVO;

public class MemberDAOImpl implements MemberDAO{
	private JdbcTemplate jdbcTemplate;
	public void setDataSource(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	public List selectAllMembers() throws DataAccessException{
		String query = "select id, pwd, name, email, joinDate" +
						" from t_member" +
						" order by joinDate desc";
		List membersList = new ArrayList();
		
		// JdbcTemplate 클래스의 query() 메서드 인자로 select 문을 전달해 조회한 레코드의 개수만큼 MemberVO 객체를 생성한다.
		// 각 레코드의 값을 속성에 저장하고 다시 memberList에 저장한다.
		membersList = this.jdbcTemplate.query(query, new RowMapper<Object>(){
			@Override
			public Object mapRow(ResultSet rs, int rowNum) throws SQLException{
				MemberVO memberVO = new MemberVO();
				memberVO.setId(rs.getString("id"));
				memberVO.setPwd(rs.getString("pwd"));
				memberVO.setName(rs.getString("name"));
				memberVO.setEmail(rs.getString("email"));
				memberVO.setJoinDate(rs.getDate("joinDate"));
				return memberVO;
			}
		});
		return membersList;
	}
	
	public int addMember(MemberVO memberVO) throws DataAccessException {
		String id = memberVO.getId();
		String pwd = memberVO.getPwd();
		String name = memberVO.getName();
		String email = memberVO.getEmail();
		String query ="INSERT INTO t_member(id, pwd, name, email) VALUES (" +
						"'" + id + "' , " +
						"'" + pwd + "' , " +
						"'" + name + "' , " +
						"'" + email + "') " ;
		System.out.println(query);
		int result = jdbcTemplate.update(query);
		System.out.println(result);
		return result;
	}

}

 

* views/listMembers.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
	request.setCharacterEncoding("utf-8");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보</title>
</head>
<body>
	<table border="1" align="left" width="800" >
		<tr align="center" bgcolor="lightgreen">
			<td><b>아이디</b></td>
			<td><b>비밀번호</b></td>
			<td><b>이름</b></td>
			<td><b>이메일</b></td>
			<td><b>가입일</b></td>
		</tr>
		<c:forEach var="member" items="${membersList }">
			<tr align="center">
				<td>${member.id }</td>
				<td>${member.pwd }</td>
				<td>${member.name }</td>
				<td>${member.email }</td>
				<td>${member.joinDate }</td>
		</c:forEach>
	</table>
</body>
</html>

 

- 코드 작성 후 /member/listMembers.do 로 요청해 본다.

회원 정보 리스트

- 테이블 및 데이터 추가 관련 정보는 다음 글을 참고한다.

https://dev1023.tistory.com/71

 

서블릿 - 비즈니스 로직 처리

- 서블릿 비즈니스 처리 작업이란 서블릿이 클라이언트로부터 요청을 받으면 그 요청에 대해 작업을 수행하는 것을 의미한다.- 웹 프로그램에서 대부분의 비즈니스 처리 작업은 DB 연동 관련 작

dev1023.tistory.com

 

- 실제 개발에서는 스프링의 JDBC보다는 마이바티스를 이용해서 DB와 연동한다.

반응형

'Spring' 카테고리의 다른 글

[Spring]스프링 애너테이션  (0) 2024.08.17
[Spring]MyBatis 연동하기  (0) 2024.08.17
[Spring]스프링 MVC  (0) 2024.08.17
[Spring]의존성 주입  (0) 2024.08.16
[Spring]스프링이란?  (0) 2024.08.16
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/11   »
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
글 보관함