JDBC 복습
1. 기본 설정
1) DB연동
jdbc.properties 에서 오라클 정보 기재 후 root-context.xml에 datasource 설정 후 db연동하면 됨
우리가 직접적으로 사용하는건 jdbcTemplate이기 때문에 이것도 root-context.xml에 명시 후 빈 설정해야함
2) auto scan
root-context.xml 에는 controller를 제외한 autoscan 명시
DAOImpl -> DB연동 (sql문 작성 및 메서드 작성)
여기는 메서드 1개당 sql문 1개를 쓰는데 만약 sql문 2개 이상을 쓴다면 ServiceImpl 쪽에서 묶어서 처리해야함
ServiceImpl -> 트랜잭션 처리 (메서드 호출 후 트랜잭션 처리)
2. Controller
- @Autowired(interface타입 import)
- 로그처리 -> 로그파일 생성 후 에러메시지나 구동 시 필요한 내용들 저장하기 위해 로그 처리함
로그레벨 (fatal, error -까지가 실행안되는 오류)
지금은 log.debug라고 하지만 실제로는 로그레벨을 warn~error까지 낮춤 (로그를 너무 많이 만들면 그것도 안좋기 때문에)
3. BoardDAOImpl 의 getBoardCount () {} 메서드에서
jdbcTemplate.queryForObject -> Object라고 지정되어 있기 때문에 타입을 꼭 명시해주는거임
**rowMapper 객체
하나의 레코드(컬럼)과 매핑된 데이터와 자바빈의 프로퍼티에 매핑시키는 것 (컬럼 데이터가 자바빈 프로퍼티에 들어가게 하는 것)
mapRow라는 메서드를 만들어서 rs로부터 한 건의 레코드를 받아옴
그래서 자바빈 타입으로 반환할 수 있게끔 한 후 public List<BoardVO> getBoardList jdbcTemplate.query에 넘겨줌
--> 위에 자바빈 타입으로 넘긴 데이터를 Controller //초기화면 불러오기 에서 사용함
<jdbc를 이용하여 대문 페이지에 글목록 만들기>
컨트롤러에서 초기화면 목록 보여주기
BoardController
//초기화면 불러오기
@RequestMapping("/list.do")
public ModelAndView process(@RequestParam(value="pageNum",defaultValue="1") int currentPage) {
int count = boardService.getBoardCount();
log.debug("pageNum : " + currentPage);
log.debug("count : " + count);
//페이지 처리
PageUtil page = new PageUtil(currentPage, count, 10, 10, "list.do");
//목록 읽어오기
List<BoardVO> list = null;
if(count > 0) {
list = boardService.getBoardList(page.getStartRow(), page.getEndRow());
}
ModelAndView mav = new ModelAndView();
mav.setViewName("selectList"); //뷰이름 지정
mav.addObject("count", count); //count 받기
mav.addObject("list", list); //list 받기
mav.addObject("page", page.getPage());//페이지 처리
return mav;
}
ModelAndView 객체 생성해서 뷰 지정 후 count, list 데이터를 넘겨주고 page 처리함
대문페이지에 글 보여주기
views
selectList.jsp
<%@ page language="java" 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>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>게시판 목록</h2>
<div class="align-right">
<input type="button" value="글쓰기" onclick="location.href='insert.do'">
</div>
<c:if test="${count == 0}">
<div class="result-display">표시할 내용이 없습니다.</div>
</c:if>
<c:if test="${count > 0}">
<table>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
</tr>
<c:forEach var="board" items="${list}">
<tr>
<td>${board.num}</td>
<td><a href="detail.do?num=${board.num}">${board.title}</a></td>
<td>${board.writer}</td>
<td>${board.reg_date}</td>
</tr>
</c:forEach>
</table>
<div class="align-center">${page}</div>
</c:if>
</div>
</body>
</html>
count가 넘어오기 때문에 그것에 대한 구문을 넣어줌
<jdbc를 이용하여 상세 페이지 만들기>
DAO class파일에서 메서드 작성
BoardDAOImpl
private static final String SELECT_DETAIL_SQL = "SELECT * FROM aboard WHERE num=?";
@Override
public BoardVO getBoard(int num) {
BoardVO board = jdbcTemplate.queryForObject(SELECT_DETAIL_SQL, new Object[] {num},
rowMapper); //sql문,?데이터바인딩,인자(rowMapper)
return board;
}
상세페이지는 한 건의 레코드가 매핑되는건데 rowMapper 를 이미 만들었기 때문에 얘만 호출하면 됨
static 상수 (sql문) 작성 -> 메서드 작성 (rowMapper 이용)
Service 클래스에 board 데이터 넘기기
BoardServiceImpl
@Override
public BoardVO getBoard(int num) {
return boardDAO.getBoard(num);
}
컨트롤러에서 메서드 생성
BoardController
//상세화면 불러오기
@RequestMapping("/detail.do")
public ModelAndView viewDetail(@RequestParam int num) {
log.debug("num : " + num);
BoardVO board = boardService.getBoard(num);
return new ModelAndView("selectDetail", "board", board); //뷰이름,속성명,속성값
}
상세 정보는 num으로 데이터를 받아오는 거라 필수적으로 전달해야하기 때문에 @RequestParam 사용
상세폼 만들기
views
selectDetail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 상세</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>${board.title}</h2>
<p>
글번호 : ${board.num}<br>
작성자 : ${board.writer}<br>
작성일 : ${board.reg_date}<br>
</p>
<hr width="90%" size="1" noshade="noshade">
<p>
${board.content}
</p>
<div class="align-center">
<input type="button" value="수정" onclick="location.href='update.do?num=${board.num}'">
<input type="button" value="삭제" onclick="location.href='delete.do?num=${board.num}'">
<input type="button" value="목록" onclick="location.href='list.do'">
</div>
</div>
</body>
</html>
컨트롤러에서 boardService.getBoard(num);
를 BoardVO board에 넣었기 때문에 board.num 형태로 명시함

