공부방
동적쿼리&트랜잭션 본문
동적 SQL
- Runtime시점에서 사용자의 입력 값에 따라 동적으로 SQL을 생성하여 실행하는 방식
- JDBC나 다른 Framework 사용 시 어려움을 느낄 수 있음
- MyBatis는 이를 편리하게 사용할 수 있게 도움을 줌
- JSTL이나 XML기반의 텍스트 프로세서를 사용해본 사람에게는 친숙할 것이다.
첫 웹페이지에 리스트 나열하고 검색기능 만들기
<%@ 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>
<%@ include file="../common/bootstrap.jsp" %>
</head>
<body>
<div class="container">
<h2>게시글 목록</h2>
<hr>
<div>
<table class="table text-center">
<tr>
<th>번호</th>
<th>제목</th>
<th>글쓰니</th>
<th>조회수</th>
<th>등록날짜</th>
</tr>
<c:forEach items="${list}" var="board">
<tr>
<td>${board.id}</td>
<td><a href="detail?id=${board.id}">${board.title}</a></td>
<td>${board.writer}</td>
<td>${board.viewCnt}</td>
<td>${board.regDate}</td>
</tr>
</c:forEach>
</table>
<form action="search" class="row">
<div class="col-2">
<label>검색 기준 :</label>
<select name="key" class="form-select">
<option value="none">없음</option>
<option value="writer">글쓰니</option>
<option value="title">제목</option>
<option value="content">내용</option>
</select>
</div>
<div class="col-5">
<label>검색 내용 :</label>
<input type="text" name="word" class="form-control">
</div>
<div class="col-2">
<label>정렬 기준 :</label>
<select name="orderBy" class="form-select">
<option value="none">없음</option>
<option value="writer">글쓰니</option>
<option value="title">제목</option>
<option value="view_cnt">조회수</option>
</select>
</div>
<div class="col-2">
<label>정렬 방향 :</label>
<select name="orderByDir" class="form-select">
<option value="asc">오름차순</option>
<option value="desc">내림차순</option>
</select>
</div>
<div class="col-1">
<input type="submit" value="검색" class="btn btn-primary">
</div>
</form>
<div class="d-flex justify-content-end">
<a class="btn btn-outline-primary" href="writeform">글등록</a>
</div>
</div>
</div>
</body>
</html>
새로운 검색 객체를 만들어준다.
SearchCondition.java
package com.ssafy.board.model.dto;
public class SearchCondition {
private String key;
private String word;
private String orderBy;
private String orderByDir; //JSP 만든 name과 이름을 동일시 해야 알잘로 넣어주더라...
public SearchCondition() { //기본생성자는 습관처럼 만들자.
}
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getWord() {
return word;
}
public void setWord(String word) {
this.word = word;
}
public String getOrderBy() {
return orderBy;
}
public void setOrderBy(String orderBy) {
this.orderBy = orderBy;
}
public String getOrderByDir() {
return orderByDir;
}
public void setOrderByDir(String orderByDir) {
this.orderByDir = orderByDir;
}
}
===================================================================
BoardDao.java
package com.ssafy.board.model.dao;
import java.util.List;
import com.ssafy.board.model.dto.Board;
import com.ssafy.board.model.dto.SearchCondition;
public interface BoardDao {
// 전체 게시글을 몽땅 들고 오쎄용
public List<Board> selectAll();
// ID에 해당하는 게시글 하나 가져오기
public Board selectOne(int id);
// 게시글 등록
public void insertBoard(Board board);
// 게시글 삭제
public void deleteBoard(int id);
// 게시글 수정
public void updateBoard(Board board);
// 조회수 증가
public void updateViewCnt(int id);
검색 기능을 추가해줬다.
//검색기능
public List<Board> search(SearchCondition condition);
}
====================================================================
BoardService.java
package com.ssafy.board.model.service;
import java.util.List;
import com.ssafy.board.model.dto.Board;
import com.ssafy.board.model.dto.SearchCondition;
//사용자 친화적으로
public interface BoardService {
//게시글 전체 조회
public List<Board> getBoardList();
//게시글 상세조회 (클릭시 읽는거)
public Board readBoard(int id);
//게시글 작성
public void writeBoard(Board board);
//게시글 삭제
public void removeBoard(int id);
//게시글 수정
public void modifyBoard(Board board);
여기도 검색 버튼 추가
//검색 버튼을 눌렀을 때 처리하기 위한 메서드
public List<Board> search(SearchCondition condition);
}
====================================================================
BoardServiceImpl.java
package com.ssafy.board.model.service;
import java.nio.charset.CodingErrorAction;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ssafy.board.model.dao.BoardDao;
import com.ssafy.board.model.dto.Board;
import com.ssafy.board.model.dto.SearchCondition;
@Service
public class BoardServiceImpl implements BoardService {
private BoardDao boardDao;
//Dao 인스턴스를 주입 해준다. (서7유지나)
@Autowired
public void setBoardDao(BoardDao boardDao) {
this.boardDao = boardDao;
}
@Override
public List<Board> getBoardList() {
System.out.println("모든 게시글을 가지고 왔습니다.");
return boardDao.selectAll();
}
@Override
public Board readBoard(int id) {
System.out.println(id+"번의 글을 읽습니다.");
boardDao.updateViewCnt(id);
return boardDao.selectOne(id);
}
@Transactional
@Override
public void writeBoard(Board board) {
System.out.println("게시글을 작성합니다.");
// boardDao.insertBoard(board);
boardDao.insertBoard(board);
}
@Transactional
@Override
public void removeBoard(int id) {
System.out.println(id+"번의 글을 삭제합니다.");
boardDao.deleteBoard(id);
}
@Transactional
@Override
public void modifyBoard(Board board) {
System.out.println("게시글을 수정합니다.");
boardDao.updateBoard(board);
}
서비스에서 추가한 인터페이스를 클래스에도 추가
@Override
public List<Board> search(SearchCondition condition) {
return boardDao.search(condition);
}
}
====================================================================
boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssafy.board.model.dao.BoardDao">
<resultMap type="Board" id="boardMap">
<result column="id" property="id"/>
<result column="writer" property="writer"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="view_cnt" property="viewCnt"/>
<result column="reg_date" property="regDate"/>
</resultMap>
<!-- 전체글 조회 -->
<select id="selectAll" resultType="Board">
SELECT id, content, writer, title, view_cnt as viewCnt, date_format(reg_date, '%y-%m-%d %H:%i:%s') as regDate
FROM board;
</select>
<!-- 상세글 조회 -->
<select id="selectOne" parameterType="int" resultMap="boardMap">
SELECT id, content, writer, title, view_cnt, date_format(reg_date, '%y-%m-%d') as reg_date
FROM board
WHERE id = #{id};
</select>
<!-- 게시글 등록 -->
<insert id="insertBoard" parameterType="Board" keyProperty="id" useGeneratedKeys="true">
INSERT INTO board (id, title, writer, content)
VALUES (#{id}, #{title}, #{writer}, #{content})
</insert>
<!-- 게시글 삭제 -->
<delete id="deleteBoard" parameterType="int">
DELETE FROM board
WHERE id = #{id}
</delete>
<!-- 조회수 증가 -->
<update id="updateViewCnt" parameterType="int">
UPDATE board
SET view_cnt = view_cnt+1
WHERE id = #{id}
</update>
<!-- 게시글 수정 -->
<!-- 지금 게시글 날짜는 등록 날짜만 존재한다. 나중에 수정날짜도 같이 관리하게 된다면의 상황을보자ㅏ... -->
<update id="updateBoard" parameterType="Board">
UPDATE board
SET title = #{title}, content=#{content}, reg_date = now()
WHERE id=#{id}
</update>
<!-- 검색기능 -->
<select id="search" resultType="Board" parameterType="SearchCondition" >
SELECT id, content, writer, title, view_cnt as viewCnt, date_format(reg_date, '%y-%m-%d %H:%i:%s') as regDate
FROM board
<!-- 어떤 기준을 가지고 검색을 할거냐!!! -->
<if test="key != 'none'">
WHERE ${key} LIKE concat('%', #{word}, '%')
</if>
<!-- 어떤 기준으로 어떤 방향으로 정렬할래? -->
<if test="orderBy != 'none'">
ORDER BY ${orderBy} ${orderByDir}
</if>
</select>
</mapper>
====================================================================
BoardController.java
package com.ssafy.board.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.ssafy.board.model.dto.Board;
import com.ssafy.board.model.dto.SearchCondition;
import com.ssafy.board.model.service.BoardService;
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@GetMapping("/")
public String showIndex() {
//보여줄게 없어서 리스트로 바로 점프를뛰자
return "redirect:list";
}
@GetMapping("list")
public String list(Model model) {
List<Board> list = boardService.getBoardList();
model.addAttribute("list", list);
return "/board/list";
}
@GetMapping("writeform")
public String writeform() {
return "/board/writeform";
}
@PostMapping("write")
public String write(Board board) {
System.out.println("등록전 : "+board);
boardService.writeBoard(board);
System.out.println("등록후 : "+board);
// return "redirect:list"; // 이렇게 하지말고...
//게시글을 보고 싶다 상세보기로 바로 가고싶어...
return "redirect:detail?id="+board.getId();
}
@GetMapping("detail")
public String detail(Model model, int id) {
Board board = boardService.readBoard(id);
model.addAttribute("board", board);
return "/board/detail";
}
@GetMapping("delete")
public String delete(int id) {
boardService.removeBoard(id);
return "redirect:list";
}
@GetMapping("updateform")
public String updateform(Model model, int id) {
//지금 게시글 하나 가져오는건 readBoard 밖에 없다.
model.addAttribute("board", boardService.readBoard(id));
return "/board/updateform";
}
@PostMapping("update")
public String update(Board board) {
boardService.modifyBoard(board);
return "redirect:detail?id="+board.getId();
}
위에까지 추가한 검색 기능을 추가함.
// 검색기능 작성
@GetMapping("search")
// public String search(Model model, String key, String word, String or.....) //이거 지저분해 처리할게 많아보여...
public String search(Model model, SearchCondition condition ) {
model.addAttribute("list", boardService.search(condition));
return "/board/list";
}
}
게시글을 등록하면 바로 detail.jsp로 넘어가 상세페이지를 볼 수 있게 해주기
BoardController.java
package com.ssafy.board.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.ssafy.board.model.dto.Board;
import com.ssafy.board.model.dto.SearchCondition;
import com.ssafy.board.model.service.BoardService;
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@GetMapping("/")
public String showIndex() {
//보여줄게 없어서 리스트로 바로 점프를뛰자
return "redirect:list";
}
@GetMapping("list")
public String list(Model model) {
List<Board> list = boardService.getBoardList();
model.addAttribute("list", list);
return "/board/list";
}
@GetMapping("writeform")
public String writeform() {
return "/board/writeform";
}
이 부분에서 글을 등록하면 바로 detail페이지로 넘어가게 설정을 해준다.
@PostMapping("write")
public String write(Board board) {
System.out.println("등록전 : "+board);
boardService.writeBoard(board);
System.out.println("등록후 : "+board);
// return "redirect:list"; // 이렇게 하지말고...
//게시글을 보고 싶다 상세보기로 바로 가고싶어...
return "redirect:detail?id="+board.getId();
밑에 update부분처럼 바로 그 부분으로 넘어게 해준다.
이렇게만 설정하면 url에서 id=0으로 가면서 바로 안된다.
}
@GetMapping("detail")
public String detail(Model model, int id) {
Board board = boardService.readBoard(id);
model.addAttribute("board", board);
return "/board/detail";
}
@GetMapping("delete")
public String delete(int id) {
boardService.removeBoard(id);
return "redirect:list";
}
@GetMapping("updateform")
public String updateform(Model model, int id) {
//지금 게시글 하나 가져오는건 readBoard 밖에 없다.
model.addAttribute("board", boardService.readBoard(id));
return "/board/updateform";
}
@PostMapping("update")
public String update(Board board) {
boardService.modifyBoard(board);
return "redirect:detail?id="+board.getId();
}
// 검색기능 작성
@GetMapping("search")
// public String search(Model model, String key, String word, String or.....) //이거 지저분해 처리할게 많아보여...
public String search(Model model, SearchCondition condition ) {
model.addAttribute("list", boardService.search(condition));
return "/board/list";
}
}
===================================================================
boardMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ssafy.board.model.dao.BoardDao">
<resultMap type="Board" id="boardMap">
<result column="id" property="id"/>
<result column="writer" property="writer"/>
<result column="title" property="title"/>
<result column="content" property="content"/>
<result column="view_cnt" property="viewCnt"/>
<result column="reg_date" property="regDate"/>
</resultMap>
<!-- 전체글 조회 -->
<select id="selectAll" resultType="Board">
SELECT id, content, writer, title, view_cnt as viewCnt, date_format(reg_date, '%y-%m-%d %H:%i:%s') as regDate
FROM board;
</select>
<!-- 상세글 조회 -->
<select id="selectOne" parameterType="int" resultMap="boardMap">
SELECT id, content, writer, title, view_cnt, date_format(reg_date, '%y-%m-%d') as reg_date
FROM board
WHERE id = #{id};
</select>
여기서 keyProperty="id" useGeneratedKeys="true"를 추가해서 id를 바로 찾아줄 수 있게
등록한 아이디로 바꿔 줄 수 있게 설정해준다.
<!-- 게시글 등록 -->
<insert id="insertBoard" parameterType="Board" keyProperty="id" useGeneratedKeys="true">
INSERT INTO board (id, title, writer, content)
VALUES (#{id}, #{title}, #{writer}, #{content})
</insert>
<!-- 게시글 삭제 -->
<delete id="deleteBoard" parameterType="int">
DELETE FROM board
WHERE id = #{id}
</delete>
<!-- 조회수 증가 -->
<update id="updateViewCnt" parameterType="int">
UPDATE board
SET view_cnt = view_cnt+1
WHERE id = #{id}
</update>
<!-- 게시글 수정 -->
<!-- 지금 게시글 날짜는 등록 날짜만 존재한다. 나중에 수정날짜도 같이 관리하게 된다면의 상황을보자ㅏ... -->
<update id="updateBoard" parameterType="Board">
UPDATE board
SET title = #{title}, content=#{content}, reg_date = now()
WHERE id=#{id}
</update>
<!-- 검색기능 -->
<select id="search" resultType="Board" parameterType="SearchCondition" >
SELECT id, content, writer, title, view_cnt as viewCnt, date_format(reg_date, '%y-%m-%d %H:%i:%s') as regDate
FROM board
<!-- 어떤 기준을 가지고 검색을 할거냐!!! -->
<if test="key != 'none'">
WHERE ${key} LIKE concat('%', #{word}, '%')
</if>
<!-- 어떤 기준으로 어떤 방향으로 정렬할래? -->
<if test="orderBy != 'none'">
ORDER BY ${orderBy} ${orderByDir}
</if>
</select>
</mapper>
Spring Tx
- 데이터 무결성을 위해서 사용
- 스프링에서 제공하는 트랜잭션 기능을 활용할 수 있음
- jar or pom.xml을 이용하여 등록
'스프링' 카테고리의 다른 글
Swagger/CORS (0) | 2023.04.26 |
---|---|
REST API (0) | 2023.04.25 |
MyBatis-Spring (0) | 2023.04.20 |
MyBatis (0) | 2023.04.19 |
File Upload&File Download (0) | 2023.04.18 |