본문 바로가기
WEB/Spring

[Spring] Spring MyBatis + 예제 실습

by 댕꼬 2022. 4. 25.
728x90

Spring MyBatis 


MyBatis 

: MyBatis는 Java Object와 SQL문 사이의 자동 Mapping기능을 지원하는 ORM Framework이다

 

 

MyBatis 특징

 

- 쉬운 접근성과 코드의 간결함

: 가장 간단한 persistence framework로, XML형태로 서술된 JDBC코드라 생각해도 될 만큼 JDBC의 모든기능을 대부분 제공하면서 복잡한 JDBC의 코드를 걷어내었다.

수동적인 parameter설정과 Query결과에 대한 mapping구문을 제거하였다.

 

- SQL문과 프로그래밍 코드의 분리

: SQL변경이 있을때마다 자바코드를 수정하거나 컴파일 하지 않아도 된다.

 

- 다양한 프로그래밍 언어로 구현가능

: Java, C#, .NET, Ruby 등등

 

 

MyBatis Spring

 

MyBatis의 Data Access Layer

 

MyBatis의 주요 Component

파일 설명
MyBatis 설정파일
(sqlMapConfig.xml)
DB의 접속주소정보나 객체의 alias, Mapping파일 경로 등 고정된 환경정보를 설정
SqlSessionFactory
Builder
MyBatis 설정 파일을 바탕으로 SqlSessionFactory를 생성
SqlSessionFactory SqlSession을 생성
SqlSession 핵심적인 역할을 하는 class로 SQL실행이나 Transaction관리를 실행
SqlSession오브젝트는 Thread-Safe하지 않으므로 thread마다 필요에 따라 생성
mapping파일 
(member.xml)
SQL문과 ORMapping을 설정

MyBatis의 주요 Component

MyBatis-Spring의 주요 Component

파일 설명
MyBatis 설정파일
(sqlMapConfig.xml)
Dto 객체의 정보를 설정한다 (Alias)
SqlSessionFactory
Bean
MyBatis 설정 파일을 바탕으로 SqlSessionFactory를 생성
Spring Bean으로 등록해야 한다.
SqlSessionTemplete 핵심적인 역할을 하는 class로 SQL실행이나 Transaction관리를 실행
SqlSession interface를 구현하며 Thread-Safe하다
Spring Bean으로 등록해야 한다.
mapping파일 
(member.xml)
SQL문과 ORMapping을 설정
Spring Bean설정파일
(beans.xml)
SqlSessionFactoryBean을 Bean에 등록할 때 DataSource정보와 MyBatis Config파일정보, Mapping파일의 정보를 함께 설정함.
SqlSessionTemplate을 Bean으로 등록

MyBatis-Spring의 주요 Component

 

 

Mapper Interface

: Mapper Interface는 mapping파일에 기재된 SQL을 호출하기 위한 Interface

 

>>Mapper Interface를 사용하지 않으면 

- SQL을 호출하는 프로그램은 SqlSession의 method의 argument에 문자열로 namespace+"."+SQL  ID로 지정

- 문자열로 지정하기 때문에 오타에 의한 버그가 생기거나 IDE에서 제공하는 code assist를 사용할 수 없다.

 

>> Mapper Interface를 사용할 경우

-  UserMapper Interface는 개발자가 작성한다.

- packagename+"."+InterfaceName+"."+methodName이 namespace+"."+SQL ID가 되도록 namespace와 SQL ID를 설정해야  한다.

- namespace의 속성에는 package를 포함한 Mapper Interface의 이름을 작성

- SQL ID에는 mapping하는 method의 이름을 지정

 

 

MyBatis와 Spring의 연동

 

1. MyBatis Spring 연동 라이브러리 의존관계 설정

- MyBatis를 스프링과 연동하기 위해서는 MyBatis에서 제공하는 Spring연동 라이브러리가 필요하다.

 

2. DataSource설정 (root-context.xml)

- 스프링 환경 설정파일에 데이터소스를 설정한다.

- 데이터소스는 dataSource아이디를 가진 빈으로 데이터베이스 연결정보를 가진 객체

3. 트랜잭션 관리자 설정 (root-context.xml)

- transactionManager 아이디를 가진 빈은 트랜잭션을  관리하는 객제

- MyBatis는 JDBC를 그대로 사용하기 때문에 DataSourceTransactionManager타입의 빈을 사용

- tx:annotation-driven요소는 트랜잭션 관리방법을 어노테이션으로 선언하도록 설정

- 스프링은 메소드나  클래스에 @Transactional이 선언되어 있으면 AOP를 통해 트랜잭션을 처리

 

 

4. SqlSessionFactoryBean 설정 (root-context.xml)

- 스프링에서 SqlSessionFactory 객체를  생성하기 위해서는 SqlSessionFactoryBean을 빈으로 등록해야 함

5. mapper 빈 등록

