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의 주요 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-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으로 등록 |
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>
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>
'WEB > Spring' 카테고리의 다른 글
[Spring] SpringBoot (스프링부트) (0) | 2022.04.27 |
---|---|
[Spring] Spring REST API (0) | 2022.04.25 |
[Spring] Spring FileUpload + 예제 실습 (0) | 2022.04.24 |
[Spring] Spring Interceptor /Filter + 예제 실습 (0) | 2022.04.24 |
[Spring] Spring AOP + 예제 실습 (0) | 2022.04.24 |
댓글