TIL 0621

먼지·2024년 6월 21일

Today I Learned

목록 보기
82/89
post-thumbnail

이론

MyBatis 한국어

설정 사항

실습

라이브러리 추가

pom.xml

		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis-spring</artifactId>
			<version>1.2.2</version>
		</dependency>
		<dependency>
			<groupId>org.mybatis</groupId>
			<artifactId>mybatis</artifactId>
			<version>3.2.2</version>
		</dependency>

root-Context.xml

JDBC 템플릿 삭제, Mybatis 설정 추가

<!--MyBatis 설정 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:config/SqlMapConfig.xml"/>
		<property name="dataSource" ref="dataSource"/>
	</bean>
	
	<!-- 생성자 전달 방식으로 전달 -->
	<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
		<constructor-arg ref="sqlSessionFactory"/>
	</bean>

main/resources > config > SqlMapConfig.xml

BoardVo만 지금 추가해놨지만 추가적으로 명시해야 하는 부분들은 typeAliases에다가 추가를 해주면 된다.

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "HTTP://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeAliases>
		<typeAlias type="kr.spring.board.vo.BoardVO" alias="boardVO"/>
	</typeAliases>
	
	<mappers>
		<!-- resource - 경로 형태로 위치를 지정해준다. -->
		<mapper resource="kr/spring/board/dao/BoardMapper.xml"/>
	</mappers>
</configuration>

kr.spring.board.vo

Board VO

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;
	
	
	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 + "]";
	}

}
	

kr.spring.board.dao

Board DAO

Interface 형태로 생성

package kr.spring.board.dao;

import java.util.List;
import java.util.Map;

import kr.spring.board.vo.BoardVO;

// 구조를 넣기 위해 생성
public interface BoardDAO {
	public void insertBoard(BoardVO board);
	public int selectBoardCount();
	
	// map으로 묶어서 보내기 object는 검색의 경우(지금은 검색이 없기 때문에 Integer를 보낸다)
	// mybatis는 하나의 인자만 사용한다. 무조건적으로 map으로 묶어서 보내야한다. (규칙)
	// 인자 1개(map), 반환 타입 1개
	// Sql Session Template를 사용하기 때문에 규칙을 따라야 한다.
	public List<BoardVO> selectBoardList(Map<String, Integer> map);
	
	public BoardVO selectBoard(int num);
	public void updateBoard(BoardVO board);
	public void deleteBoard(int num);
}
	

Board DAO Impl

개수 구하기

  • selectOne 메서드는 MyBatis 프레임워크에서 사용되는 메서드로, SQL 쿼리를 실행하여 단일 결과 값을 반환할 때 사용한다.
    sql 문장을 읽어오는 식별자(ID)를 명시하는데 해당 식별자는 sql 문장을 작성할 때 부여할 수 있다.
@Override
	public int selectBoardCount() {
		return sqlSessionTemplate.selectOne("selectBoardCount");
	}

목록 호출

  • map 안에 key와 value가 함께 저장이 되어있다.
    selectBoardList = 아이디
    map = ?에 전달하는 Data를 갖고 있다
@Override
	public List<BoardVO> selectBoardList(Map<String, Integer> map) {
		return sqlSessionTemplate.selectList("selectBoardList",map);
	}

글 등록하기

  • selectDetail = 아이디
    num = 전달해줘야 하는 Data
@Override
	public BoardVO selectBoard(int num) {
		return sqlSessionTemplate.selectOne("selectDetail", num);
	}

글 수정하기

  • updateBoard = 아이디
    board = 전달해줘야 하는 Data
@Override
	public void updateBoard(BoardVO board) {
		sqlSessionTemplate.selectOne("updateBoard", board);
	}

글 삭제하기

  • deleteBoard = 아이디
    num = 전달해줘야 하는 Data
	@Override
	public void deleteBoard(int num) {
		sqlSessionTemplate.selectOne("deleteBoard", num);
	}

전체 코드

package kr.spring.board.dao;

import java.util.List;
import java.util.Map;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import kr.spring.board.vo.BoardVO;

@Repository
public class BoardDAOImpl implements BoardDAO {
	
	// sql session template를 사용하기 때문에 autowired를 통해 주입 받는다.
	@Autowired
	private SqlSessionTemplate sqlSessionTemplate;
		
	@Override
	public void insertBoard(BoardVO board) {
		sqlSessionTemplate.insert("insertBoard", board);
	}

