MyBatis의 게시판 기능에 대해 알아보자
🔥 게시판 상세 조회 & 댓글 리스트 조회 🔥
💻 boardListView.jsp
각각의 게시글마다 링크 걸기
<c:forEach var="b" items="${ list }">
<tr>
<td>${ b.boardNo }</td>
<td><a href="detail.bo?bno=${ b.boardNo }">${ b.boardTitle }</a></td>
<td>${ b.boardWriter }</td>
<td>${ b.count }</td>
<td>${ b.createDate }</td>
</tr>
</c:forEach>
💻 boardDetailView.jsp 생성 - 하드코딩 ver.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<style>
td>textarea {
width : 100%;
height : 100%;
resize : none;
box-sizing : border-box; /* 표 크기 밖으로 삐쳐 나가지 않고 맞추고 싶을 때 사용 */
}
</style>
</head>
<body>
<jsp:include page="../common/menubar.jsp" />
<div class="outer">
<br>
<h1 align="center">게시판 상세조회</h1>
<br>
<table align="center" border="1">
<!-- (tr>(td*2))*6 -->
<tr>
<td width="100">글번호</td>
<td width="500">10</td>
</tr>
<tr>
<td>제목</td>
<td>여기는 제목이 들어갈 자리 :)</td>
</tr>
<tr>
<td>작성자</td>
<td>user01</td>
</tr>
<tr>
<td>조회수</td>
<td>200</td>
</tr>
<tr>
<td>작성일</td>
<td>2022-11-14</td>
</tr>
<tr>
<td>내용</td>
<td height="100">
여기가 내용이 들어갈 자리*^_________^*
</td>
</tr>
</table>
<table align="center" border="1">
<!-- (tr>(td*3))*4 -->
<tr>
<td width="100">댓글 작성</td>
<td width="400"><textarea></textarea></td>
<td width="100"><button>등록</button></td>
</tr>
<tr>
<td colspan="3"><b>댓글 (2)</b></td>
</tr>
<tr>
<td>admin</td>
<td>우와 재미있어요</td>
<td>2022-11-14</td>
</tr>
<tr>
<td>user02</td>
<td>집에 언제 가요?</td>
<td>2022-11-14</td>
</tr>
</table>
</div>
</body>
</html>
💻 Reply 클래스 생성
package com.kh.mybatis.board.model.vo;
import java.sql.Date;
public class Reply {
// 필드부
private int replyNo; // REPLY_NO NUMBER PRIMARY KEY,
private String replyContent; // REPLY_CONTENT VARCHAR2(400),
private int refBoardNo; // REF_BNO NUMBER,
private String replyWriter; // REPLY_WRITER NUMBER,
private Date createDate; // CREATE_DATE DATE DEFAULT SYSDATE,
private String status; // STATUS VARCHAR2(1) DEFAULT 'Y' CHECK (STATUS IN ('Y', 'N')),
// 생성자부
public Reply() { }
public Reply(int replyNo, String replyContent, int refBoardNo, String replyWriter, Date createDate, String status) {
super();
this.replyNo = replyNo;
this.replyContent = replyContent;
this.refBoardNo = refBoardNo;
this.replyWriter = replyWriter;
this.createDate = createDate;
this.status = status;
}
// 메소드부
public int getReplyNo() {
return replyNo;
}
public void setReplyNo(int replyNo) {
this.replyNo = replyNo;
}
public String getReplyContent() {
return replyContent;
}
public void setReplyContent(String replyContent) {
this.replyContent = replyContent;
}
public int getRefBoardNo() {
return refBoardNo;
}
public void setRefBoardNo(int refBoardNo) {
this.refBoardNo = refBoardNo;
}
public String getReplyWriter() {
return replyWriter;
}
public void setReplyWriter(String replyWriter) {
this.replyWriter = replyWriter;
}
public Date getCreateDate() {
return createDate;
}
public void setCreateDate(Date createDate) {
this.createDate = createDate;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
@Override
public String toString() {
return "Reply [replyNo=" + replyNo + ", replyContent=" + replyContent + ", refBoardNo=" + refBoardNo
+ ", replyWriter=" + replyWriter + ", createDate=" + createDate + ", status=" + status + "]";
}
}
💻 BoardDetailController Servlet 생성
url mapping: /detail.bo
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 글 번호 먼저 뽑기 (bno)
int boardNo = Integer.parseInt(request.getParameter("bno"));
// 다형성을 적용
BoardService boardService = new BoardServiceImpl();
// 1. 조회수를 증가시키는 서비스 먼저 요청
int result = boardService.increaseCount(boardNo);
if(result > 0) { // 조회수가 성공적으로 증가되었다면
// 2. 해당 게시글을 상세 조회하는 서비스 요청
Board b = boardService.selectBoard(boardNo);
// 3. 해당 게시글에 딸린 댓글들을 조회하는 서비스 요청
// => 댓글 조회 기능을 동기식 방식으로 selectList 연습해 보기
ArrayList<Reply> list = boardService.selectReplyList(boardNo);
// 상세 조회 결과, 댓글 리스트 조회 결과 => request에 담기
request.setAttribute("b", b);
request.setAttribute("list", list);
request.getRequestDispatcher("WEB-INF/views/board/boardDetailView.jsp").forward(request, response);
} else {
// 에러 문구를 담아서 에러 페이지로 포워딩
request.setAttribute("errorMsg", "게시글 상세 조회 실패");
request.getRequestDispatcher("WEB-INF/views/common/errorPage.jsp").forward(request, response);
}
}
💻 BoardServiceImpl
@Override
public int increaseCount(int boardNo) {
SqlSession sqlSession = getSqlSession();
int result = boardDao.increaseCount(sqlSession, boardNo);
if(result > 0) {
sqlSession.commit();
} else {
sqlSession.rollback();
}
sqlSession.close();
return result;
}
@Override
public Board selectBoard(int boardNo) {
SqlSession sqlSession = getSqlSession();
Board b = boardDao.selectBoard(sqlSession, boardNo);
sqlSession.close();
return b;
}
@Override
public ArrayList<Reply> selectReplyList(int boardNo) {
SqlSession sqlSession = getSqlSession();
ArrayList<Reply> list = boardDao.selectReplyList(sqlSession, boardNo);
sqlSession.close();
return list;
}
💻 BoardDao
public int increaseCount(SqlSession sqlSession, int boardNo) {
return sqlSession.update("boardMapper.increaseCount", boardNo);
}
public Board selectBoard(SqlSession sqlSession, int boardNo) {
return sqlSession.selectOne("boardMapper.selectBoard", boardNo);
// 현재 Board 타입으로 mapper에서 반환되었음
// 그대로 리턴!
}
public ArrayList<Reply> selectReplyList(SqlSession sqlSession, int boardNo) {
return (ArrayList)sqlSession.selectList("boardMapper.selectReplyList", boardNo);
// 제네릭 설정까지 형 변환 하면 오류 남!
}
💻 board-mapper.xml
기존 resultMap에서 BOARD_CONTENT만 추가해 줌!
❓ 그럼 기존 boardResultSet을 쓰던 애는 BOARD_CONTENT가 없으니까 오류 나는 거 아닌가요?
❗️ ㄴㄴ 없으면 mapping 안 되고 말지 오류가 나지는 않음!
👉🏻 즉, 중복된 컬럼이 많다면 굳이 2번 만들 필요 없이 재활용 할 것!
<resultMap id="boardResultSet" type="board">
<result column="BOARD_NO" property="boardNo" />
<result column="BOARD_TITLE" property="boardTitle" />
<result column="USER_ID" property="boardWriter" />
<result column="COUNT" property="count" />
<result column="CREATE_DATE" property="createDate" />
<result column="BOARD_CONTENT" property="boardContent" /> <!-- 추가한 컬럼 -->
</resultMap>
<!--
mtbatis-config.xml에 별칭 지정하지 않고 풀 클래스명 적어도 무방함
<resultMap id="replyResultSet" type="com.kh.mybatis.board.model.vo.Reply">
-->
<resultMap id="replyResultSet" type="reply">
<result column="REPLY_NO" property="replyNo" />
<result column="USER_ID" property="replyWriter" />
<result column="REPLY_CONTENT" property="replyContent" />
<result column="CREATE_DATE" property="createDate" />
</resultMap>
<update id="increaseCount" parameterType="_int">
UPDATE BOARD
SET COUNT = COUNT + 1
WHERE BOARD_NO = #{boardNo}
AND STATUS = 'Y'
</update>
<select id="selectBoard" parameterType="_int" resultMap="boardResultSet">
SELECT BOARD_NO
, BOARD_TITLE
, USER_ID
, COUNT
, CREATE_DATE
, BOARD_CONTENT
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE BOARD_NO = #{boardNo}
AND B.STATUS = 'Y'
</select>
<select id="selectReplyList" parameterType="_int" resultMap="replyResultSet">
SELECT REPLY_NO
, USER_ID
, REPLY_CONTENT
, CREATE_DATE
FROM REPLY R
JOIN MEMBER ON (REPLY_WRITER = USER_NO)
WHERE REF_BNO = #{boardNo}
AND R.STATUS = 'Y'
ORDER BY REPLY_NO DESC
</select>
💻 mybatis-config.xml 에 별칭 추가
<typeAliases>
<typeAlias type="com.kh.mybatis.member.model.vo.Member" alias="member" />
<typeAlias type="com.kh.mybatis.board.model.vo.Board" alias="board" />
<typeAlias type="com.kh.mybatis.board.model.vo.Reply" alias="reply" /> <!-- 별칭 사용을 위해 추가 -->
</typeAliases>
💻 BoardService
필요한 메소드가 추가되었으므로 인터페이스 서비스단에 추가해 줄 것!
// 댓글 조회
ArrayList<Reply> selectReplyList(int boardNo);
💻 boardDetailView.jsp - 동적코딩 ver.
<%@ 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>Insert title here</title>
<style>
td>textarea {
width : 100%;
height : 100%;
resize : none;
box-sizing : border-box; /* 표 크기 밖으로 삐쳐 나가지 않고 맞추고 싶을 때 사용 */
}
</style>
</head>
<body>
<jsp:include page="../common/menubar.jsp" />
<div class="outer">
<br>
<h1 align="center">게시판 상세조회</h1>
<br>
<table align="center" border="1">
<!-- (tr>(td*2))*6 -->
<tr>
<td width="100">글번호</td>
<td width="500">${ b.boardNo }</td>
</tr>
<tr>
<td>제목</td>
<td>${ b.boardTitle }</td>
</tr>
<tr>
<td>작성자</td>
<td>${ b.boardWriter }</td>
</tr>
<tr>
<td>조회수</td>
<td>${ b.count }</td>
</tr>
<tr>
<td>작성일</td>
<td>${ b.createDate }</td>
</tr>
<tr>
<td>내용</td>
<td height="100">
${ b.boardContent }
</td>
</tr>
</table>
<table align="center" border="1">
<!-- (tr>(td*3))*4 -->
<tr>
<td width="100">댓글 작성</td>
<td width="400"><textarea></textarea></td>
<td width="100"><button>등록</button></td>
</tr>
<tr>
<td colspan="3"><b>댓글 (${ list.size() })</b></td>
</tr>
<c:forEach var="r" items="${ list }">
<tr>
<td>${ r.replyWriter }</td>
<td>${ r.replyContent }</td>
<td>${ r.createDate }</td>
</tr>
</c:forEach>
</table>
</div>
</body>
</html>
🔥 게시글 검색 기능 🔥
💻 boardListView.jsp
<h1 align="center">게시판</h1>
<div id="search-area">
<form action="search.bo" method="get">
<input type="hidden" name="currentPage" value="1"> <!-- 페이징 처리를 위해 넘기는 값 -->
<select name="condition">
<option value="writer">작성자</option>
<option value="title">제목</option>
<option value="content">내용</option>
</select>
<input type="text" name="keyword">
<button type="submit">검색</button>
</form>
</div>
💻 BoardSearchController Servlet 생성
url mapping: /search.bo
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 검색 요청 시 전달값 뽑기
String condition = request.getParameter("condition"); // condition : 검색 조건("writer" / "title" / "content")
String keyword = request.getParameter("keyword"); // keyword : 검색어("사용자가 입력한 키워드값")
// 마이바티스에서는 미완성된 쿼리문 부분이 여러 개일지라도 하나의 매개변수로 가공해서 구멍을 매꿔 줘야 하는 것이 원칙!
// => 그래서 항상 VO로 가공해서 보냈던 것!
// => 하지만 만약 굳이 VO로 가공하지 않아도 될 것 같다면? HashMap 타입으로 가공하면 됨!
HashMap<String, String> map = new HashMap<>();
map.put("condition", condition);
map.put("keyword", keyword);
// 페이징 처리를 위한 기본 변수 4가지
// int searchCount = new BoardService().selectSearchCount(condition, keyword); // 현재 검색결과에 맞는 게시글의 총 개수
// 마이바티스에서는 구멍이 여러 개라도 VO타입 하나로 가공해서 보내는 것이 원칙!
int searchCount = new BoardServiceImpl().selectSearchCount(map);
int currentPage = Integer.parseInt(request.getParameter("currentPage")); // currentPage = 1 : 페이징 처리를 위한 사용자가 요청한 페이지
int pageLimit = 10;
int boardLimit = 5;
PageInfo pi = Pagination.getPageInfo(searchCount, currentPage, pageLimit, boardLimit);
// System.out.println(pi);
// 작성자: user // PageInfo [listCount=7, currentPage=1, pageLimit=10, boardLimit=5, maxPage=2, startPage=1, endPage=2]
// 제목: 입니다 // PageInfo [listCount=1, currentPage=1, pageLimit=10, boardLimit=5, maxPage=1, startPage=1, endPage=1]
// 내용: 게시판 // PageInfo [listCount=5, currentPage=1, pageLimit=10, boardLimit=5, maxPage=1, startPage=1, endPage=1]
ArrayList<Board> list = new BoardServiceImpl().selectSearchList(map, pi);
request.setAttribute("pi", pi);
request.setAttribute("list", list);
request.getRequestDispatcher("WEB-INF/views/board/boardListView.jsp").forward(request, response);
}
💻 BoardService
// 게시글 검색
int selectSearchCount(HashMap<String, String> map);
// 검색된 게시글 리스트 조회
ArrayList<Board> selectSearchList(HashMap<String, String> map, PageInfo pi);
💻 BoardServiceImpl
@Override
public int selectSearchCount(HashMap<String, String> map) {
SqlSession sqlSession = getSqlSession();
int searchCount = boardDao.selectSearchCount(sqlSession, map);
// select문의 결과가 int 타입으로 돌아오기 때문에 별도 변환 필요 없음
sqlSession.close();
return searchCount;
}
@Override
public ArrayList<Board> selectSearchList(HashMap<String, String> map, PageInfo pi) {
SqlSession sqlSession = getSqlSession();
ArrayList<Board> list = boardDao.selectSearchList(sqlSession, map, pi);
sqlSession.close();
return list;
}
💻 BoardDao
public int selectSearchCount(SqlSession sqlSession, HashMap<String, String> map) {
return sqlSession.selectOne("boardMapper.selectSearchCount", map);
}
public ArrayList<Board> selectSearchList(SqlSession sqlSession, HashMap<String, String> map, PageInfo pi) {
int limit = pi.getBoardLimit();
int offset = (pi.getCurrentPage() - 1) * limit;
RowBounds rowBounds = new RowBounds(offset, limit); // 몇 개를 건너뛰고, 몇 개를 가지고 올 건지 범위 제시
return (ArrayList)sqlSession.selectList("boardMapper.selectSearchList", map, rowBounds);
// 어떤 매퍼 타입의 어떤 쿼리문 실행할지? 구멍이 뚫렸을 때 매꿀 놈, rowBounds 자리
}
💻 board-mapper.xml
<select id="selectSearchCount" parameterType="hashMap" resultType="_int">
SELECT COUNT(*)
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
<if test="condition == 'writer'">
AND USER_ID
</if>
<if test="condition == 'title'">
AND BOARD_TITLE
</if>
<if test="condition == 'content'">
AND BOARD_CONTENT
</if>
LIKE '%' || #{keyword} || '%'
</select>
<select id="selectSearchList" parameterType="hashmap" resultMap="boardResultSet">
SELECT BOARD_NO
, BOARD_TITLE
, USER_ID
, COUNT
, CREATE_DATE
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
<choose>
<when test="condition == 'writer'">
AND USER_ID
</when>
<when test="condition == 'title'">
AND BOARD_TITLE
</when>
<otherwise>
AND BOARD_CONTENT
</otherwise>
</choose>
LIKE '%' || #{keyword} || '%'
ORDER BY BOARD_NO DESC
</select>
📌 MyBatis에서의 동적 SQL(중복된 쿼리문 활용)
뭐 지가 다 강력하대...
📍 정석적으로 검색을 위해서는 위와 같이 따로 쿼리문을 작성하는 것이 원칙이나 MyBatis에서는 이를 보다 효율적으로 사용할 수 있음!
1) 기존 쿼리문 만들기
-- 게시글 검색 결과 게시글의 개수 구하기 (searchCount)
SELECT COUNT(*)
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y' -- 14건 (전체)
-- AND USER_ID LIKE '%' || 'user' || '%' -- 7건 (작성자로 user라는 키워드 검색)
-- AND BOARD_TITLE LIKE '%' || '입니다' || '%' -- 1건 (제목으로 입니다라는 키워드 검색)
AND BOARD_CONTENT LIKE '%' || '게시판' || '%' -- 5건 (내용으로 게시판이라는 키워드 검색)
2) 공통점 찾기
-- 쿼리문 공통적인 부분만 다듬기 (== 공통점 찾기)
SELECT COUNT(*)
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
-- AND USER_ID -- writer로 검색
-- AND BOARD_TITLE -- title로 검색
-- AND BOARD_CONTENT -- content로 검색
LIKE '%' || '사용자가 입력한 키워드' || '%'
3-1) if문 활용하기
3-2) choose, when, otherwise 활용하기
개발자 문서 참고 자료
작성자: user 검색 시 필터 잘됨!
문제1) 검색 시 검색창에서 검색어가 사라짐!
url을 직접 currenPage=2로 바꾸어 줬을 때도 잘 나옴
근데 첫 번째 페이지에서 [2]를 누르면?
문제2) condition과 keyword에 대한 쿼리스트팅이 사라짐!
문제1) 검색 시 검색창에서 검색어가 사라짐!
💻 BoardSearchController
jsp로 보낼 값에 condition과 keyword를 추가할 것!
// 검색창에 검색어를 유지시키기 위해 추가하여 jsp로 보내 줌!
request.setAttribute("condition", condition);
request.setAttribute("keyword", keyword);
💻 boardListView.jsp
헤드 부분에 jQuery 라이브러리 연결하고, 바디 부분에 condition이 있을 때와 없을 때에 대한 조건 및 이벤트 추가
// 헤드 부분 추가 내용 - jQuery 라이브러리 연결
<title>Insert title here</title>
<!-- jQuery 라이브러리 연결 -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
// 바디 부분 추가 내용
<br>
<h1 align="center">게시판</h1>
<div id="search-area">
<form action="search.bo" method="get">
<input type="hidden" name="currentPage" value="1"> <!-- 페이징 처리를 위해 넘기는 값 -->
<select name="condition">
<option value="writer">작성자</option>
<option value="title">제목</option>
<option value="content">내용</option>
</select>
<input type="text" name="keyword" value="${ keyword }">
<!-- 검색 시 검색어 유지를 위해 keyword를 넣어 줌! 만약 keyword가 없는 상태라면 안 뽑고 말기 때문에 검색했을 때만 이용 가능! -->
<button type="submit">검색</button>
</form>
</div>
<!-- 검색 시 검색어 유지를 위해 추가함 -->
<c:if test="${ not empty condition }">
<script>
$(function() {
$("#search-area option[value=${ condition }]").attr("selected", true);
});
</script>
</c:if>
<br>
검색어 잘 남아 있음!
문제2) condition과 keyword에 대한 쿼리스트팅이 사라짐!
💻 boardListView.jsp
paging-area 영역에 condition이 있는 경우와 없는 경우(검색함/안 함) 조건을 추가하고, 검색했을 시 url 값도 유지되도록 조건 넣기
<div id="paging-area">
<c:if test="${ pi.currentPage ne 1 }">
<c:choose>
<c:when test="${ empty condition }">
<a href="list.bo?currentPage=${ pi.currentPage - 1 }">[이전]</a>
</c:when>
<c:otherwise>
<a href="search.bo?currentPage=${ pi.currentPage - 1 }&condition=${ condition }&keyword=${ keyword }">[이전]</a>
</c:otherwise>
</c:choose>
</c:if>
<c:forEach var="p" begin="${ pi.startPage }" end="${ pi.endPage }" step="1">
<c:choose>
<c:when test="${ empty condition }"> <!-- 전체 조회일 경우: list.bo로 페이지 이동할 수 있게끔 -->
<a href="list.bo?currentPage=${ p }">[${ p }]</a>
</c:when>
<c:otherwise> <!-- 검색 조회일 경우: search.bo로 페이지 이동할 수 있게끔 -->
<a href="search.bo?currentPage=${ p }&condition=${ condition }&keyword=${ keyword }">[${ p }]</a>
</c:otherwise>
</c:choose>
</c:forEach>
<c:if test="${ pi.currentPage ne pi.maxPage }">
<c:choose>
<c:when test="${ empty condition }">
<a href="list.bo?currentPage=${ pi.currentPage + 1 }">[다음]</a>
</c:when>
<c:otherwise>
<a href="search.bo?currentPage=${ pi.currentPage + 1 }&condition=${ condition }&keyword=${ keyword }">[다음]</a>
</c:otherwise>
</c:choose>
</c:if>
</div>
작성자 user 검색 시 1 페이지 잘 나옴
작성자 user 검색 시 2 페이지도 잘 나옴
⭐️ 검색 기능 구현 시 정적 바인딩을 사용하는 경우
MyBatis의 동적 바인딩 👉🏻 #{} : 문자열의 경우 양사이드에 홑따옴표가 붙어서 구멍이 메꿔짐
정적 바인딩 👉🏻 ${} : 문자열의 경우 양사이드에 홑따움표가 붙지 않고 구멍이 메꿔짐
(보안이 상당히 취약한 방식으로 권장되지 않음!)
💻 boardListView.jsp
기존 search-area 구문의 option 태그 value 값을 컬럼명으로 변경
<div id="search-area">
<form action="search.bo" method="get">
<input type="hidden" name="currentPage" value="1">
<select name="condition">
<option value="USER_ID">작성자</option>
<option value="BOARD_TITLE">제목</option>
<option value="BOARD_CONTENT">내용</option>
</select>
<input type="text" name="keyword" value="${ keyword }">
<button type="submit">검색</button>
</form>
</div>
💻 BoardSearchController
코드상 달라진 점은 없으나 condition에 들어가는 값이 달라지게 됨!
// 검색 요청 시 전달값 뽑기: 동적 쿼리를 이용한 방식
// String condition = request.getParameter("condition"); // condition : 검색 조건("writer" / "title" / "content")
// String keyword = request.getParameter("keyword"); // keyword : 검색어("사용자가 입력한 키워드값")
// 검색 요청 시 전달값 뽑기: 정적 쿼리를 이용한 방식
String condition = request.getParameter("condition"); // condition: 검색 조건("USER_ID" / "BOARD_TITLE" / "BOARD_CONTENT")
String keyword = request.getParameter("keyword"); // keyword: 검색어 ("사용자가 입력한 키워드값")
💻 board-mapper.xml
<select id="selectSearchCount" parameterType="hashmap" resultType="_int">
SELECT COUNT(*)
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
<!--
<if test="condition == 'writer'">
AND USER_ID
</if>
<if test="condition == 'title'">
AND BOARD_TITLE
</if>
<if test="condition == 'content'">
AND BOARD_CONTENT
</if>
LIKE '%' || #{keyword} || '%'
--> <!-- 동적 쿼리를 이용한 방식 -->
AND ${condition} LIKE '%' || #{keyword} || '%' <!-- 정적 바인딩을 이용한 방식 -->
</select>
<select id="selectSearchList" parameterType="hashmap" resultMap="boardResultSet">
SELECT BOARD_NO
, BOARD_TITLE
, USER_ID
, COUNT
, CREATE_DATE
FROM BOARD B
JOIN MEMBER ON (BOARD_WRITER = USER_NO)
WHERE B.STATUS = 'Y'
<!--
<choose>
<when test="condition == 'writer'">
AND USER_ID
</when>
<when test="condition == 'title'">
AND BOARD_TITLE
</when>
<otherwise>
AND BOARD_CONTENT
</otherwise>
</choose>
LIKE '%' || #{keyword} || '%'
--> <!-- 동적 쿼리를 이용한 방식 -->
AND ${condition} LIKE '%' || #{keyword} || '%' <!-- 정적 바인딩을 이용한 방식 -->
ORDER BY BOARD_NO DESC
</select>