<jdbc를 이용하여 수정폼 만들기>
수정폼 불러오기
BoardController
//수정폼 불러오는 작업
@GetMapping("/update.do")
public String formUpdate(@RequestParam int num, Model model) {
//모델에 데이터 저장
model.addAttribute("boardVO", boardService.getBoard(num)); //속성명, 속성값
return "updateForm";
}
1.
한 건의 레코드를 읽어오는건 getBoard를 호출해서 사용
getBoard는 request에 데이터가 있기 때문에 커스텀 태그의 form 형식은 바뀌지 않음 (insert 폼 복붙해서 조금만 수정)
2.
ModelAndView -> view/ data 모두 저장
Model -> view같은 경우는 이미 string으로 반환했기 때문에 data만 처리하면 돼서 model만 인자로 넣어줌
3.
model.addAttribute("boardVO", boardService.getBoard(num)); //속성명, 속성값
속성명, 속성값으로 request에 저장함
자바빈에 데이터가 다 들어가 있기 때문에 속성명을 boardVO라고 했음
속성값은 하나의 레코드만 읽어오면 되기 때문에 getBoard사용
수정폼 생성하기
views
updateForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>글 수정</h2>
<form:form action="update.do" modelAttribute="boardVO">
<form:hidden path="num"/>
<ul>
<li>
<form:label path="writer">작성자</form:label>
<form:input path="writer"/>
<form:errors path="writer" cssClass="error-color"/>
</li>
<li>
<form:label path="title">제목</form:label>
<form:input path="title"/>
<form:errors path="title" cssClass="error-color"/>
</li>
<li>
<form:label path="passwd">비밀번호</form:label>
<form:password path="passwd"/> <%-- 커스텀 태그가 비밀번호를 제외하고 미리보기 처리해줌 --%>
<form:errors path="passwd" cssClass="error-color"/>
</li>
<li>
<form:label path="content">내용</form:label>
<form:textarea path="content"/>
<form:errors path="content" cssClass="error-color"/>
</li>
</ul>
<div class="align-center">
<form:button>수정</form:button>
<input type="button" value="홈으로" onclick="location.href='list.do'">
</div>
</form:form>
</div>
</body>
</html>
form:hidden path="num" 추가
pk만 히든값으로 넘겨줌