	@Override
	public int selectBoardCount() {
		//  MyBatis 프레임워크에서 사용되는 메서드로, SQL 쿼리를 실행하여 단일 결과 값을 반환할 때 사용
		// sql 문장을 읽어오는 식별자를 명시(ID) 
		// sql문장에 id를 부여하는데 해당 id를 제공
		// int를 반환해줌
		return sqlSessionTemplate.selectOne("selectBoardCount");
	}

	@Override
	public List<BoardVO> selectBoardList(Map<String, Integer> map) {
		// map 안에 key와 value가 함께 저장이 되어있다.
											// ID				?에 전달할 Data 갖고 있음
		return sqlSessionTemplate.selectList("selectBoardList",map);
	}

	@Override
	public BoardVO selectBoard(int num) {
		return sqlSessionTemplate.selectOne("selectDetail", num);
	}

	@Override
	public void updateBoard(BoardVO board) {
		sqlSessionTemplate.selectOne("updateBoard", board);
	}

	@Override
	public void deleteBoard(int num) {
		sqlSessionTemplate.selectOne("deleteBoard", num);
	}
}

Board Mapper XML

Board DAO의 Mapper

총 레코드 수 구하는 SQL

  • 반환 타입(resultType)를 작성해줘야 한다.
    원래는 클래스 형으로 작성을 해야하는데 alias가 지정되어있기 때문에 integer로 작성이 가능하다.
    ID는 BoardDAOImpl에서 명시했던 것과 동일하게 작성
	<select  id="selectBoardCount" resultType="integer">
		SELECT COUNT(*) FROM aboard
	</select >

List 구하는 SQL

  • 컬럼명=자바빈 동일하다면 자동 mapping
    전달 타입(parameterType) = map
    반환 타입(resultType) = boardVO 실제 데이터가 담기는 빈을 명시
    list가 resultType이 아닌 이유는 전체의 결과 반환 타입이 리스트이기 때문
    비교 연산자(<=, >=) 에러 -> xml의 특수문자(태그 명시에 사용)이기 때문에 에러가 발생함 해당하는 블럭이 xml 문법 체크를 하지 않도록 설정을 해줘야한다.
    cdatasection(<![CDATA[에러가 발생하는 코드 내부 작성]]>) -> xml 문법 체크를 하지 않도록 설정하는 태그
    key = start, end 키를 사용
    #{start} , #{end} 로 명시해야 한다 (Mybatis 규칙)
    Board DAO Impl에서 ID로 sql을 받고, map을 받아서 처리
<select id="selectBoardList" parameterType="map" resultType="boardVO">
	SELECT * FROM(SELECT a.*,rownum rnum FROM (SELECT * FROM aboard ORDER BY num DESC)a) 
	<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
	]]>
	</select>

글 작성하기

  • 자바빈에 담아서 값을 보내기 때무에 parameterType = boardVO
	<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>

글 수정하기

  • 자바빈에 담아서 값을 보내기 때문에 parameterType = boardVO
<!-- 글 수정하기 -->
	<update id="updateBoard" parameterType="boardVO">
		UPDATE aboard SET writer=#{writer}, title=#{title}, content=#{content} WHERE num=#{num}
	</update>

글 삭제하기

  • 보내는 값이 num이기 때문에 parameterType = integer
	<delete id="deleteBoard" parameterType="integer">
		DELETE FROM aboard WHERE num=#{num}
	</delete>

전체 코드

<?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.BoardDAO">
	<!-- 총 레코드 수 구하는 sql -->
	<!-- 반환 타입 명시(클래스형으로 작성) alias가 있기 때문에 integer로 작성이 가능-->
	<!-- BoardDAOImpl에서 명시했던 id와 동일하게 작성! -->
	<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 num DESC)a) 
	<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
	]]>
	</select>
	
	<!-- 글 작성하기 -->
	<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>
	
	<!-- 해당하는 글 불러오기 -->
	<select id="selectDetail" parameterType="integer" resultType="boardVO">
		SELECT * FROM aboard WHERE num = #{num}
	</select>
	
	<!-- 글 수정하기 -->
	<update id="updateBoard" parameterType="boardVO">
		UPDATE aboard SET writer=#{writer}, title=#{title}, content=#{content} WHERE num=#{num}
	</update>
	
	<!-- 글 삭제하기 -->
	<delete id="deleteBoard" parameterType="integer">
		DELETE FROM aboard WHERE num=#{num}
	</delete>
 </mapper>

