1. JDBC란?
- JDBC는 Java의 데이터베이스 Access 기술
- Entity 클래스와 Annotation을 이용하는 최신 ORM 기술도 내부적으로 JDBC를 이용
- 간단한 SQL을 실행 할 때도 중복된 코드가 반복적으로 사용되는 Low level 기술로 인식
2. Data Access 계층
- Data Access 계층은 DAO 패턴을 적용, 비즈니스 로직과 데이터 액세스 로직을 분리하는 것이 원칙 (Service와 DAO)
- DataSource는 DB 커넥션 정보를 갖는 객체로 DB Connection Pool 기능 제공
- Spring Data는 데이터 저장소의 특수성을 유지하면서 데이터 접근을 위한 친숙하고 일관된 Spring 기반의 프로그래밍 모델을 제공하는 프로젝트
- Spring Data는 데이터 액세스와 관련된 많은 하위 프로젝트(module) 포함
MongoDB : NoSQL
Redis : 메모리 기반 DB
3. Spring Data JDBC
- Spring Data JDBC는 스프링 프레임워크에서 제공하는 JDBC 기반의 데이터 액세스 기술
- Spring Data JDBC는 기존 JDBC의 단점을 보완한 간결한 형태의 API 지원
기존의 JDBC 단점? 쿼리 하나 실행하는데에 너무 반복적인 일련의 코드가 필요함 - JdbcTemplate은 JDBC의 모든 기능을 지원하는 클래스
<< Spring data JDBC 관련라이브러리 추가 >>
- Spring JDBC
Spring 관련 라이브러리들이 5.3.30으로 맞춰져있으니 맞춰주는게 좋음
https://mvnrepository.com/artifact/org.springframework/spring-jdbc/5.3.30
- MySQL Connector/J
DBMS를 MySQL 사용하므로
https://mvnrepository.com/artifact/com.mysql/mysql-connector-j/8.1.0
- Apache Commons DBCP
https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2/2.10.0
하고 pom.xml, application.xml 설정파일 설정해주고, view 파일 생성
(이때 주의할점!!!! View Resolver 경로 잡아놓은데로 뷰 생성해야함)
---
각 컨트롤러별로 하나의 서비스가 나온다고 생각하면됨
(main같은 경우는 서비스가 필요없음... 페이지만 띄우는거라..)
어노테이션 각각 붙여주기
------------- User1Service
Service 싱글톤 필요X
어노테이션이 다 알아서 관리함
User1DAO라는 스프링객체를 컨테이너에 등록해서 주입받는 식
서비스에서 DAO 주입받아야하니까 어노테이션 제발 잊지말기.. @Autowired
------------- User1Controller
컨트롤러에서도 서비스 선언해주어야 함. 사용해야하니까.!
매개변수에 @ModelAttribute 생략되어있는것!
------------- User1DAO 설정
JdbcTemplate 주입받을건데 스프링 컨테이너(application.xml)에 생성되어있지 않음.
생성이 되어있어야 쟤네가 관리를해서 주입을 받을 수 있으니까.. 생성해주어야 함.
<bean> = 스프링 컨테이너가 관리하는 객체
따라서 빈을 만들어주어야 함.
<!-- DataSource 설정 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://<!-- ip주소 -->:3306/<!-- 테이블명 -->"/>
<property name="username" value="<!-- 사용자 -->"/>
<property name="password" value="<!-- 비밀번호 -->"/>
</bean>
<!-- JdbcTemplate 설정 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
DataSource를 설정해주고 이를 참조하여 JdbcTemplate을 설정해줌
우클릭 - Copy Qualified Name 해서 속성(<property>) 설정까지 해주면 된다.
======================================
--- 대망의 데이터 INSERT하기
- User1Controller.java
등록 뷰 페이지 띄우기
폼에서 전송한걸 받아서 리스트로 리다이렉트
- User1DAO.java
jdbc.update 혹은 jdbc.query 두가지를 대부분 사용하는데 Java/JSP JDBC와 마찬가지로 select 시에만 query, 나머지(insert, update, delete) 시에는 jdbc.update를 사용해주면 된다.
쿼리문을 먼저 작성해주고 쿼리 파라미터에 맞게 값을 넣어주어야 하는데 여러 값을 넣어야하므로 오브젝트 배열을 생성 후 jdbc.update(쿼리문, 바인딩)으로 전달해주면 끝
=================================================
--- list 출력하기 (SELECT)
- User1Controller.java
리스트 뷰 페이지를 띄워줄건데 서비스의 selectUser1s를 통해 리스트에 출력할 리스트를 받고,
뷰에서는 Model클래스를 이용해서 참조해야하기 때문에 model.addAttribute()
- User1DAO.java
원래는 ResultSet으로 반복문 돌려서 리스트에 저장 후 그 리스트를 반환했었는데 이를 RowMapper를 이용해서 처리한다.
- User1RowMapper.java
User1RowMapper 클래스 만들어주고
그리고
현재 행의 값을 매핑해주는데, ResultSet의 각 데이터 행을 매핑하기 위해 mapRow 메서드를 구현해야 한다.
=============================
--- 수정 (SELECT, UPDATE)
- User1Controller.java
수정페이지 클릭할 때 uid를 전송해서 수정할 uid를 받음.
수정 뷰 페이지 띄워주기
마찬가지로 뷰에서는 모델로 참조해서 값을 띄울거기때문에 model.addAttribute()
model.addAttribute(인자값) 하나면?! 저 타입(User1DTO)가 attributeName이 됨. (컴포넌트처럼 소문자로!) 즉, user1DTO
- User1DAO.java
바인딩해야할 값이 하나이므로 uid넣어주면되고, dto로 반환하기 위해 jdbc.queryForObject() 이용
- User1Controller.java
수정한 데이터들이 post방식으로 들어옴
UPDATE처리 후 리스트로 리다이렉트
- User1DAO.java
마찬가지로 바인딩해야하는 값이 여러개이므로 오브젝트 배열을 사용해야한다.
==============================
--- 삭제 (DELETE)
리스트에서 삭제를 클릭하면,
서비스-삭제 후, 리스트로 리다이렉트
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Ch05::index</title>
</head>
<body>
<h3>Ch05.Spring JDBC 실습</h3>
<h4>user1 실습</h4>
<a href="/Ch05/user1/register">user1 등록</a>
<a href="/Ch05/user1/list">user1 목록</a>
</body>
</html>
package ch05.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class MainController {
@GetMapping(value = {"/", "/index"})
public String index() {
return "/index";
}
}
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>user1::register</title>
</head>
<body>
<h3>user1 등록</h3>
<a href="/Ch05/index">메인</a>
<a href="/Ch05/user1/list">user1 목록</a>
<form action="/Ch05/user1/register" method="post">
<table border="1">
<tr>
<td>아이디</td>
<td><input type="text" name="uid"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>휴대폰</td>
<td><input type="text" name="hp"></td>
</tr>
<tr>
<td>나이</td>
<td><input type="number" name="age"></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="등록하기"></td>
</tr>
</table>
</form>
</body>
</html>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>user1::list</title>
</head>
<body>
<h3>user1 목록</h3>
<a href="/Ch05/index">메인</a>
<a href="/Ch05/user1/register">user1 등록</a>
<form action="/Ch05/user1/register" method="post">
<table border="1">
<tr>
<td>아이디</td>
<td>이름</td>
<td>휴대폰</td>
<td>나이</td>
<td>관리</td>
</tr>
<c:forEach var="user" items="${users}">
<tr>
<td>${user.uid}</td>
<td>${user.name}</td>
<td>${user.hp}</td>
<td>${user.age}</td>
<td>
<a href="/Ch05/user1/modify?uid=${user.uid}">수정</a>
<a href="/Ch05/user1/delete?uid=${user.uid}">삭제</a>
</td>
</tr>
</c:forEach>
</table>
</form>
</body>
</html>
<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>user1::modify</title>
</head>
<body>
<h3>user1 수정</h3>
<a href="/Ch05/index">메인</a>
<a href="/Ch05/user1/modify">user1 수정</a>
<form action="/Ch05/user1/modify" method="post">
<table border="1">
<tr>
<td>아이디</td>
<td><input type="text" name="uid" value="${user1DTO.uid}" readonly="readonly"></td>
</tr>
<tr>
<td>이름</td>
<td><input type="text" name="name" value="${user1DTO.name}"></td>
</tr>
<tr>
<td>휴대폰</td>
<td><input type="text" name="hp" value="${user1DTO.hp}"></td>
</tr>
<tr>
<td>나이</td>
<td><input type="number" name="age" value="${user1DTO.age}"></td>
</tr>
<tr>
<td colspan="2" align="right"><input type="submit" value="등록하기"></td>
</tr>
</table>
</form>
</body>
</html>
package ch05.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import ch05.dto.User1DTO;
import ch05.service.User1Service;
@Controller
public class User1Controller {
@Autowired
private User1Service service;
@GetMapping("/user1/register")
public String register() {
return "/user1/register";
}
@PostMapping("/user1/register")
public String register(User1DTO dto) {
service.insertUser1(dto);
return "redirect:/user1/list";
}
@GetMapping("/user1/list")
public String list(Model model) {
List<User1DTO> users = service.selectUser1s();
model.addAttribute("users", users);
return "/user1/list";
}
@GetMapping("/user1/modify")
public String modify(@RequestParam("uid") String uid, Model model) {
// 수정할 값 조회
User1DTO user = service.selectUser1(uid);
model.addAttribute(user);
return "/user1/modify";
}
@PostMapping("/user1/modify")
public String modify(@ModelAttribute User1DTO dto) {
service.updateUser1(dto);
return "redirect:/user1/list";
}
@GetMapping("/user1/delete")
public String delete(String uid) {
service.deleteUser1(uid);
return "redirect:/user1/list";
}
}
package ch05.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ch05.dao.User1DAO;
import ch05.dto.User1DTO;
@Service
public class User1Service {
@Autowired
private User1DAO dao;
public void insertUser1(User1DTO dto) {
dao.insertUser1(dto);
}
public User1DTO selectUser1(String uid) {
return dao.selectUser1(uid);
}
public List<User1DTO> selectUser1s() {
return dao.selectUser1s();
}
public void updateUser1(User1DTO dto) {
dao.updateUser1(dto);
}
public void deleteUser1(String uid) {
dao.deleteUser1(uid);
}
}
package ch05.dao;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Repository;
import ch05.dto.User1DTO;
@Repository
public class User1DAO {
@Autowired
private JdbcTemplate jdbc;
public void insertUser1(User1DTO dto) {
String sql = "INSERT INTO `user1` VALUES (?,?,?,?)";
// 쿼리파라미터 순서에 맞게 바인딩
Object[] params = {dto.getUid(), dto.getName(), dto.getHp(), dto.getAge()};
jdbc.update(sql, params);
}
public User1DTO selectUser1(String uid) {
String sql = "SELECT * FROM `user1` WHERE `uid`=?";
User1DTO dto = jdbc.queryForObject(sql, new User1RowMapper(), uid);
return dto;
}
public List<User1DTO> selectUser1s() {
String sql = "SELECT * FROM `user1`";
List<User1DTO> users = jdbc.query(sql, new User1RowMapper());
return users;
}
public void updateUser1(User1DTO dto) {
String sql = "UPDATE `user1` SET `name`=?, `hp`=?, `age`=? WHERE `uid`=?";
Object[] params = {
dto.getName(),
dto.getHp(),
dto.getAge(),
dto.getUid()
};
jdbc.update(sql, params);
}
public void deleteUser1(String uid) {
String sql = "DELETE FROM `user1` WHERE `uid`=?";
jdbc.update(sql, uid);
}
}
package ch05.dto;
public class User1DTO {
private String uid;
private String name;
private String hp;
private int age;
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHp() {
return hp;
}
public void setHp(String hp) {
this.hp = hp;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
package ch05.dao;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.springframework.jdbc.core.RowMapper;
import ch05.dto.User1DTO;
public class User1RowMapper implements RowMapper<User1DTO> {
@Override
public User1DTO mapRow(ResultSet rs, int rowNum) throws SQLException {
User1DTO dto = new User1DTO();
dto.setUid(rs.getString(1));
dto.setName(rs.getString(2));
dto.setHp(rs.getString(3));
dto.setAge(rs.getInt(4));
return dto;
}
}