웹에서 동적으로 CRUD를 할 수 있는 도서관리 프로그램을 스프링을 이용하여 만들고 몇 가지 기술을 정리해 볼 것이다.
https://suldenlion.tistory.com/113
프로그램의 기본 토대로 이전에 다룬 Servlet Library CRUD 프로그램을 가져올 것이다. (Servlet 프로그램을 Spring으로 Migration 할 것이다)
Servlet은 스프링의 메커니즘을 이해하기 위해 거쳐간 것이므로 스프링 방식을 이해하기 위한 목적으로 정리해 볼 것이다.
우선, 스프링 개발을 위한 일반적인 순서를 알아보겠다.
① 요구사항 및 설계
- 애플리케이션의 요구사항을 분석하고, 필요한 기능과 비즈니스 로직을 정의함. 이를 바탕으로 애플리케이션의 전체적인 아키텍처와 설계를 수립.
② 환경 구성
- 개발에 필요한 환경을 설정. JDK, IDE, 빌드 도구(Maven, Gradle), 데이터베이스 등의 환경 구성.
③ 프로젝트 생성
- 스프링 프로젝트 생성. 스프링 이니셜라이저(Spring Initializer)를 사용하거나, IDE에서 제공하는 기능을 활용하여 프로젝트를 생성함. 이때 필요한 의존성(라이브러리)를 선택하고, 프로젝트의 구조를 설정
④ 데이터 엑세스 계층 구현
- 데이터베이스와의 상호작용을 위한 데이터 엑세스 계층을 구현. JPA, JDBC, MyBatis 등을 활용하여 DB와의 연동을 처리하고, Entity와 Repository를 정의.
⑤ 비즈니스 로직 개발
- 애플리케이션의 비즈니스 로직을 개발. Service 클래스를 구현하고, 비즈니스 규칙에 따라 필요한 기능 구현
⑥ 컨트롤러 개발
- 스프링 MVC를 사용하여 웹 요청을 처리하는 Controller를 개발. 컨트롤러는 요청을 받아 비즈니스 로직을 호출하고, 응답을 생성하여 클라이언트에게 전달.
⑦ 뷰 개발
- 클라이언트에게 보여질 화면을 개발. 주로 HTML, CSS, JavaScript 등을 사용하여 웹 페이지를 작성하고, 스프링의 템플릿 엔진(JSP, Thymeleaf 등)을 사용하여 동적인 데이터를 표시할 수 있음
⑧ 테스트
- 단위 테스트와 통합 테스트 수행. JUnit, Mockito, Spring Test 라는 것 등을 활용하여 각각의 모듈과 기능을 테스트. 테스트를 통해 개발한 코드의 정확성과 동작 여부를 검증
⑨ 보안과 예외 처리
- 애플리케이션의 보안을 강화하고 예외처리를 구현. 스프링 시큐리티를 사용하여 인증과 권한 부여를 처리하고, 예외 처리 기능을 구현하여 애플리케이션의 안정성을 높임.
⑩ 배포
- 개발한 애플리케이션을 실제 환경에 배포. 서버 설정, DB 설정, 보안 설정 등을 확인하고, WAR 또는 JAR 파일을 생성하여 애플리케이션 배포
⑪ 유지보수
- 애플리케이션이 실제 운영 환경에서 동작하면서 발생하는 문제를 해결하고, 필요한 기능 추가 또는 변경을 수행함. 버그 수정, 보안 강화, 성능 최적화 등을 진행하며 애플리케이션을 지속적으로 관리.
위의 개발 순서를 준수하여 프로그램을 만들어 볼 것이다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
version 1
이전 프로그램과 같은 등록(Create), 리스트보기(Read), 수정(Update), 삭제(Delete) 프로그램이다.
이전 프로그램과 중복되는 로직적인 부분은 설명을 생략하고 스프링에서 추가로 사용된 기술 등을 정리해볼 것이다.
(이전 프로그램 → https://suldenlion.tistory.com/113)
Front 부분도 이전 프로그램과 같다.
달라진 부분은 HTML에서 디자인 역할을 하던 css 파일과 기능적 요소인 js 파일을 한데 묶어 중복을 제거하였다.
예시로 book_regits.jsp 파일이다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>도서 등록</title>
<link href="../resources/css/basic_style.css" rel="stylesheet" type="text/css">
<script type="text/javascript" src="https://code.jquery.com/jquery-latest.min.js"></script>
<script type="text/javascript" src="../resources/js/basic_go.js"></script>
</head>
<body>
<%-- <% String cmd = request.getParameter("cmd"); %>
<%=cmd.equals("success")?"<script>alert('hello');</script>":""%> --%>
<form action="" method="post" id="frm">
<table>
<tr><th colspan="4" id="form">도서등록</th></tr>
<tr><th>구분</th><th class="data_ui" colspan="2">데이터입력</th><th>비고</th></tr>
<tr>
<td>도서번호</td>
<td colspan="2">
<input type="text" id="book_seq" name="bookSeq" disabled="disabled">
</td>
<td id="message">자동생성</td></tr>
<tr>
<td>ISBN</td>
<td colspan="2">
<input type="text" id="isbn" name="isbn">
</td>
<td>
<input type="hidden" id="flag" value="false">
</td>
</tr>
<tr>
<td>도서명</td>
<td colspan="2">
<input type="text" id="book_title" name="title">
</td><td></td>
</tr>
<tr>
<td>저자/역자</td>
<td colspan="2">
<input type="text" id="author" name="author">
</td><td></td>
</tr>
<tr>
<td>출판일</td>
<td colspan="2">
<input type="text" id="publish_date" size="35" name="publishDate">
</td>
<td></td>
<tr>
<tr>
<td>도서위치</td>
<td colspan="2">
<select name="bookPosition" disabled="disabled">
<option value='BS'>--도서 위치--
<option value='BS-001' selected>일반서가
<option value='BS-002'>예약서가
<option value='BS-'>회원
</select>
</td>
<td>기본값삽입</td>
<tr>
<tr>
<td>도서상태</td>
<td colspan="2">
<select name="bookStaus" disabled="disabled">
<option value='BM'>--도서 상태--
<option value='BM-001' selected>도서대출서비스
<option value='BM-002'>도서수선
<option value='BM-003'>도서저장고
</select>
</td>
<td>기본값삽입</td>
<tr>
<tr>
<td colspan="4" id="sending">
<input type="submit" value="도서등록" id="go_book_regist">
<input type="submit" value="도서리스트" id="go_book_list">
</td>
</tr>
</table>
</form>
</body>
</html>
html 내에 있던 css, js 코드를 파일로 따로 빼서 아래와 같이 둔다.
다음은 basic_style.css와 basic_go.js의 내용이다.
@charset "UTF-8";
table, td, th {
border : 1px solid black;
border-collapse: collapse;
margin: 20px auto;
}
td {
width: 150px;
height: 50px;
padding: 5px;
font-size: 20px;
/* text-align: center; */
}
input , select {
font-size: 20px;
}
.data_ui {
/* width: 250px; */
height: 50px;
}
button {
font-size: 15px;
margin: 5px;
}
#sending {
text-align: center;
}
input.poster :disabled {
background: gray;
}
#form {
font-size: 30px;
}
#title {
height: 80px;
font-size: 50px;
}
$(document).ready(function(){
$('#go_view_update').on('click',function(){
alert($('#book_seq').val());
$('#frm').attr('action','view_update.do?bookSeq='+$('#book_seq').val());
$('#frm').submit();
});
$('#go_book_list').on('click',function(){
alert('go');
$('#frm').attr('action','list.do');
$('#frm').attr('method','get');
$('#frm').submit();
});
$('#go_book_regist').on('click',function(){
$('#frm').attr('action','regist.do');
$('#publish_date').val($('#publish_date').val()+" 00:00:00");
$('#frm').submit();
});
$('#go_book_update').on('click',function(){
$('#frm').attr('action','update.do?bookSeq='+$('#book_seq').val());
$('#publish_date').val($('#publish_date').val()+" 00:00:00");
$('#frm').submit();
});
});
컨트롤러를 보겠다.
package bitedu.bipa.book.controller;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import bitedu.bipa.book.service.QuizService;
import bitedu.bipa.book.vo.BookCopy;
@Controller("bookController1")
@RequestMapping("/basic")
public class BookController1 {
@Autowired
private QuizService quizService;
@RequestMapping(value="/list.do", method=RequestMethod.GET)
public ModelAndView list() {
System.out.println("basic");
ModelAndView mav = new ModelAndView();
ArrayList<BookCopy> list = quizService.searchBookAll();
mav.addObject("list",list);
mav.setViewName("./manager/book_list");
return mav;
}
@RequestMapping(value="/view_regist.do", method=RequestMethod.GET)
public ModelAndView viewRegist() {
ModelAndView mav = new ModelAndView();
mav.setViewName("./manager/book_regist");
return mav;
}
@RequestMapping(value="/view_detail.do", method=RequestMethod.GET)
public ModelAndView viewDetail(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
String bookSeq = request.getParameter("bookSeq");
BookCopy copy = quizService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_detail");
return mav;
}
@RequestMapping(value="/view_update.do", method=RequestMethod.POST)
public ModelAndView viewUpdate(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
String bookSeq = request.getParameter("bookSeq");
BookCopy copy = quizService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_update");
return mav;
}
@RequestMapping(value="/remove.do", method=RequestMethod.GET)
public ModelAndView remove(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
String bookSeq = request.getParameter("bookSeq");
boolean flag = quizService.removeBook(bookSeq);
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public ModelAndView update(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BookCopy copy = new BookCopy();
copy.setBookSeq(Integer.parseInt(request.getParameter("book_seq")));
copy.setIsbn(request.getParameter("isbn"));
copy.setTitle(request.getParameter("book_title"));
copy.setAuthor(request.getParameter("author"));
String date = request.getParameter("publish_date");
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date now = df.parse(date);
copy.setPublishDate(new Timestamp(now.getTime()));
} catch (ParseException e) {
e.printStackTrace();
}
boolean flag = quizService.modifyBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/regist.do", method=RequestMethod.POST)
public ModelAndView regist(HttpServletRequest request) {
ModelAndView mav = new ModelAndView();
try {
request.setCharacterEncoding("UTF-8");
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
}
BookCopy copy = new BookCopy();
copy.setIsbn(request.getParameter("isbn"));
copy.setTitle(request.getParameter("book_title"));
copy.setAuthor(request.getParameter("author"));
copy.setPublisher(request.getParameter("publisher"));
String date = request.getParameter("publish_date");
System.out.println(date);
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
Date now = df.parse(date);
copy.setPublishDate(new Timestamp(now.getTime()));
} catch (ParseException e) {
e.printStackTrace();
}
quizService.registBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
}
스프링 컨트롤러의 모습이다.
@Controller, @Autowired, @RequestMapping 등의 annotation을 볼 수 있다.
▶ @Controller
- @Controller 어노테이션은 Spring MVC 프로젝트에서 컨트롤러 클래스를 정의할 때 사용하며, 해당 클래스가 웹 요청을 처리하는 컨트롤러 역할을 수행함을 나타냄.
- @Controller 어노테이션이 지정된 클래스는 Spring 컨테이너에서 Bean으로 관리되며, 요청을 처리하는 메서드를 정의할 수 있음.
- 주로 사용자의 요청을 받아 비즈니스 로직을 수행하고, 적절한 뷰를 반환하여 응답을 생성하는 역할을 수행함.
▶ @Autowired
- @Autowired 어노테이션은 Spring Framework에서 의존성 주입(Dependency Injection)을 수행할 떄 사용됨.
- 이 어노테이션은 해당 필드, 생성자, 메서드의 매개변수, 설정 메서드 등에 붙여서 Spring이 해당 의존성을 자동으로 주입하도록 지정함.
- @Autowired를 사용하여 의존하는 객체를 주입받으면, Spring은 컨테이너 내에서 해당 타입의 Bean을 찾아서 자동으로 연결함.
- 주로 Service, Repository, 다른 Bean들과의 협력 관계를 맺을때 사용됨.
▶ @RequestMapping
- @RequestMapping 어노테이션은 Spring MVC 프로젝트에서 요청을 처리하는 메서드와 URL을 매핑할 때 사용됨.
- 이 어노테이션은 메서드 레벨 또는 클래스 레벨에서 사용할 수 있음.
- @RequestMapping 어노테이션을 지정하면 해당 메서드 또는 클래스가 지정된 URL 패턴과 매칭되는 요청을 처리함.
- value 속성을 사용하여 URL 패턴을 지정하고, method 속성을 사용하여 요청 방식을 제한할 수 있음.
- 주로 Controller의 요청 핸들러 메서드에 사용되며, 클라이언트의 요청에 대한 응답을 생성하는 역할을 수행함.
컨트롤러를 보면 @Controller 어노테이션을 사용하여 컨트롤러 역할을 한다는 것을 나타낸다. 어노테이션 안의 내용(클래스 명)은 생략가능한 것으로 보인다.
@RequestMapping에 "/basic"이라는 URL을 명시해주고 /book(= 컨텍스트 경로, 루트 경로) 다음 레벨에 해당하게 함
컨트롤러를 매핑해주기 위해서 웹을 띄울때 위와 같이 경로를 적어준다.
다음은 @Autowired된 서비스 객체이다.
QuizService라는 클래스와 연결해준다.
package bitedu.bipa.book.service;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import org.springframework.stereotype.Service;
import bitedu.bipa.book.vo.BookCopy;
@Service("quizService")
public class QuizService {
private ArrayList<BookCopy> list;
public QuizService() {
list = new ArrayList<BookCopy>();
list.add(new BookCopy(1,"PM0000037903","데이터베이스 개론과 실습","최승환",new Timestamp(new Date(2021-1900,12,23).getTime()),"BS-0001","BM-0001"));
list.add(new BookCopy(2,"PM0000037904","XML 완벽 정리","유시현",new Timestamp(new Date(2023-1900,1,28).getTime()),"BS-0001","BM-0001"));
list.add(new BookCopy(3,"PM0000037905","쉽게 배우는 스프링","허재승",new Timestamp(new Date(2023-1900,9,8).getTime()),"BS-0001","BM-0001"));
}
public boolean checkId(String id) {
boolean flag = false;
if(id.equals("admin")) {
flag = true;
}
return flag;
}
public boolean registBook(BookCopy copy) {
boolean flag = false;
copy.setBookSeq(list.size()+1);
copy.setBookPosition("BS-0001");
copy.setBookStaus("BM-0001");
list.add(copy);
return flag;
}
public ArrayList<BookCopy> searchBookAll(){
return this.list;
}
public boolean removeBook(String bookSeq) {
// TODO Auto-generated method stub
boolean flag = false;
int index = -1;
for(int i=0;i<list.size();i++) {
BookCopy copy = list.get(i);
if(copy.getBookSeq()==Integer.parseInt(bookSeq)) {
index = i;
flag = true;
break;
}
}
list.remove(index);
return flag;
}
public BookCopy findBook(String bookSeq) {
BookCopy copy = null;
for(int i=0;i<list.size();i++) {
copy = list.get(i);
if(copy.getBookSeq()==Integer.parseInt(bookSeq)) {
break;
} else {
copy = null;
}
}
System.out.println(copy);
return copy;
}
public boolean modifyBook(BookCopy copy) {
// TODO Auto-generated method stub
boolean flag = false;
BookCopy book = null;
for(int i=0;i<list.size();i++) {
book = list.get(i);
if(book.getBookSeq()==copy.getBookSeq()) {
list.set(i, copy);
flag = true;
}
}
return flag;
}
}
DB를 만들어 DAO를 통한 쿼리작업을 하는게 아닌 간단하게 ArrayList로 CRUD를 구현한 객체이다.
로직에 대한 설명은 생략하고 컨트롤러로 돌아가 보겠다.
메서드들과 매핑하는 어노테이션들을 보면 value에 "/~~~.do"라고 표현하였다.
초기 웹서비스의 경우 html, jsp, php 등의 웹 프로그래밍 언어의 물리적인 파일을 직접 호출하여 클라이언트 프로그램인 브라우저에 표시하기도 하였으나, 프레임워크가 적용이 되면서 요청과 응답을 분리하며 처리하고 있음. 보안이나 효과적인 비즈니스 처리를 위해 이런 방식을 쓰는 듯.
메서드는 리턴 타입이 ModelAndView인데, ModelAndView를 생성하여 객체 단위로 데이터를 add 시켜주고 페이지에 set해주어 리턴해준다.
서블릿의 setAttribute() 메서드와 getRequestDispatcher()에 해당하는 부분이라 보면 될 것 같다.
페이지 redirect 할 필요가 있는 경우는 위와 같이 setViewName()에 "redirect:..."으로 해준다.
Version1, Servlet에서 Spring으로 넘어온 것은 이 정도로 하고, version 2로 넘어가 보겠다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Version 2
version 1에서는 Client로 부터 데이터가 넘어올 때 메서드의 파라미터로 HttpServletRequest request가 넘어오고 getParameter를 하며 데이터를 얻어왔다. 그런 방식을 좀 수정하도록 하겠다.
package bitedu.bipa.book.controller;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
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.servlet.ModelAndView;
import bitedu.bipa.book.service.QuizService;
import bitedu.bipa.book.vo.BookCopy;
@Controller("bookController2")
@RequestMapping("extend")
public class BookController2 {
@Autowired
private QuizService quizService;
@RequestMapping(value="/list.do", method=RequestMethod.GET)
public ModelAndView list() {
ModelAndView mav = new ModelAndView();
ArrayList<BookCopy> list = quizService.searchBookAll();
mav.addObject("list",list);
mav.setViewName("./manager/book_list");
return mav;
}
@RequestMapping(value="/view_regist.do", method=RequestMethod.GET)
public ModelAndView viewRegist() {
ModelAndView mav = new ModelAndView();
mav.setViewName("./manager/book_regist");
return mav;
}
@RequestMapping(value="/view_detail.do", method=RequestMethod.GET)
public ModelAndView viewDetail(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = quizService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_detail");
return mav;
}
@RequestMapping(value="/view_update.do", method=RequestMethod.POST)
public ModelAndView viewUpdate(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = quizService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_update");
return mav;
}
@RequestMapping(value="/remove.do", method=RequestMethod.GET)
public ModelAndView remove(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
boolean flag = quizService.removeBook(bookSeq);
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
// SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// try {
// Date now = df.parse(date);
// copy.setPublishDate(new Timestamp(now.getTime()));
// } catch (ParseException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
boolean flag = quizService.modifyBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/regist.do", method=RequestMethod.POST)
public ModelAndView regist(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
System.out.println(copy);
quizService.registBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
}
version 1과는 크게 다른 것은 없고 Controller 메서드에 대한 매핑을 달리 해준 것과 메서드 호출시 넘어오는 데이터의 형태가 바뀐 것 정도이다.
@ModelAttribute("book") BookCopy copy 와 같이 BookCopy라는 객체에 어노테이션을 달아서 해당 객체의 필드를 메서드 내에서 set해줄 필요없이 필드들이 담겨서 넘어온다.
version 2는 간단하게 이정도이고 다음은 version 3이다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
version 3
다음은 서비스에서 ArrayList로 간단하게 테스트 한 것을 실제 DataBase 데이터로 해볼 것이다.
이 예제도 이전 서블릿에서 소개 했던 방식이라서 자세한 설명은 생략하도록 하겠다.
package bitedu.bipa.book.controller;
import java.io.UnsupportedEncodingException;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
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.servlet.ModelAndView;
import bitedu.bipa.book.service.BlmService;
import bitedu.bipa.book.service.QuizService;
import bitedu.bipa.book.vo.BookCopy;
@Controller("bookController3")
@RequestMapping("db")
public class BookController3 {
@Autowired
private BlmService blmService;
@RequestMapping(value="/list.do", method=RequestMethod.GET)
public ModelAndView list() {
System.out.println("extends");
ModelAndView mav = new ModelAndView();
ArrayList<BookCopy> list = blmService.searchBookAll();
mav.addObject("list",list);
mav.setViewName("./manager/book_list");
return mav;
}
@RequestMapping(value="/view_regist.do", method=RequestMethod.GET)
public ModelAndView viewRegist() {
ModelAndView mav = new ModelAndView();
mav.setViewName("./manager/book_regist");
return mav;
}
@RequestMapping(value="/view_detail.do", method=RequestMethod.GET)
public ModelAndView viewDetail(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_detail");
return mav;
}
@RequestMapping(value="/view_update.do", method=RequestMethod.POST)
public ModelAndView viewUpdate(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_update");
return mav;
}
@RequestMapping(value="/remove.do", method=RequestMethod.GET)
public ModelAndView remove(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
boolean flag = blmService.removeBook(bookSeq);
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
// SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// try {
// Date now = df.parse(date);
// copy.setPublishDate(new Timestamp(now.getTime()));
// } catch (ParseException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
boolean flag = blmService.modifyBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/regist.do", method=RequestMethod.POST)
public ModelAndView regist(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
System.out.println(copy);
blmService.registBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
}
Controller이다.
db라는 경로로 매핑한다.
package bitedu.bipa.book.service;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import bitedu.bipa.book.dao.BlmDAO;
import bitedu.bipa.book.vo.BookCopy;
@Service("blmService")
public class BlmService {
@Autowired
private BlmDAO dao;
// public BlmService() {
// dao = new BlmDAO();
// }
public boolean registBook(BookCopy copy) {
boolean flag = false;
flag = dao.insertBook(copy);
return flag;
}
public ArrayList<BookCopy> searchBookAll(){
ArrayList<BookCopy> list = null;
list = dao.selectBookAll();
return list;
}
public boolean removeBook(String bookSeq) {
boolean flag = false;
flag = dao.deleteBook(Integer.parseInt(bookSeq));
return flag;
}
public BookCopy findBook(String bookSeq) {
BookCopy copy = null;
copy = dao.selectBook(Integer.parseInt(bookSeq));
System.out.println(copy);
return copy;
}
public boolean modifyBook(BookCopy copy) {
boolean flag = false;
flag = dao.updateBook(copy);
return flag;
}
}
Service이다.
Service 어노테이션을 사용한다.
package bitedu.bipa.book.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import org.springframework.stereotype.Repository;
import bitedu.bipa.book.utils.ConnectionManager;
import bitedu.bipa.book.vo.BookCopy;
@Repository("blmDAO")
public class BlmDAO {
private ConnectionManager manager;
public BlmDAO() {
manager = ConnectionManager.getInstance();
}
public boolean insertBook(BookCopy copy){
boolean flag = false;
String sql1 = "insert into book_info values (?,?,?,?)";
String sql2 = "insert into book_copy(book_isbn) values (?)";
Connection con = manager.getConnection();
try {
con.setAutoCommit(false);
PreparedStatement pstmt = con.prepareStatement(sql1);
pstmt.setString(1, copy.getIsbn());
pstmt.setString(2, copy.getTitle());
pstmt.setString(3, copy.getAuthor());
pstmt.setTimestamp(4, copy.getPublishDate());
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
pstmt = con.prepareStatement(sql2);
pstmt.setString(1, copy.getIsbn());
affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
con.commit();
System.out.println("commit");
}
} else {
con.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
try {
con.rollback();
System.out.println("rollback");
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
con.setAutoCommit(true);
manager.closeConnection(null, null, con);
} catch (SQLException e) {
e.printStackTrace();
}
}
return flag;
}
public ArrayList<BookCopy> selectBookAll(){
ArrayList<BookCopy> list = null;
list = new ArrayList<BookCopy>();
BookCopy copy = null;
StringBuilder sb = new StringBuilder("select a.*, b.* from book_info a ");
sb.append("inner join book_copy b on a.book_isbn=b.book_isbn");
String sql = sb.toString();
Connection con = manager.getConnection();
PreparedStatement pstmt;
try {
pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
copy = new BookCopy();
copy.setIsbn(rs.getString(1));
copy.setTitle(rs.getString(2));
copy.setAuthor(rs.getString(3));
copy.setPublishDate(rs.getTimestamp(4));
copy.setBookSeq(rs.getInt(5));
copy.setBookPosition(rs.getString(6));
copy.setBookStaus(rs.getString(7));
list.add(copy);
}
manager.closeConnection(rs, pstmt, con);
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public boolean deleteBook(int parseInt) {
boolean flag = false;
String sql = "delete from book_copy where book_seq = ?";
Connection con = manager.getConnection();
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, parseInt);
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
}
manager.closeConnection(null, pstmt, con);
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
public BookCopy selectBook(int parseInt) {
BookCopy copy = null;
StringBuilder sb = new StringBuilder("select a.*, b.* from book_info a ");
sb.append("inner join book_copy b on a.book_isbn=b.book_isbn ");
sb.append("where b.book_seq = ?");
String sql = sb.toString();
Connection con = manager.getConnection();
PreparedStatement pstmt = null;
try {
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, parseInt);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
copy = new BookCopy();
copy.setIsbn(rs.getString(1));
copy.setTitle(rs.getString(2));
copy.setAuthor(rs.getString(3));
copy.setPublishDate(rs.getTimestamp(4));
copy.setBookSeq(rs.getInt(5));
copy.setBookPosition(rs.getString(6));
copy.setBookStaus(rs.getString(7));
}
manager.closeConnection(rs, pstmt, con);
} catch (SQLException e) {
e.printStackTrace();
}
return copy;
}
public boolean updateBook(BookCopy copy) {
boolean flag = false;
String sql = "update book_info set book_title = ?, book_author=?, book_published_date = ? where book_isbn = ?";
Connection con = manager.getConnection();
PreparedStatement pstmt = null;
System.out.println(copy);
try {
pstmt = con.prepareStatement(sql);
pstmt.setString(1, copy.getTitle());
pstmt.setString(2, copy.getAuthor());
pstmt.setTimestamp(3, copy.getPublishDate());
//pstmt.setInt(4, copy.getBookSeq());
pstmt.setString(4, copy.getIsbn());
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
}
manager.closeConnection(null, pstmt, con);
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
}
쿼리문을 이용해 DB에 접근하는 DAO 부분이다.
@Repository 어노테이션을 사용했다.
서블릿에서 소개한 Connection을 사용하여 DB 프로퍼티에 접근하는 방식이다.
ConnectionManager 클래스의 getConnection에 하드코딩으로 Driver와 jdbcURL을 명시해놓고 연결했다.
public Connection getConnection() {
Connection con = null;
String jdbcURL = "jdbc:mysql://localhost:3306/bitedu";
String driver = "com.mysql.cj.jdbc.Driver";
String id = "root";
String pwd = "1234";
try {
Class.forName(driver);
con = DriverManager.getConnection(jdbcURL,id,pwd);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return con;
}
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
version 4
version 4에서는 다른 방식으로 DB 프로퍼티에 접근할 것이다.
package bitedu.bipa.book.controller;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
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.servlet.ModelAndView;
import bitedu.bipa.book.service.BlmService2;
import bitedu.bipa.book.vo.BookCopy;
@Controller("bookController4")
@RequestMapping("springdb")
public class BookController4 {
@Autowired
private BlmService2 blmService;
@RequestMapping(value="/list.do", method=RequestMethod.GET)
public ModelAndView list() {
System.out.println("extends");
ModelAndView mav = new ModelAndView();
ArrayList<BookCopy> list = blmService.searchBookAll();
mav.addObject("list",list);
mav.setViewName("./manager/book_list");
return mav;
}
@RequestMapping(value="/view_regist.do", method=RequestMethod.GET)
public ModelAndView viewRegist() {
ModelAndView mav = new ModelAndView();
mav.setViewName("./manager/book_regist");
return mav;
}
@RequestMapping(value="/view_detail.do", method=RequestMethod.GET)
public ModelAndView viewDetail(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_detail");
return mav;
}
@RequestMapping(value="/view_update.do", method=RequestMethod.POST)
public ModelAndView viewUpdate(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_update");
return mav;
}
@RequestMapping(value="/remove.do", method=RequestMethod.GET)
public ModelAndView remove(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
boolean flag = blmService.removeBook(bookSeq);
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
// SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
// try {
// Date now = df.parse(date);
// copy.setPublishDate(new Timestamp(now.getTime()));
// } catch (ParseException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
boolean flag = blmService.modifyBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/regist.do", method=RequestMethod.POST)
public ModelAndView regist(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
System.out.println(copy);
blmService.registBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
}
컨트롤러이다. Service2에 @Autowired하여 사용한다.
package bitedu.bipa.book.service;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import bitedu.bipa.book.dao.BlmDAO;
import bitedu.bipa.book.dao.BlmDAO2;
import bitedu.bipa.book.vo.BookCopy;
@Service("blmService2")
public class BlmService2 {
@Autowired
private BlmDAO2 dao;
public boolean registBook(BookCopy copy) {
boolean flag = false;
flag = dao.insertBook(copy);
return flag;
}
public ArrayList<BookCopy> searchBookAll(){
ArrayList<BookCopy> list = null;
list = dao.selectBookAll();
return list;
}
public boolean removeBook(String bookSeq) {
boolean flag = false;
flag = dao.deleteBook(Integer.parseInt(bookSeq));
return flag;
}
public BookCopy findBook(String bookSeq) {
BookCopy copy = null;
copy = dao.selectBook(Integer.parseInt(bookSeq));
System.out.println(copy);
return copy;
}
public boolean modifyBook(BookCopy copy) {
boolean flag = false;
flag = dao.updateBook(copy);
return flag;
}
}
Service는 DAO2와 연결한다.
package bitedu.bipa.book.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import bitedu.bipa.book.utils.ConnectionManager;
import bitedu.bipa.book.vo.BookCopy;
@Repository("blmDAO2")
public class BlmDAO2 {
@Autowired
private DataSource dataSource;
public boolean insertBook(BookCopy copy){
boolean flag = false;
String sql1 = "insert into book_info values (?,?,?,?)";
String sql2 = "insert into book_copy(book_isbn) values (?)";
Connection con = null;
PreparedStatement pstmt = null;
System.out.println(copy);
try {
con = dataSource.getConnection();
con.setAutoCommit(false);
pstmt = con.prepareStatement(sql1);
pstmt.setString(1, copy.getIsbn());
pstmt.setString(2, copy.getTitle());
pstmt.setString(3, copy.getAuthor());
pstmt.setTimestamp(4, copy.getPublishDate());
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
pstmt = con.prepareStatement(sql2);
pstmt.setString(1, copy.getIsbn());
affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
con.commit();
System.out.println("commit");
}
} else {
con.rollback();
}
} catch (SQLException e) {
e.printStackTrace();
try {
con.rollback();
System.out.println("rollback");
} catch (SQLException e1) {
e1.printStackTrace();
}
} finally {
try {
con.setAutoCommit(true);
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
return flag;
}
public ArrayList<BookCopy> selectBookAll(){
ArrayList<BookCopy> list = null;
list = new ArrayList<BookCopy>();
BookCopy copy = null;
StringBuilder sb = new StringBuilder("select a.*, b.* from book_info a ");
sb.append("inner join book_copy b on a.book_isbn=b.book_isbn");
String sql = sb.toString();
Connection con = null;
PreparedStatement pstmt = null;
System.out.println(copy);
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
copy = new BookCopy();
copy.setIsbn(rs.getString(1));
copy.setTitle(rs.getString(2));
copy.setAuthor(rs.getString(3));
copy.setPublishDate(rs.getTimestamp(4));
copy.setBookSeq(rs.getInt(5));
copy.setBookPosition(rs.getString(6));
copy.setBookStaus(rs.getString(7));
list.add(copy);
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
public boolean deleteBook(int parseInt) {
boolean flag = false;
String sql = "delete from book_copy where book_seq = ?";
Connection con = null;
PreparedStatement pstmt = null;
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, parseInt);
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
public BookCopy selectBook(int parseInt) {
BookCopy copy = null;
StringBuilder sb = new StringBuilder("select a.*, b.* from book_info a ");
sb.append("inner join book_copy b on a.book_isbn=b.book_isbn ");
sb.append("where b.book_seq = ?");
String sql = sb.toString();
Connection con = null;
PreparedStatement pstmt = null;
System.out.println(copy);
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setInt(1, parseInt);
ResultSet rs = pstmt.executeQuery();
while(rs.next()) {
copy = new BookCopy();
copy.setIsbn(rs.getString(1));
copy.setTitle(rs.getString(2));
copy.setAuthor(rs.getString(3));
copy.setPublishDate(rs.getTimestamp(4));
copy.setBookSeq(rs.getInt(5));
copy.setBookPosition(rs.getString(6));
copy.setBookStaus(rs.getString(7));
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return copy;
}
public boolean updateBook(BookCopy copy) {
boolean flag = false;
String sql = "update book_info set book_title = ?, book_author=?, book_published_date = ? where book_isbn = ?";
Connection con = null;
PreparedStatement pstmt = null;
System.out.println(copy);
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql);
pstmt.setString(1, copy.getTitle());
pstmt.setString(2, copy.getAuthor());
pstmt.setTimestamp(3, copy.getPublishDate());
//pstmt.setInt(4, copy.getBookSeq());
pstmt.setString(4, copy.getIsbn());
int affectedCount = pstmt.executeUpdate();
if(affectedCount>0) {
flag = true;
}
con.close();
} catch (SQLException e) {
e.printStackTrace();
}
return flag;
}
}
ConnectionManager가 아닌 DataSource 객체를 만들어서 Connection을 얻어온다.
DataSource Bean은 root-context.xml 파일에서 의존성 주입을 통해 DB 연결을 설정한다.
db.properties에 있는 정보를 가지고 DB에 연결한다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
version 5
다음은 mybatis를 이용한 version 5이다.
https://suldenlion.tistory.com/116
MyBatis에 대한 간략한 정리는 위의 글 참고.
package bitedu.bipa.book.controller;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
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.servlet.ModelAndView;
import bitedu.bipa.book.service.BlmService2;
import bitedu.bipa.book.service.BlmService3;
import bitedu.bipa.book.vo.BookCopy;
@Controller("bookController5")
@RequestMapping("mybatisdb")
public class BookController5 {
@Autowired
private BlmService3 blmService;
@RequestMapping(value="/list.do", method=RequestMethod.GET)
public ModelAndView list() {
System.out.println("extends");
ModelAndView mav = new ModelAndView();
ArrayList<BookCopy> list = blmService.searchBookAll();
mav.addObject("list",list);
mav.setViewName("./manager/book_list");
return mav;
}
@RequestMapping(value="/view_regist.do", method=RequestMethod.GET)
public ModelAndView viewRegist() {
ModelAndView mav = new ModelAndView();
mav.setViewName("./manager/book_regist");
return mav;
}
@RequestMapping(value="/view_detail.do", method=RequestMethod.GET)
public ModelAndView viewDetail(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_detail");
return mav;
}
@RequestMapping(value="/view_update.do", method=RequestMethod.POST)
public ModelAndView viewUpdate(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
BookCopy copy = blmService.findBook(bookSeq);
mav.addObject("copy",copy);
mav.setViewName("./manager/book_update");
return mav;
}
@RequestMapping(value="/remove.do", method=RequestMethod.GET)
public ModelAndView remove(@RequestParam("bookSeq") String bookSeq) {
ModelAndView mav = new ModelAndView();
boolean flag = blmService.removeBook(bookSeq);
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/update.do", method=RequestMethod.POST)
public ModelAndView update(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
boolean flag = blmService.modifyBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
@RequestMapping(value="/regist.do", method=RequestMethod.POST)
public ModelAndView regist(@ModelAttribute("book") BookCopy copy) {
ModelAndView mav = new ModelAndView();
System.out.println(copy);
blmService.registBook(copy);
System.out.println("regist");
mav.setViewName("redirect:list.do");
return mav;
}
}
컨트롤러5이다.
mybatisdb란 경로로 컨트롤러에 매핑하고 Service3과 연결할 것이다.
package bitedu.bipa.book.service;
import java.util.ArrayList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import bitedu.bipa.book.dao.BlmDAO;
import bitedu.bipa.book.dao.BlmDAO2;
import bitedu.bipa.book.dao.BlmDAO3;
import bitedu.bipa.book.vo.BookCopy;
@Service("blmService3")
public class BlmService3 implements IBlmService {
@Autowired
private BlmDAO3 dao;
@Override
public boolean registBook(BookCopy copy) {
boolean flag = false;
flag = dao.insertBook(copy);
return flag;
}
@Override
public ArrayList<BookCopy> searchBookAll(){
ArrayList<BookCopy> list = null;
list = dao.selectBookAll();
return list;
}
@Override
public boolean removeBook(String bookSeq) {
boolean flag = false;
flag = dao.deleteBook(Integer.parseInt(bookSeq));
return flag;
}
@Override
public BookCopy findBook(String bookSeq) {
BookCopy copy = null;
copy = dao.selectBook(Integer.parseInt(bookSeq));
System.out.println(copy);
return copy;
}
@Override
public boolean modifyBook(BookCopy copy) {
boolean flag = false;
flag = dao.updateBook(copy);
return flag;
}
}
Service 클래스이다. DAO3와 연결한다.
package bitedu.bipa.book.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import bitedu.bipa.book.utils.ConnectionManager;
import bitedu.bipa.book.vo.BookCopy;
@Repository("blmDAO3")
public class BlmDAO3 implements IBlmDAO {
@Autowired
private SqlSession sqlSession;
@Override
public boolean insertBook(BookCopy copy){
boolean flag = false;
int affectedCount1 = sqlSession.insert("mapper.book.insertBook", copy);
int affectedCount2 = sqlSession.insert("mapper.book.insertCopy", copy.getIsbn());
if (affectedCount1 > 0 && affectedCount2 > 0) {
flag = true;
}
return flag;
}
@Override
public ArrayList<BookCopy> selectBookAll(){
ArrayList<BookCopy> list = null;
list = (ArrayList)sqlSession.selectList("mapper.book.selectAllBook");
System.out.println(list.size());
return list;
}
@Override
public boolean deleteBook(int parseInt) {
boolean flag = false;
int affectedCount = sqlSession.delete("mapper.book.deleteBook", parseInt);
if (affectedCount > 0) {
flag = true;
}
return flag;
}
public BookCopy selectBook(int parseInt) {
BookCopy copy = null;
copy = sqlSession.selectOne("mapper.book.selectBookBySeq",parseInt);
return copy;
}
@Override
public boolean updateBook(BookCopy copy) {
boolean flag = false;
int affectedCount = sqlSession.update("mapper.book.updateBook", copy);
if (affectedCount>0) {
flag = true;
}
return flag;
}
}
mybatis의 핵심 객체인 sqlSession을 볼 수 있다.
DAO 클래스를 보기 앞서 MyBatis 세팅 과정을 짚고 넘어가겠다.
우선, pom.xml 파일에 MyBatis를 쓰기 위한 의존성을 추가시켜준다.
root-context.xml에도 sqlSessionFactory와 sqlSession에 대한 Bean 객체를 등록시켜준다.
sqlSessionFactory의 구성을 위한 config파일과 메서드와 쿼리의 매핑을 세팅해줄 mapper파일을 위에 명시한 경로에 둔다.
resources 폴더에 다음과 같이 폴더와 파일을 만들어준다. 내용은 다음과 같다.
- book.xml의 <![CDATA[ ]]> 구문은 XML 문서 내에서 특정 데이터 블록을 포함할 때 사용함. CDATA 섹션은 해당 데이터가 마크업 규칙을 따르지 않고 원본 그대로 처리되어야 함을 나타냄.
- CDATA 섹션은 특수문자나 예약 문자가 포함된 데이터를 XML 문서에 포함할 때 유용함.
- 일반적으로 텍스트 데이터, HTML 코드, XML 코드, 스크립트 등을 CDATA 섹션으로 감싸는데 사용됨.
- CDATA 섹션 내부의 데이터는 마크업 구문으로 간주되지 않으며, XML 파서에 의해 그대로 유지됨.
위의 작업들을 통해 DAO에서 SqlSession을 연결하여 xml 파일에서의 쿼리문을 실행할 수 있다.
이런식으로 쓰는 이유는 DAO에 쿼리 내용을 하드코딩하지 않고, 필요한 쿼리가 담긴 파일을 통해 처리하기 위함 때문이다. (DB 쿼리가 MySQL이냐 Oracle DB냐에 따라 쿼리 내용이 다를 수도 있고 한 이유)
insertBook() 메서드를 보면 sqlSession.insert()에 "mapper의 namespace" + ".메서드"를 써서 동작하게 한다.
마지막으로 추가로 Service3와 DAO3를 interface를 implements하게 했는데, 추상화와 다형성 / 코드 재사용과 모듈화 / 의존성 역전 / API 설계와 문서화 등의 이유로 사용한다.
package bitedu.bipa.book.service;
import java.util.ArrayList;
import bitedu.bipa.book.vo.BookCopy;
public interface IBlmService {
public boolean registBook(BookCopy copy);
public ArrayList<BookCopy> searchBookAll();
public boolean removeBook(String bookSeq);
public BookCopy findBook(String bookSeq);
public boolean modifyBook(BookCopy copy);
}
package bitedu.bipa.book.dao;
import java.util.ArrayList;
import bitedu.bipa.book.vo.BookCopy;
public interface IBlmDAO { // C# 인터페이스 명명 규칙 따름 I..
public boolean insertBook(BookCopy copy);
public ArrayList<BookCopy> selectBookAll();
public boolean deleteBook(int parseInt);
public BookCopy selectBook(int parseInt);
public boolean updateBook(BookCopy copy);
}
① 추상화와 다형성 :
- Interface는 추상화를 통해 구체적인 구현과 분리함으로써 다형성을 지원함. 즉, 동일한 인터페이스를 구현하는 여러개의 클래스를 만들 수 있으며, 이들은 각자 다른 방식으로 동작할 수 있음. 이는 유연하고 확장 가능한 코드를 작성하는데 도움을 줌.
② 코드 재사용과 모듈화 :
- Interface는 재사용 가능한 코드의 기반이 될 수 있음. 인터페이스를 정의하고 해당 인터페이스를 구현하는 클래스를 만들면, 다른 클래스에서 해당 인터페이스를 사용하여 동작을 확장하거나 변경할 수 있음. 이는 코드의 모듈화와 재사용성을 높여줌.
③ 의존성 역전 원칙 :
- Interface는 의존성 역전(Dependency Inversion) 원칙을 지원함. 의존성 역전은 클래스가 구체적인 구현에 의존하는 것이 아니라, 인터페이스에 의존해야 한다는 원칙. 이를 통해 결합도를 낮추고 유연성과 테스트 용이성을 향상시킴.
④ API 설계와 문서화 :
- Interface는 API를 정의하고 문서화하는데 사용될 수 있음. 인터페이스를 사용하여 클래스간의 상호 작용을 정의하고, 해당 인터페이스의 메서드에 대한 명확한 문서를 작성할 수 있음. 이는 개발자들이 인터페이스를 사용하는 방법을 이해하고 구현할 수 있도록 도움.
스프링 프로그래밍을 버전 별로 나누어 정리해보았다.
'Spring' 카테고리의 다른 글
웹 페이지 파일(이미지) 업로드 & 페이지네이션 (0) | 2023.07.24 |
---|---|
(Spring 관련 정보) Dispatcher Servlet, Filter, Interceptor에 대하여 (0) | 2023.07.18 |
MyBatis 정리 (0) | 2023.07.16 |
(스프링 관련 정보) web.xml / servlet-context.xml / root-context.xml 에 대하여 (1) | 2023.07.16 |
페이지네이션 (Pagination) - Servlet 프로그래밍 (0) | 2023.07.08 |
댓글