kr.spring.board.service

Board Service

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);
}

Board Service Impl

리스트 불러오기 (count, list)

	@Override
	public int selectBoardCount() {
		return boardDAO.selectBoardCount();
	}

	@Override
	public List<BoardVO> selectBoardList(Map<String, Integer> map) {
		return boardDAO.selectBoardList(map);
	}

글 작성하기

@Override
	public void insertBoard(BoardVO board) {
		boardDAO.insertBoard(board);
	}

글 수정하기

@Override
	public void updateBoard(BoardVO board) {
		boardDAO.updateBoard(board);
	}

글 삭제하기

@Override
	public void deleteBoard(int num) {
		boardDAO.deleteBoard(num);
	}

전체 코드

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.BoardDAO;
import kr.spring.board.vo.BoardVO;

@Service
@Transactional
public class BoardServiceImpl implements BoardService{

	@Autowired
	private BoardDAO boardDAO;
	
	@Override
	public void insertBoard(BoardVO board) {
		boardDAO.insertBoard(board);
	}

	@Override
	public int selectBoardCount() {
		return boardDAO.selectBoardCount();
	}

	@Override
	public List<BoardVO> selectBoardList(Map<String, Integer> map) {
		return boardDAO.selectBoardList(map);
	}

	@Override
	public BoardVO selectBoard(int num) {
		return boardDAO.selectBoard(num);
	}

	@Override
	public void updateBoard(BoardVO board) {
		boardDAO.updateBoard(board);
	}

	@Override
	public void deleteBoard(int num) {
		boardDAO.deleteBoard(num);
	}

}

kr.spring.board.controller

Board Controller

리스트 불러오기

pageNum이라는 요청 매개변수를 받아 현재 페이지 번호로 사용
pageNum이 제공되지 않으면 기본값으로 1을 사용

@RequestParam(value = "pageNum", defaultValue = "1")

총 레코드 수를 구하고, 콘솔에 count된 값 출력

int count = boardService.selectBoardCount();
log.debug("<<count>> : " + count );

PagingUtil 객체를 생성하여 페이지 처리
currentPage는 현재 페이지, count는 총 게시물 수, 20은 한 페이지당 게시물 수, 10은 페이지 블록 수, "list.do"는 페이지 요청 URL

PagingUtil page = new PagingUtil(currentPage, count, 20,10,"list.do"); 

총 게시물 수가 0보다 크면, 페이지 시작과 끝 행 번호를 map에 담아 boardService를 통해 게시물 목록을 가져온다.

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 객체를 생성하고, 뷰 이름을 "selectList"로 설정
또한, 게시물 수(count), 게시물 목록(list), 페이지 정보(page)를 모델에 추가 후 반환

ModelAndView mav = new ModelAndView();
mav.setViewName("selectList");
mav.addObject("count", count);
mav.addObject("list", list);
mav.addObject("page", page.getPage());
return mav;

글 작성하기 폼& 등록

  1. 유효성 체크를 위한 폼 초기화
	@ModelAttribute
		public BoardVO initCommand() {
			return new BoardVO();
		}
  1. 폼 호출하기
	@GetMapping("/insert.do")
	public String insertForm() {
		return "insertForm";
	}
  1. 폼 등록하기
  • 로그 호출로 등록되는 데이터 확인
  • 유효성 체크 -> 에러가 있다면 Form으로 돌아가기
  • 유효성 체크 문제 없으면 글 삽입하기(vo의 데이터 넣어서)
  • 글 쓰기가 문제 없이 동작한 후 list로 돌아가기
	@PostMapping("/insert.do")
	public String submit(@Valid BoardVO vo, BindingResult result) {
		// 로그 호출
		log.debug("<<BoardVo>> : " + vo);
		// 유효성 체크
		if(result.hasErrors()) {
			return insertForm();
		}
		// 글 삽입
		boardService.insertBoard(vo);
		
		return "redirect:/list.do";
	}

글 상세보기