유효성 검사도 넣어놨기 때문에 동작함
만약 유효성 체크를 어노테이션이 아닌 스크립트로 했다면 미리보기 value값을 일일이 다 명시했어야 했음
커스텀 태그와 자바빈이 매핑해서 자바빈 미리보기까지 가능했던 것
<jdbc를 이용하여 수정하기>
수정하기 + 글 수정 시 비밀번호 인증
BoardDAOImpl
private static final String UPDATE_SQL = "UPDATE aboard SET writer=?,title=?,content=? WHERE num=?";
@Override
public void updateBoard(BoardVO board) {
jdbcTemplate.update(UPDATE_SQL, new Object[] {board.getWriter(),
board.getTitle(),board.getContent(),board.getNum()});
}
Service class 파일
BoardServiceImpl
@Override
public void updateBoard(BoardVO board) {
boardDAO.updateBoard(board);
}
컨트롤러 + 글 수정 시 비밀번호 인증
BoardController
//업데이트 작업
@PostMapping("/update.do")
public String submitUpdate(@Valid BoardVO boardVO, BindingResult result) {
//유효성 체크 결과 오류가 있으면 폼 재호출
if(result.hasErrors()) {
return "updateForm";
}
//DB에 저장된 비밀번호 구하기
BoardVO db_board = boardService.getBoard(boardVO.getNum());
//비밀번호 일치 여부 체크
if(!db_board.getPasswd().equals(boardVO.getPasswd())) {
result.rejectValue("passwd", "invalidPassword");
return "updateForm";
}
//글 수정
boardService.updateBoard(boardVO);
return "redirect:/list.do";
}
비밀번호 유효성 체크는 한 건의 레코드만 읽어오면 되는거라 컨트롤러에서도 가능
db_board.getPasswd = db에 저장된 pw
boardVO.getPasswd = 내가 입력한 pw
result.rejectValue("passwd", "invalidPassword");
필드가 있기 때문에 (passwd) rejectValue 사용 // 필드명, 에러코드 (이전에 명시했던 invalidPassword 에러코드 사용)

모든 유효성 검사 + 수정 가능
<jdbc를 이용하여 삭제하기>
삭제기능 implements 파일에 넣기
BoardDAOImpl
private static final String DELETE_SQL = "DELETE FROM aboard WHERE num=?";
@Override
public void deleteBoard(int num) {
jdbcTemplate.update(DELETE_SQL, new Object[] {num});
}
상세페이지 -> 삭제버튼 -> 바로 삭제하려고 함
Service class파일
@Override
public void deleteBoard(int num) {
boardDAO.deleteBoard(num);
}
컨트롤러에서 호출
BoardController
@GetMapping("/delete.do")
public String formDelete(@RequestParam int num, Model model) {
BoardVO boardVO = new BoardVO();
boardVO.setNum(num);
model.addAttribute("boardVO", boardVO);
return "deleteForm";
}
전송되는 데이터가 글번호고, 유효성체크를 하기 위해선 자바빈에 담겨있어야 하기 때문에 개별적으로 한다 하더라도 자바빈에 담겨있어야함
그래서 코드를 줄이기 위해 자바빈에 정보를 담을거임 자바빈에 만들고 자바빈에 넣어주기 위해 model도 생성
비밀번호 인증 후 삭제할거기 때문에 유효성 검사도 수행
전송되는 데이터가 글번호고, 유효성체크를 하기 위해선 자바빈에 담겨있어야 하기 때문에 개별적으로 한다 하더라도 자바빈에 담겨있어야함
그래서 코드를 줄이기 위해 자바빈에 정보를 담을 것
자바빈에 만들고 자바빈에 넣어주기 위해 model도 생성
=============================
BoardVO boardVO = new BoardVO();
자바빈 생성
boardVO.setNum(num);
자바빈에 num 넣기
model.addAttribute("boardVO", boardVO);
model에 자바빈 데이터 넣기
addAttribute(String name, Object value)
: value 객체를 name 이름으로 추가해줌
: View에서 name으로 지정된 value를 사용
============================
url 을 delete.do?num= 이렇게 되어있는데
임의로 num을 지워서 넘기는 놈들이 있을 수도 있기 때문에 @RequestParam을 기재한거임
비밀번호 체크 폼
views
deleteForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 삭제</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>글 삭제</h2>
<form:form action="delete.do" modelAttribute="boardVO">
<form:hidden path="num"/>
<ul>
<li>
<form:label path="passwd">비밀번호</form:label>
<form:password path="passwd"/>
<form:errors path="passwd" cssClass="error-color"/>
</li>
</ul>
<div class="align-center">
<form:button>삭제</form:button>
<input type="button" value="홈으로" onclick="location.href='list.do'">
</div>
</form:form>
</div>
</body>
</html>
유효성 체크가 있어서 taglib form 넣어줌
hidden값도 명시