- Mapper 인터페이스를 사용하기 위해서  mapper파일의 경로를 알려줌

6. MyBatis Configuration 파일 예시

- DB접속 정보 및 Mapper관련 설정은 스프링 빈으로 등록하여 관리 

 

7. 데이터 접근객체 구현 (DAO)

- 데이터 접근 객체는 특정 기술을 사용하여 데이터 저장소에 접근하는 방식을 구현한 객체

- @Repository는 데이터 접근 객체를 빈으로 등록하는 어노테이션

- @Autowired 어노테이션을 통해 사용하려는 Mapper 인터페이스를 데이터접근객체와 의존관계 설정

 

 

 

 

Spring Framework기반 사용자정보 관리 애플리케이션


MyBatis를 통해 실제 사용자등록, 사용자목록 전체조회, 사용자이름 검색기능을 제공하는 프로그램 구현

 

요구사항

 

- pom.xml에 Mybatis에 필요한 의존성 추가

- UserRepoImpl.java 삭제

- User.xml에서 UserRepo에서 선언한 메서드를sql문으로 매핑

- root-context.xml에 빈 등록 (DataSource, SqlSessionFactory, Mapper, Dto)과 namespace선언 

- 사용자 등록 및 검색 위한 view페이지들  수정

- UserServiceImpl메서드 완성

- 위 기능들을 수행할 수 있도록 UserController 수정

 

<참고>DB정보

 

 

 

 

 

 

pom.xml

mybatis사용에 필요한 의존성을 아래와 같이 추가한다.

user.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
	"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!-- name space는 UserRepo의 fully qualified name으로 설정한다. -->