num이라는 정수형 매개변수
반환 타입은 ModelAndView로, 이는 뷰의 이름과 모델 데이터를 포함하여 반환
boardService라는 서비스 객체의 selectBoard 메서드를 호출하여 num에 해당하는 게시판 글 불러옴
해당 메서드는 BoardVO 객체를 반환한다.
새로운 ModelAndView 객체를 생성하여 반환
첫 번째 인자는 뷰의 이름 selectDetail
두 번째 인자는 모델의 속성 이름인 board
세 번째 인자는 모델의 속성 값인 board 객체
이 반환 값은 뷰에서 board 데이터를 사용할 수 있도록 전달한다.

	@RequestMapping("/detail.do")
	public ModelAndView detail(int num) {
		log.debug("<<num>> : " + num);

		BoardVO board = boardService.selectBoard(num);
		// 뷰 이름 속성명 속성값
		return new ModelAndView("selectDetail", "board", board);
	}

글 수정하기 폼 & 수정

  1. 글 수정하는 폼 호출하기
    num: 요청 매개변수로 전달된 게시물 번호, 스프링은 자동으로 URL 쿼리 파라미터 num의 값을 이 변수에 매핑
    model: 뷰(View)에 데이터를 전달하기 위한 모델 객체, 이 객체를 사용하여 컨트롤러에서 뷰로 데이터를 전달 가능
model.addAttribute("boardVO", boardService.selectBoard(num));

뷰에 전달할 데이터를 추가하는 메서드
boardVO는 뷰에서 사용할 데이터의 키, 해당 이름으로 데이터를 뷰에서 참조
num에 해당하는 게시물 정보를 가져오기 위해 서비스 계층의 selectBoard 메서드를 호출
selectBoard(num) 호출 결과를 boardVO라는 이름으로 모델에 추가

	@GetMapping("/update.do")
	public String updateForm(int num, Model model) {
		model.addAttribute("boardVO", boardService.selectBoard(num));
		return "updateForm";
	}
  1. 글 수정하기
    글을 수정할 때도 유효성 체크는 해야하기 때문에 어노테이션 @Valid 추가
    유효성 체크에서 걸리면 updateForm으로 돌아가고
    비밀번호 확인 시 오류가 발생한다면 invalidPassword 오류 코드 생성하여 오류 메세지를 띄운다.
    모두 문제가 없다면 vo에 저장된 값들로 수정된다.
	@PostMapping("/update.do")
	public String submitUpdate(@Valid BoardVO vo, BindingResult result) {
		log.debug("<<UpdateBoardVO>> : "+ vo);
		if(result.hasErrors()) {
			return "updateForm";
		}
		// DB에서 저장된 
		BoardVO db_board = boardService.selectBoard(vo.getNum());
		
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
				result.rejectValue("passwd", "invalidPassword");
				return "updateForm";
			}
		
		boardService.updateBoard(vo);
		
		return "redirect:/list.do";
	}

글 삭제하기 폼 & 삭제

  1. 글 삭제 폼 호출하기
    BoardVO vo를 넣는 이유는 detail로 들어가서 삭제를 해야 하기 때문이다.
@GetMapping("/delete.do")
	public String deleteForm(BoardVO vo) {
		return "deleteForm";
	}
  1. 글 삭제하기
    유효성 체크를 해야 하기 때문에 @Valid 어노테이션을 써주고, passwd의 필드만 유효성 체크를 하면 되기 때문에 hasFieldErrors라는 메서드를 사용하여 필드를 지정하여 에러 확인을 해준다.
    만약 result.hasErrors()라고 쓰게 된다면 다른 값들이 넘어오지 않기 때문에 계속 오류가 있다고 판단하여 동작이 되지 않는다.
    등록된 글의 비밀번호와 입력된 비밀번호가 같은지 체크 후, 같지 않다면 invalidPassword 오류 코드를 생성하여 오류 메세지를 띄운다.
    모두 문제 없이 완료가 되면 해당 글의 번호를 받아서 삭제 처리를 한다.
	@PostMapping("/delete.do")
	public String submitDelete(@Valid BoardVO vo, BindingResult result) {

		log.debug("<<Delete Board>> : " + vo);

		if (result.hasFieldErrors("passwd")) {
			return "deleteForm";
		}

		// DB에서 저장된
		BoardVO db_board = boardService.selectBoard(vo.getNum());

		if (!db_board.getPasswd().equals(vo.getPasswd())) {
			result.rejectValue("passwd", "invalidPassword");
			return "deleteForm";
		}
		
		boardService.deleteBoard(vo.getNum());
			
		return "redirect:/list.do";
	}

전체 코드

package kr.spring.board.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import kr.spring.board.service.BoardService;
import kr.spring.board.vo.BoardVO;
import kr.spring.util.PagingUtil;