글삭제 페이지 url
http://localhost:8080/ch11-Spring_JDBC/delete.do?num=1
페이지 소스보기
<input id="num" name="num" type="hidden" value="1"/>
뜨면 정상적으로 실행된거임
아직 삭제기능은 안넣었고 폼만 넣은거임
<jdbc를 이용하여 삭제하기>
삭제기능 컨트롤러에 명시
BoardController
@PostMapping("/delete.do")
public String submitDelete(@Valid BoardVO boardVO, BindingResult result) {
//비밀번호만 유효성 체크 결과를 확인
if(result.hasFieldErrors("passwd")) {
return "deleteForm";
}
//DB에 저장된 비밀번호 구하기
BoardVO db_board = boardService.getBoard(boardVO.getNum());
//비밀번호 일치 여부 체크
if(!db_board.getPasswd().equals(boardVO.getPasswd())) {
result.rejectValue("passwd", "invalidPassword");
return "deleteForm";
}
//글 삭제
boardService.deleteBoard(boardVO.getNum());
return "redirect:/list.do";
}
인자로 글번호, 비밀번호 받아야함
@Valid BoardVO boardVO, BindingResult result
삭제는 deleteForm.jsp 에서 2차 비밀번호 인증 후 삭제하려고 하는데
자바빈(BoardVO) 에서 reg_date를 제외한 모든 필드에 @NotEmpty를 줬기 때문에 num, passwd값만 넘기면 에러가 남 (다른 값들은 null이라서)
그렇기 때문에 Controller 에서 비밀번호 유효성 체크 검사 시 passwd만 체크하기 위해 hasFieldErrors 사용
hasErrors = 필드를 명시하지 않고 전체적인 오류가 있는지 없는지 확인
hasFieldErrors = 필드를 명시해서 해당 필드의 오류만 확인