<mapper namespace="com.ssafy.hw.model.repo.UserRepo">

	<!-- 사용자 정보를 저장한다. id는 repo클래스의 메소드 이름과 일치시킨다. -->
	<!-- <insert id="insert" parameterType="com.ssafy.hw.dto.User"> -->
	<!--  insert int 테이블명 [(컬럼명1,컬럼명2)]  values (데이터1,데이터2) 
	
	
	     INSERT INTO users
		VALUES(#{id}, #{password}, #{name}, #{email}, #{age}, #{img} )


	     INSERT INTO users  (id,password,name,email,age)
		VALUES(#{id}, #{password}, #{name}, #{email}, #{age} )
	
	  -->
	<insert id="insert" parameterType="User">
		INSERT INTO user
		VALUES(#{id}, #{password}, #{name}, #{email}, #{age}, #{img} )
	</insert>
	
	<!-- 사용자 정보를 삭제한다. -->
	<delete id="delete" parameterType="String">
		DELETE FROM user
		WHERE id = #{id}
	</delete>
	
	<!-- 사용자 정보를 수정한다. -->
	<update id="update" parameterType="user"  >
		UPDATE user
		SET password = #{password} , name = #{name} , email = #{email}, age = #{age}
		WHERE id = #{id}
	</update>
	
	<!-- 사용자를 id로 검색하여 조회한다. id는 repo클래스의 메소드 이름과 일치시킨다. -->
	<select id="searchById" parameterType="string"
		resultType="user">
		SELECT *
		FROM user WHERE id = #{id}
	</select>

	<!-- 사용자 이름으로 검색하여 조회한다. id는 repo클래스의 메소드 이름과 일치시킨다. -->
	<select id="searchByName" parameterType="String"
		resultType="User">
		SELECT *
		FROM user WHERE name LIKE
		CONCAT('%',#{name},'%')
	</select>

	<!-- 모든 사용자 정보를 검색한다. id는 repo클래스의 메소드 이름과 일치시킨다. -->
	<select id="selectAll" resultType="User">
		SELECT * FROM user
	</select>
</mapper>

 

root-context.xml

mybatis사용에 필요한 환경설정을 추가한다.

 

index.jsp
- 검색을 위한 폼을 추가한다. (이름검색, 아이디검색)

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SSAFY 사용자 관리</title>
</head>
<body>
	<div class="container">
		<h1>사용자 관리</h1>
		<form action="searchname" method="get">
			이름검색 : <input type="text" name="name" placeholder="이름을 입력해주세요.">
			<input type="submit" value="검색">
		</form>
		<br>
		<form action="searchid" method="get">
			아이디검색 : <input type="text" name="id" placeholder="id을 입력해주세요.">
			<input type="submit" value="검색">
		</form>
		<hr>
		<ul>
			<li><a href="./regist">사용자 등록</a>
			<li><a href="./list">사용자 목록</a>
		</ul>
	</div>
</body>
</html>

index.jsp

 

UserController.java

package com.ssafy.hw.controller;

import java.io.File;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.ssafy.hw.dto.User;
import com.ssafy.hw.model.service.UserService;

// 이 클래스가 컨트롤러 임을 어노테이션으로 설정, 컴포넌트 스캔을 통해 빈으로 등록
@Controller
public class UserController {
	
	// 서비스 주입
	@Autowired
	UserService service;
	
	@Autowired
	ResourceLoader resLoader;

	
	@GetMapping({ "/", "/index" })
//	@RequestMapping(value ={ "/", "/index" }, method = RequestMethod.GET )
	public String showIndex() {
		return "index";
	}

	@GetMapping("/regist")
	public String showRegistForm() {
		return "regist";
	}

	@PostMapping("/regist")
	public ModelAndView doRegist(User user, @RequestParam("userImg") MultipartFile file) throws Exception {
		ModelAndView mav = new ModelAndView();

		Resource res = resLoader.getResource("resources/upload");

		if (file != null && file.getSize() > 0) {
			user.setImg(file.getOriginalFilename());
			file.transferTo(new File(res.getFile().getCanonicalPath() + "/" + user.getImg()));
		}
		// 사용자 정보 등록
		service.insert(user);
		mav.setViewName("regist_result");
		// 전달할 객체
		mav.addObject("user", user);
		return mav;
	}

	@GetMapping("/list")
	public ModelAndView showList() {
		List<User> list = service.selectAll();
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("list");
		mav.addObject("users", list);
		return mav;
	}
	
	@GetMapping("searchname")
	public ModelAndView showSearchModelNameList(String name) {
		List<User> list = service.searchByName(name);
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("list");
		mav.addObject("users", list);
		return mav;
	}

	@GetMapping("searchid")
	public ModelAndView showSearchModelidList(String id) {
		User user = service.searchById(id);
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("list");
		mav.addObject("user", user);
		return mav;
	}
	
	@PostMapping("/update") //URL분석
	public ModelAndView doUpdate(User user) {
		service.update(user);
		
		List<User> list = service.selectAll();
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("list");
		mav.addObject("users", list);
		return mav;
	}
	
	@GetMapping("/delete")
	public ModelAndView doDelete(String id) {
		service.delete(id);
		
		List<User> list = service.selectAll();
		
		ModelAndView mav = new ModelAndView();
		mav.setViewName("list");
		mav.addObject("users", list);
		return mav;
	}
}

 

list.jsp

-UserController에서 받은 데이터를 화면에 출력한다.

- name검색의 경우, list로 전달되기때문에 forEach를 사용

- id검색의 경우, id는 고유값이기 때문에 User객체 단 하나만 전달된다.

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SSAFY 사용자 관리</title>
<style>
</style>
</head>
<body>
	<h1>사용자 목록</h1>
	<c:if test="${!empty users}">
		<%-- request 영역에 users로 등록된 자료를 반복문을 이용해 출력한다. --%>
		<c:forEach items="${users }" var="user" varStatus="vs">
			<form method="post" action="update" accept-charset="UTF-8">
				<table id="user-list">
					<c:if test="${vs.index eq 0 }">
						<thead>
							<tr>
								<th>아이디</th>
								<th>비밀번호</th>
								<th>이름</th>
								<th>이메일</th>
								<th>나이</th>
								<th></th>
								<th></th>
							</tr>
						</thead>
					</c:if>
					<tbody>
						<tr>
							<td><input type="text" name="id" id="id" value="${user.id }" /></td>
							<td><input type="password" name="password" id="password" /></td>
							<td><input type="text" name="name" id="name"
								value="${user.name }" /></td>
							<td><input type="email" name="email" id="email"
								value="${user.email }" /></td>
							<td><input type="number" name="age" id="age"
								value="${user.age }" /></td>
							<td><input type="submit" value="수정" /></td>
							<td><button type="button"
									onclick="location.href='./delete?id=${user.id}'">삭제</button></td>
						</tr>
					</tbody>
				</table>
			</form>
		</c:forEach>
	</c:if>
	
	<c:if test="${!empty user}">
			<form method="post" action="update" accept-charset="UTF-8">
				<table id="user-list">
						<thead>
							<tr>
								<th>아이디</th>
								<th>비밀번호</th>
								<th>이름</th>
								<th>이메일</th>
								<th>나이</th>
								<th></th>
								<th></th>
							</tr>
						</thead>
					<tbody>
						<tr>
							<td><input type="text" name="id" id="id" value="${user.id }" /></td>
							<td><input type="password" name="password" id="password" /></td>
							<td><input type="text" name="name" id="name"
								value="${user.name }" /></td>
							<td><input type="email" name="email" id="email"
								value="${user.email }" /></td>
							<td><input type="number" name="age" id="age"
								value="${user.age }" /></td>
							<td><input type="submit" value="수정" /></td>
							<td><button type="button"
									onclick="location.href='./delete?id=${user.id}'">삭제</button></td>
						</tr>
					</tbody>
				</table>
			</form>
	</c:if>


	<a href="index">홈으로</a>
	<a href="regist">추가등록</a>
</body>
</html>

list.jsp

 

728x90

댓글