@Controller
public class BoardController {
	@Autowired
	private BoardService boardService;

	// 유효성 체크를 위한 폼 초기화
	@ModelAttribute
	public BoardVO initCommand() {
		return new BoardVO();
	}

	// 로그 처리하기
	private static final Logger log = LoggerFactory.getLogger(BoardController.class);

	@RequestMapping("/list.do")
	// pageutil 에서 사용하는 값
	public ModelAndView getList(@RequestParam(value = "pageNum", defaultValue = "1") int currentPage) {
		// 총 레코드 수
		int count = boardService.selectBoardCount();
		log.debug("<<count>> : " + count);

		// 페이지 처리하기
		PagingUtil page = new PagingUtil(currentPage, count, 20, 10, "list.do");

		// 목록 호출하기
		List<BoardVO> list = null;
		if (count > 0) {
			// map에 담겨서 넘기기 때문에 map 생성
			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;
	}

	// 폼 호출하기
	@GetMapping("/insert.do")
	public String insertForm() {
		return "insertForm";
	}

	// 폼 등록하기
	@PostMapping("/insert.do")
	public String submit(@Valid BoardVO vo, BindingResult result) {
		// 로그 호출
		log.debug("<<BoardVo>> : " + vo);
		// 유효성 체크
		if (result.hasErrors()) {
			return insertForm();
		}
		// 글 삽입
		boardService.insertBoard(vo);

		return "redirect:/list.do";
	}

	// 글 상세보기
	@RequestMapping("/detail.do")
	public ModelAndView detail(int num) {
		log.debug("<<num>> : " + num);

		BoardVO board = boardService.selectBoard(num);
		// 뷰 이름 속성명 속성값
		return new ModelAndView("selectDetail", "board", board);
	}

	// 글 수정 폼 호출하기
	@GetMapping("/update.do")
	public String updateForm(int num, Model model) {
		model.addAttribute("boardVO", boardService.selectBoard(num));
		return "updateForm";
	}
	
	// 글 수정하기
	@PostMapping("/update.do")
	public String submitUpdate(@Valid BoardVO vo, BindingResult result) {
		log.debug("<<UpdateBoardVO>> : "+ vo);
		if(result.hasErrors()) {
			return "updateForm";
		}
		// DB에서 저장된 
		BoardVO db_board = boardService.selectBoard(vo.getNum());
		
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
				result.rejectValue("passwd", "invalidPassword");
				return "updateForm";
			}
		
		boardService.updateBoard(vo);
		
		return "redirect:/list.do";
	}
	
	// 글 삭제하기 폼 호출하기
	@GetMapping("/delete.do")
	public String deleteForm(BoardVO vo) {
		return "deleteForm";
	}
	
	// 글 삭제하기
	@PostMapping("/delete.do")
	public String submitDelete(@Valid BoardVO vo, BindingResult result) {

		log.debug("<<Delete Board>> : " + vo);

		if (result.hasFieldErrors("passwd")) {
			return "deleteForm";
		}

		// DB에서 저장된
		BoardVO db_board = boardService.selectBoard(vo.getNum());

		if (!db_board.getPasswd().equals(vo.getPasswd())) {
			result.rejectValue("passwd", "invalidPassword");
			return "deleteForm";
		}
		
		boardService.deleteBoard(vo.getNum());
			
		return "redirect:/list.do";
	}
}

Annotation 사용하기

Root-Context XML

자동 스캔 방법을 사용함
알리아스로 명시하는데 더 설정해야 하는 경우 ,를 사용해서 추가 가능하고, *를 통해서도 작성이 가능하다.

<!-- 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">
		<!-- xml 파일 등록 -->
		<property name="basePackage" value="kr.spring.board.dao"/>
	</bean>

kr.spring.board.vo

Board VO

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;
	
	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 + "]";
	}
}

kr.spring.board.controller

상단의 코드와 동일하게 작성되어 있기 때문에 추가적은 설명은 없이 지나감

Board Controller

package kr.spring.board.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.validation.Valid;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
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.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;

import kr.spring.board.service.BoardService;
import kr.spring.board.vo.BoardVO;
import kr.spring.util.PagingUtil;

@Controller
public class BoardController {
	@Autowired
	private BoardService boardService;
	//로그 처리(로그 대상 지정)
	private static final Logger log = 
			LoggerFactory.getLogger(BoardController.class);
	
