[MyBatis] MyBatis CRUD - 게시판 기능 2(게시판 상세 조회 & 댓글리스트 조회, 게시글 검색 기능)

2022. 11. 14. 14:22·📗 self-study/📗 KH정보교육원 당산지원
더보기

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 활용하기

더보기

개발자 문서 참고 자료

https://mybatis.org/mybatis-3/ko/dynamic-sql.html

 

MyBatis – 마이바티스 3 | 동적 SQL

동적 SQL 마이바티스의 가장 강력한 기능 중 하나는 동적 SQL을 처리하는 방법이다. JDBC나 다른 유사한 프레임워크를 사용해본 경험이 있다면 동적으로 SQL 을 구성하는 것이 얼마나 힘든 작업인지

mybatis.org

 

더보기

작성자: 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>

 

저작자표시 비영리 변경금지 (새창열림)
'📗 self-study/📗 KH정보교육원 당산지원' 카테고리의 다른 글
  • [Spring] STS(Spring Tool Suite) 설치법 & 세팅
  • [MyBatis] view단과 Controller단 사이의 Filter
  • [MyBatis] MyBatis CRUD - 게시판 기능 1(공통 코드, 페이징 바, 게시판 전체 조회)
  • [MyBatis] MyBatis CRUD - 로그인/로그아웃/정보 변경/ 탈퇴 기능
천재강쥐
천재강쥐
  • 천재강쥐
    디버거도 버거다
    천재강쥐
  • 전체
    오늘
    어제
    • Category (467)
      • 진짜 너무 궁금한데 이걸 나만 몰라...? (0)
      • 💾 Portfolio (2)
      • 🐤 CodingTest (28)
        • Java (20)
        • ᕕ(ꐦ°᷄д°᷅)ᕗ❌ (5)
      • 🚀 from error to study (142)
        • AI (1)
        • Cloud (2)
        • DB (12)
        • Front-End (16)
        • Github (14)
        • Java (39)
        • Mac (7)
        • Normal (29)
        • Server (22)
      • 📘 certificate (44)
        • 📘 리눅스마스터1급 (1)
        • 📘⭕️ 정보처리기사 (40)
        • 📘⭕️ SQLD (3)
      • 📗 self-study (234)
        • 📗 inflearn (35)
        • 📗 생활코딩 (8)
        • 📗 KH정보교육원 당산지원 (190)
      • 🎨 Scoop the others (0)
        • 📖 Peeking into other people.. (0)
        • 🇫🇷 (0)
        • 📘⭕️ 한국사능력검정시험 심화 (11)
        • 오블완 (4)
  • 인기 글

  • hELLO· Designed By정상우.v4.10.1
천재강쥐
[MyBatis] MyBatis CRUD - 게시판 기능 2(게시판 상세 조회 & 댓글리스트 조회, 게시글 검색 기능)
상단으로

티스토리툴바