위에 명시한 파일들은 여러 개의 sql문이 한 번에 들어갈 일이 없었기 때문에 Service 파일에 트랜잭션 처리 설정을 하지 않았음 하지만 트랜잭션 처리를 어노테이션 방식으로 해볼거임
sql문이 지금은 하나라서 잘 모르겠지만 service에 sql문이 여러 개 묶여있어서 트랜잭션 처리를 할 때 만약 하나라도 잘못되면 rollback시키는 설정임
설정파일에 명시
root-context.xml
<!-- JDBC 기반 트랜잭션 관리자 설정 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 어노테이션 방식으로 트랜잭션 처리 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
1.
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
트랜잭션을 관리해주는 매니저 객체 기재 (의무)
dataSource-ref=해서 dataSource객체를 넘겨주면 됨
2.
<!-- 어노테이션 방식으로 트랜잭션 처리 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
위 트랜잭션 관리자 설정한 id 와 해당 transaction-manager가 동일해야함
이제 serviceImpl에 트랜잭션 처리 시 위에 명시한 어노테이션을 넣어주면 되는데
1) 메서드 단위 2) 클래스 단위 두가지 방법으로 넣을 수 있음
메서드 단위 -> 필요한 메서드만 적용
클래스 단위 -> 전체 클래스에 모두 적용
클래스 단위로 넣어줄거고 보통 그 단위로 많이들 작성한다 함
서비스 파일에 어노테이션 명시
BoardServiceImpl
@Service
@Transactional
public class BoardServiceImpl implements BoardService {
@Transactional
이라고 넣게 되면 해당 클래스 전체에 설정이 됨
jdbc 끝!
mybatis 시작 (래거시)!
jdbcTemplate / myBatis 둘다 메서드 기반으로 처리하지만 rowMapper의 유무 차이가 있음
myBatis 는 rowMapper도 자동으로 처리해주기 때문에 xml에 sql문을 작성하고 연결하면 됨
mybatis 참고 사이트
The MyBatis Blog
A blog about the the MyBatis data mapper framework.
blog.mybatis.org
사용법
mybatis – MyBatis 3 | Introduction
mybatis – MyBatis 3 | Introduction
What is MyBatis? MyBatis is a first class persistence framework with support for custom SQL, stored procedures and advanced mappings. MyBatis eliminates almost all of the JDBC code and manual setting of parameters and retrieval of results. MyBatis can use
mybatis.org
기본 설정
ch12 프로젝트
root-contex.xml (기존에 배웠던 자동스캔, jdbc properties-db연동 구문은 기입해놓은 상태)
<!-- JDBC 기반 트랜잭션 관리자 설정 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
<!-- 어노테이션 방식으로 트랜잭션 설정 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Mybatis 설정 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="typeAliasesPackage" value="kr.spring.board.vo"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="kr.spring.board.dao"/>
</bean>
1. jdbc 기반 관리자 설정 + 어노테이션 방식으로 트랜잭션 설정
=> service가 트랜잭션을 수행하기 위해 넣어놓은 설정
2. jdbcTemplate 대신 mybatis 설정을 넣음
dataSource + mybatis설정에 kr.spring.board.vo 에 알리아스를 준걸 볼 수 있음
마이바티스는 자바빈을 가져다 쓰기 때문에 상당히 편해짐
3. mapper라는 이름의 xml파일을 kr.spring.board.dao에 넣고 사용할거기 때문에 spring.mapper.MapperScannerConfigurer 라고 명시 (dao를 통해서 마이바티스를 연동하기 때문에 세팅)
==> 마이바티스는 dao를 통해 연동하고, vo를 가져다 쓴다!
자바빈 생성
kr.spring.board.vo (package)
BoardVO (class)
package kr.spring.board.vo;
import java.sql.Date;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
public class BoardVO {
private int num;
@NotBlank
private String writer;
@NotBlank
private String title;
@NotBlank
private String passwd;
@NotEmpty
private String content;
private Date reg_date; //db연동시에는 java.sql 사용
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getWriter() {
return writer;
}
public void setWriter(String writer) {
this.writer = writer;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getPasswd() {
return passwd;
}
public void setPasswd(String passwd) {
this.passwd = passwd;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getReg_date() {
return reg_date;
}
public void setReg_date(Date reg_date) {
this.reg_date = reg_date;
}
@Override
public String toString() {
return "BoardVO [num=" + num + ", writer=" + writer + ", title=" + title + ", passwd=" + passwd + ", content="
+ content + ", reg_date=" + reg_date + "]";
}
}
@NotEmpty = 공백 허용 // @NotBlank = 공백 비허용
에러 메시지 설정
messages
validation.properties
NotBlank.writer=작성자는 필수 항목
NotBlank.title=제목은 필수 항목
NotBlank.passwd=비밀번호는 필수 항목
NotEmpty.content=내용은 필수 항목
invalidPassword=비밀번호 불일치
컨트롤러 생성 (로그 처리, 초기 뷰 호출)
kr.spring.board.controller
BoardController (class)
package kr.spring.board.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class BoardController {
//로그 처리(로그 대상 지정)
private static final Logger log = LoggerFactory.getLogger(BoardController.class);
@RequestMapping("/list.do")
public ModelAndView getList() {
ModelAndView mav = new ModelAndView();
//뷰 이름 지정
mav.setViewName("selectList");
return mav;
}
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
메인페이지 생성
views
selectList.jsp
<%@ page language="java" 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>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>게시판 목록</h2>
<div class="align-right">
<input type="button" value="글쓰기" onclick="location.href='insert.do'">
</div>
</div>
</body>
</html>
실행 파일 (초기 화면으로 redirect 걸어주는 것)
index.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
response.sendRedirect(request.getContextPath()+"/list.do");
%>
저장 후 실행하면 ch11과 같은 초기 화면이 뜸 (정상적으로 연동됐을 경우)
<mybatis (래거시)를 이용하여 글쓰기>
컨트롤러 - 자바빈 초기화+유효성 체크
BoardController
폼을 보여주기 위해 먼저 체크부터 할 것임
package kr.spring.board.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import kr.spring.board.vo.BoardVO;
@Controller
public class BoardController {
//로그 처리(로그 대상 지정)
private static final Logger log = LoggerFactory.getLogger(BoardController.class);
//자바빈 초기화
@ModelAttribute
public BoardVO initCommand() {
return new BoardVO();
}
//글쓰기 폼 불러오기
@GetMapping("/insert.do")
public String form() {
return "insertForm";
}
//메인페이지
@RequestMapping("/list.do")
public ModelAndView getList() {
ModelAndView mav = new ModelAndView();
//뷰 이름 지정
mav.setViewName("selectList");
return mav;
}
}
글쓰기 폼 생성
views
insertForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>글쓰기</h2>
<form:form action="insert.do" modelAttribute="boardVO">
<ul>
<li>
<form:label path="writer">작성자</form:label>
<form:input path="writer"/>
<form:errors path="writer" cssClass="error-color"/>
</li>
<li>
<form:label path="title">제목</form:label>
<form:input path="title"/>
<form:errors path="title" cssClass="error-color"/>
</li>
<li>
<form:label path="passwd">비밀번호</form:label>
<form:password path="passwd"/>
<form:errors path="passwd" cssClass="error-color"/>
</li>
<li>
<form:label path="content">내용</form:label>
<form:textarea path="content"/>
<form:errors path="content" cssClass="error-color"/>
</li>
</ul>
<div class="align-center">
<input type="submit" value="등록">
<input type="button" value="홈으로" onclick="location.href='list.do'">
</div>
</form:form>
</div>
</body>
</html>
위 컨트롤러에서 자바빈 초기화 시 @ModelAttribute 라고 기재하고 따로 이름을 주지 않았기 때문에
앞글자만 소문자로 바꾼 BoardVO -> boardVO가 form modelAttribute로 들어가게 됨
DAO생성
마이바티스와 연동하기 위해선 dao와 연동해야함
그래서 dao를 만들건데 마이바티스 느낌이 나기 위해 mapper라는 단어를 써서 만들어보려고 함
dao도 jdbc와 마찬가지로 interface로 생성
kr.spring.board.dao
BoardMapper (interface)
package kr.spring.board.dao;
import java.util.List;
import java.util.Map;
import kr.spring.board.vo.BoardVO;
public interface BoardMapper {
public void insertBoard(BoardVO board);
public int selectBoardCount();
public List<BoardVO> selectBoardList(Map<String,Integer> map);
public BoardVO selectBoard(int num);
public void updateBoard(BoardVO board);
public void deleteBoard(int num);
}
마이바티스 특성이 작업 시 하나의 인자만 받는거라고 함
그렇기 때문에 여러 개의 인자가 있을 경우 map으로 처리한다고 함
public List<BoardVO> selectBoardList처럼 Map<String,Integer> map 형태로 인자 받음
마이바티스 같은 경우에는 DAO의 class를 따로 생성할 필요가 없음
마이바티스가 자동으로 생성하고 컨테이너에 보관해주기 때문
하지만 Service 파일은 만들어야 하기 때문에 interface와 class 둘다 만들어보겠음
서비스 파일 생성
kr.spring.board.service
BoardService (interface)
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import kr.spring.board.vo.BoardVO;
public interface BoardService {
public void insertBoard(BoardVO board);
public int selectBoardCount();
public List<BoardVO> selectBoardList(Map<String,Integer> map);
public BoardVO selectBoard(int num);
public void updateBoard(BoardVO board);
public void deleteBoard(int num);
}
ch11도 그렇고 이번에도 DAO (BoardMapper) 메서드와 동일하게 기재함
다르게 해도 가능하지만 매번 호출관계를 확인해야 하고 불편한 점이 많다고 하심
똑같이 할 수 있다면 똑같이 하는 게 더 좋다고 함
서비스 class파일 생성
kr.spring.board.service
BoardServiceImpl (class)
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.spring.board.dao.BoardMapper;
import kr.spring.board.vo.BoardVO;
@Service
@Transactional
public class BoardServiceImpl implements BoardService{
@Autowired
BoardMapper boardMapper;
@Override
public void insertBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public int selectBoardCount() {
return boardMapper.selectBoardCount();
}
@Override
public List<BoardVO> selectBoardList(Map<String, Integer> map) {
// TODO Auto-generated method stub
return null;
}
@Override
public BoardVO selectBoard(int num) {
// TODO Auto-generated method stub
return null;
}
@Override
public void updateBoard(BoardVO board) {
// TODO Auto-generated method stub
}
@Override
public void deleteBoard(int num) {
// TODO Auto-generated method stub
}
}
implements 후 @Service (연동) @Transactional (트랜잭션 처리) 어노테이션을 넣고
BoardMapper를 @Autowired를 통해 연결해준다 (ch11과 동일한 형태)
매핑된 메서드를 만들어줘야 정보가 처리되는데 BoardMapper는 인터페이스만 만들었기 때문에
BoardMapper와 매핑하기 위해선 xml파일을 만들고 그 안에 sql문을 작성해야 함
오타나기 쉬워서 선생님이 파일 나눠주심
xml파일
kr.spring.board.dao
BoardMapper.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">
<mapper namespace="kr.spring.board.dao.BoardMapper">
<insert id="insertBoard" parameterType="boardVO">
INSERT INTO aboard(
num,
writer,
title,
passwd,
content,
reg_date)
VALUES (
aboard_seq.nextval,
#{writer},
#{title},
#{passwd},
#{content},
SYSDATE)
</insert>
</mapper>
1.
<mapper namespace="kr.spring.board.dao.BoardMapper">
마이바티스가 인식하기 위해선 BoardMapper.interface와 xml파일이 이름 + namespace 가 같아야함
명칭을 다 통일해서 명시하고 마이바티스가 자동으로 매핑, 객체 생성 및 호출을 하기 때문
2.
태그로 sql문을 명시해서 마이바티스가 xml에 있는 태그 정보와 interface에 있는 메서드 정보를 확인 후 매핑 시키고, 그 후에 동작되는 원리임
3.
<insert id="insertBoard" parameterType="boardVO">
insertBoard = interface의 메서드명 = xml파일의 id // 모두 같아야함!
parameterType=boardVO에 데이터가 담겨서 온다 라는 뜻
본래 BoardVO에서 자바빈을 전달하고, xml 파일에서는 타입만 명시하면 되는데
본래 명시해야 하는건 parameterType="kr.spring.board.vo.BoardVO" 라고 풀 네임을 명시해야 하지만
맨 위 설정파일에서 typeAliases를 board.vo에 줬기 때문에 풀네임을 명시할 필요가 없고, 첫 글자만 소문자로 명시하면 됨
그래서 parameterType="boardVO" 라고 명시한 것
** 내가 받는 것 = parameterType // select(반환)하는 것 = resultType
4.
#{writer}
등은 자바빈 프로퍼티를 명시할 때 마이바티스에서 사용하는 형식임
$아니고 #임 꼭 기억하기 (오류나면 뜨지도 않기 때문에 한번 들어가서 확인해주는 것도 좋음)
서비스 class파일에 insert 호출할 수 있도록 수정
BoardServiceImpl
package kr.spring.board.service;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import kr.spring.board.dao.BoardMapper;
import kr.spring.board.vo.BoardVO;
@Service
@Transactional
public class BoardServiceImpl implements BoardService{
@Autowired
BoardMapper boardMapper;
@Override
public void insertBoard(BoardVO board) {
boardMapper.insertBoard(board);
}
@Override
public int selectBoardCount() {
}
@Override
public List<BoardVO> selectBoardList(Map<String, Integer> map) {
}
@Override
public BoardVO selectBoard(int num) {
}
@Override
public void updateBoard(BoardVO board) {
}
@Override
public void deleteBoard(int num) {
}
}
컨트롤러에서 submit 생성 + 유효성 체크
kr.spring.board.controller
BoardController
@PostMapping("/insert.do")
public String submit(@Valid BoardVO boardVO, BindingResult result) {
log.debug("<<BoardVO>> : " + boardVO);
//유효성 체크 결과 오류가 있으면 폼을 호출
if(result.hasErrors()) {
return form();
}
//글 등록
boardService.insertBoard(boardVO);
return "redirect:/list.do";
}
-->
mapper : 연동, sql문 작성/
ServiceImpl : boardMapper.insertBoard(board)
Controller : boardService.insertBoard(boardVO)
index.jsp 실행 후
글 작성 -> sql developer에 데이터가 들어가야 함 (유효성 체크도 검사)
<mybatis를 이용하여 목록 처리하기>
rowMapper없이 목록처리하기
BoardMapper.xml
selectBoardCount와 selectBoardList가 동작되기만 하면 됨
테이블 컬럼명=자바빈 프로퍼티명 일치하게 sql문 작성하면 됨 (다르면 수작업으로 작업)
<select id="selectBoardCount" resultType="integer">
SELECT
COUNT(*)
FROM aboard
</select>
<select id="selectBoardList" parameterType="map" resultType="boardVO">
SELECT
*
FROM (SELECT
a.*,
rownum rnum
FROM (SELECT
*
FROM aboard
ORDER BY reg_date DESC)a)
<![CDATA[
WHERE rnum >= #{start} AND rnum <= #{end}
]]>
</select>
1. insert 시 insert태그, select 시 select 태그를 사용하면 됨
2. id = 메서드 명과 맞춰서 selectBoardList, selectBoardCount라고 기재
3. selectBoardCount 는 받는 (반환) 타입이 정수기 때문에 integer or integer라고 기재
풀네임은 resultType="java.lang.Integer"
4.
selectBoardList 는 인자가 여러 개 이기 때문에 parameterType=map / resultType=boardVO라 기재
반환타입은 목록이기 때문에 list라고 적는거라고 생각하는데 resultType="list"라고 기재하면 에러남
resultType은 하나의 레코드와 매핑되는 자바빈을 매핑하게 되어 있음
자바빈이 여러 개가 만들어지면 마이바티스가 자동으로 리스트를 만들어주기 때문에
하나의 레코드와 매핑되는 자바빈의 타입을 명시해야함
그래서 resultType="boardVO" 라고 명시 // 목록 처리 시 resultType이 하나의 레코드와 매핑되는 객체가 됨
5.
WHERE rnum >= #{start} AND rnum <= #{end}
map에 키를 넣어야 하는데 startRownum 번호를 넣을거기 때문에 key인 start만 넣음
>= <= 같은 비교연산자는 xml에서는 특문처리가 되기 때문에 CDATA 섹션을 만들어야함
그래서 <![CDATA[]]> 사이에 해당 문자열만 넣음
서비스 class파일 목록처리 메서드 작성
BoardServiceImpl
@Override
public int selectBoardCount() {
return boardMapper.selectBoardCount();
}
@Override
public List<BoardVO> selectBoardList(Map<String, Integer> map) {
return boardMapper.selectBoardList(map);
}
컨트롤러에서 호출, 목록작업
BoardController
@RequestMapping("/list.do")
public ModelAndView getList(@RequestParam(value="pageNum", defaultValue="1") int currentPage) {
//총 레코드 수
int count = boardService.selectBoardCount();
log.debug("<<count>> : " + count);
log.debug("<<pageNum>> : " + currentPage);
//페이지 처리
PageUtil page = new PageUtil(currentPage, count, 10, 10, "list.do");
//목록 호출
List<BoardVO> list = null;
if(count > 0) {
Map<String,Integer>map = new HashMap<String,Integer>();
map.put("start", page.getStartRow());
map.put("end", page.getEndRow());
list = boardService.selectBoardList(map);
}
ModelAndView mav = new ModelAndView();
//뷰 이름 지정
mav.setViewName("selectList");
//데이터 저장
mav.addObject("count", count);
mav.addObject("list", list);
mav.addObject("page", page.getPage());
return mav;
}
초기화면에 목록 보여주기
selectList.jsp
<%@ page language="java" 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>게시판 목록</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>게시판 목록</h2>
<div class="align-right">
<input type="button" value="글쓰기" onclick="location.href='insert.do'">
</div>
<c:if test="${count == 0}">
<div class="result-display">출력할 내용이 없습니다.</div>
</c:if>
<c:if test="${count > 0}">
<table>
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
</tr>
<c:forEach var="board" items="${list}">
<tr>
<td>${board.num}</td>
<td><a href="detail.do?num=${board.num}">${board.title}</a></td>
<td>${board.writer}</td>
<td>${board.reg_date}</td>
</tr>
</c:forEach>
</table>
<div class="align-center">${page}</div>
</c:if>
</div>
</body>
</html>

<mybatis를 이용하여 글 상세 보기>
한건의 레코드를 반환해서 글 상세 보기
BoardMapper.xml
<select id="selectBoard" parameterType="integer" resultType="boardVO">
SELECT
*
FROM aboard
WHERE num=#{num}
</select>
마이바티스 - ? 대신 #{} 로 표시함
num은 selectBoard(int num) < 메서드의 인자명을 넣음 (num)
+ 인자가 2개인 map은 key값을 쓰면 됨
서비스 class에 호출
BoardServiceImpl
@Override
public BoardVO selectBoard(int num) {
return boardMapper.selectBoard(num);
}
컨트롤러에서 selectBoard를 호출해서 사용
BoardController
//선택 페이지 호출 (상세보기)
@RequestMapping("/detail.do")
public ModelAndView detail(@RequestParam int num) {
BoardVO board = boardService.selectBoard(num);
return new ModelAndView("selectDetail", "board", board); //뷰이름, 속성명, 속성값
}
상세보기 폼 생성
views
selectDetail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글 상세</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/resources/css/style.css">
</head>
<body>
<div class="page-main">
<h2>${board.title}</h2>
<p>
글번호 : ${board.num}<br>
작성자 : ${board.writer}<br>
작성일 : ${board.reg_date}
</p>
<hr width="100%" size="1" noshade="noshade">
<p>
${board.content}
</p>
<div class="align-center">
<input type="button" value="수정" onclick="location.href='update.do?num=${board.num}'">
<input type="button" value="삭제" onclick="location.href='delete.do?num=${board.num}'">
<input type="button" value="목록" onclick="location.href='list.do'">
</div>
</div>
</body>
</html>
jsp 실행 후 상세 글이 보이면 됨

'학원 > spring' 카테고리의 다른 글
1.10 (myBatis(boot)-crud/spring-tiles crud) (0) | 2024.01.11 |
---|---|
1.9 (myBatis-목록,상세,수정,삭제/ myBatis(boot) 설정,대문페이지) (0) | 2024.01.09 |
1.4 (SpringMVC-로그인처리,회원가입,파일업로드,파일다운로드) (0) | 2024.01.04 |
1.3 (SpringMVC-db,자바빈연결,service,cookie,유효성검사) (0) | 2024.01.03 |
1.2 (AOP 동작방식/SpringMVC-기본 출력, @RequestParam (String,int 값 생략 시) ) (0) | 2024.01.03 |