	//유효성 체크를 위한 자바빈(VO) 초기화
	@ModelAttribute
	public BoardVO initCommand(){
		return new BoardVO();
	}
	//글쓰기 폼 호출
	@GetMapping("/insert.do")
	public String form() {
		return "insertForm";
	}
	//전송된 데이터 처리
	@PostMapping("/insert.do")
	public String submit(@Valid BoardVO vo, 
			                  BindingResult result) {
		log.debug("<<BoardVO>> : " + vo);
		
		//유효성 체크 결과 오류가 있으면 폼 호출
		if(result.hasErrors()) {
			return form();
		}
		//글쓰기
		boardService.insertBoard(vo);
		
		return "redirect:/list.do";
	}
	
	//목록
	@RequestMapping("/list.do")
	public ModelAndView getList(
			@RequestParam(value="pageNum",
			          defaultValue="1") int currentPage) {
		//총레코드 수
		int count = boardService.selectBoardCount();
		//페이지 처리
		PagingUtil page = 
			new PagingUtil(currentPage,count,20,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;
	}
	//글상세
	@RequestMapping("/detail.do")
	public ModelAndView detail(int num) {
		BoardVO board = 
				boardService.selectBoard(num);
		return new ModelAndView("selectDetail","board",board);
	}
	//수정 폼 호출
	@GetMapping("/update.do")
	public String formUpdate(int num,Model model) {
		model.addAttribute("boardVO", 
				boardService.selectBoard(num));
		
		return "updateForm";
	}
	//전송된 데이터 처리
	@PostMapping("/update.do")
	public String submitUpdate(@Valid BoardVO vo,
			                   BindingResult result) {
		log.debug("<<BoardVO>> : " + vo);
		
		//유효성 체크 결과 오류가 있으면 폼 호출
		if(result.hasErrors()) {
			return "updateForm";
		}
		
		//비밀번호 일치 여부 체크
		//DB에 저장된 비밀번호 구하기
		BoardVO db_board = 
				boardService.selectBoard(vo.getNum());
		//비밀번호 체크
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
			result.rejectValue("passwd", "invalidPassword");
			return "updateForm";
		}
		
		//글 수정
		boardService.updateBoard(vo);		
		
		return "redirect:/list.do";
	}
	//글 삭제 폼 호출
	@GetMapping("/delete.do")
	public String formDelete(BoardVO vo) {
		return "deleteForm";
	}
	//글 삭제 처리
	@PostMapping("/delete.do")
	public String submitDelete(@Valid BoardVO vo,
			                   BindingResult result) {
		log.debug("<<BoardVO>> : " + vo);
		
		//유효성 체크 결과 오류가 있으면 폼 호출
		//비밀번호 전송 여부만 체크
		if(result.hasFieldErrors("passwd")) {
			return "deleteForm";
		}
		//비밀번호 일치 여부 체크
		//DB에 저장된 비밀번호 구하기
		BoardVO db_board = 
				boardService.selectBoard(vo.getNum());
		//비밀번호 체크
		if(!db_board.getPasswd().equals(vo.getPasswd())) {
			result.rejectValue("passwd", "invalidPassword");
			return "deleteForm";
		}
		//글 삭제
		boardService.deleteBoard(vo.getNum());
		
		return "redirect:/list.do";
	}
}

kr.spring.board.dao

Board Mapper

인터페이스는 윗 부분의 코드처럼 객체를 생성 할 수 없고, 객체 생성을 위해서는 클래스가 존재해야 한다. 그러나 어노테이션 방법을 사용하면 mybatis가 자동으로 implement를 해서 자동으로 생성해주기 때문에 클래스를 생성할 필요가 없어졌다.

어노테이션 @Insert를 사용해서 SQL Insert 구문을 작성할 수 있다.
#{} 객체의 속성값을 SQL 구문에 매핑할 수 있다.
해당하는 insert 구문은 컬럼명과 객체의 속성값을 모두 다 입력하면 코드가 길어지기 때문에 XML에 입력하는 것이 깔끔하겠지만 모든 값을 순서대로 작성해주면 그대로 잘 값이 입력되기 때문에 컬럼명은 생략 후 SQL문을 작성했다.

글 생성

@Insert("INSERT INTO aboard VALUES(aboard_seq.nextval,#{writer},#{title},#{passwd},#{content},SYSDATE)")
		public void insertBoard(BoardVO board);

@Select 어노테이션을 사용하여 SQL SELECT 구문을 작성할 수 있다.

총 개수 구하기

@Select("SELECT COUNT(*) FROM aboard")
		public int selectBoardCount();

글 목록은 SQL 구문이 길기 때문에 Board Mapper XML에 작성해주었다.

글 목록

public List<BoardVO> selectBoardList(Map<String, Integer> map);

@Select 어노테이션을 사용하여 SQL Select 구문을 작성할 수 있다.
#{} num의 속성값을 SQL 구문에 매핑한다.

글 세부

@Select("SELECT * FROM aboard WHERE num=#{num}")
		public BoardVO selectBoard(int num);

@Update 어노테이션을 이용하여 SQL Update 구문을 작성할 수 있다.
#{} 객체의 속성값들을 SQL 구문에 매핑해준다.

글 수정

@Update("UPDATE aboard SET writer=#{writer}, title=#{title}, content=#{content} WHERE num=#{num}")
		public void updateBoard(BoardVO board);

@Delete 어노테이션을 사용하여 SQL Delete 구문을 작성할 수 있다.
#{} num의 속성값을 SQL 구문에 매핑한다.

글 삭제

@Delete("DELETE FROM aboard WHERE num=#{num}")
		public void deleteBoard(int num);

전체 코드

package kr.spring.board.dao;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.annotations.Delete;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;
import org.apache.ibatis.annotations.Update;

import kr.spring.board.vo.BoardVO;

// mybatis가 자동으로 implement 해서 생성시켜준다
public interface BoardMapper {
		@Insert("INSERT INTO aboard VALUES(aboard_seq.nextval,#{writer},#{title},#{passwd},#{content},SYSDATE)")
		public void insertBoard(BoardVO board);
		
		@Select("SELECT COUNT(*) FROM aboard")
		public int selectBoardCount();
		
		public List<BoardVO> selectBoardList(Map<String, Integer> map);
		
		@Select("SELECT * FROM aboard WHERE num=#{num}")
		public BoardVO selectBoard(int num);
		
		@Update("UPDATE aboard SET writer=#{writer}, title=#{title}, content=#{content} WHERE num=#{num}")
		public void updateBoard(BoardVO board);
		
		@Delete("DELETE FROM aboard WHERE num=#{num}")
		public void deleteBoard(int num);
		
		
}

Board Mapper XML

매퍼 파일(BoardMapperXML)과 Java 인터페이스(BoardMapper)를 연결하는데 두 이름이 동일해야한다. namespace 속성은 이 매퍼 파일이 kr.spring.board.dao.BoardMapper 인터페이스와 연관되어 있음을 나타낸다.
목록 불러오는 sql 문장만 xml에 명시하는 이유는 너무 길기 때문에 어노테이션 방식보다 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">  

<!-- interface명칭과 xml의 명칭이 동일해야 한다 -->
<mapper namespace="kr.spring.board.dao.BoardMapper">
	<!-- 목록 가져오기 , 아이디는 따로 명시하지 않았음 그러나 메소드 명을 아이디로 사용 가능함-->
 	<select id="selectBoardList" parameterType="map" resultType="boardVO">
		SELECT * FROM(SELECT a.*,rownum rnum FROM (SELECT * FROM aboard ORDER BY num DESC)a) 
		<![CDATA[
		WHERE rnum >= #{start} AND rnum <= #{end}
		]]>
	</select>
 </mapper>

kr.spring.board.service

Board Service

상단의 코드와 동일하게 쓰여있음

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);
}

Board Service Impl

상단의 코드와 동일하게 작성되어 있음

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
	private BoardMapper boardMapper;
	
	@Override
	public void insertBoard(BoardVO board) {
		boardMapper.insertBoard(board);
	}

	@Override
	public int selectBoardCount() {
		return boardMapper.selectBoardCount();
	}

	@Override
	public List<BoardVO> selectBoardList(Map<String, Integer> map) {
		return boardMapper.selectBoardList(map);
	}

	@Override
	public BoardVO selectBoard(int num) {
		return boardMapper.selectBoard(num);
	}

	@Override
	public void updateBoard(BoardVO board) {
		boardMapper.updateBoard(board);
	}

	@Override
	public void deleteBoard(int num) {
		boardMapper.deleteBoard(num);
	}

}
profile
Lucky Things🍀

0개의 댓글