오늘이라도
[MyBatis] 21. 게시판 만들기 ④ : 검색 기능 추가 본문
https://github.com/upcake/Class_Examples
교육 중에 작성한 예제들은 깃허브에 올려두고 있습니다.
gif 파일은 클릭해서 보는 것이 정확합니다.
- 게시판 만들기 ④ : 검색 기능 추가 -
□진행 상황(※ 볼드체 : 오늘 다룬 파일들)
○ JAVA
- com.hanul.mybatis : board.sql, db.properties, SqlMapConfig.xml, boardMapper.xml
- com.hanul.dto : BoardDTO.java, SearchDTO.java
- com.hanul.dao : BoardDAO.java
- com.hanul.controller : BoardFrontController.java ▶ Servlet : web.xml에서 Mapping
- com.hanul.action : Action.java(Interface), ActionForward.java,
Boardxxx.java(BoardListAction.java, BoardInsertAction.java, BoardDetailAction.java
BoardDetailAction.java, BoardDeleteAction.java, BoardUpdateFormAction.java,
BoardUpdateAction.java, BoardSearchAction.java)
-----------------------------------------------------------------------------------------------------
○ WebContent
- boardMain.html
- board\ : *.jsp (boardList.jsp, boardInsertForm.jsp, boardDetail.jsp, boardUpdateForm.jsp, boardSearchList.jsp)
- css\ : *.css
- js\ : *.js
- images\ : *.png, *.gif, *.jpg
-----------------------------------------------------------------------------------------------------
○ 목록 조회
boardMain.html → boardList.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardListAction.java → BoardDAO.java → boardMapper.xml → BoardDAO.java
→ BoardListAction.java → BoardFrontController.java → ActionForward.java
→ boardList.jsp
-----------------------------------------------------------------------------------------------------
○ 게시글 작성
boardList.jsp → boardInsertForm.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ boardInsertForm.jsp(입력화면) → boardInsert.do(*.do) → web.xml →
BoardFrontController.java(Servlet) → BoardInsertAction.java → BoardDAO.java
→ boardMapper.xml → BoardDAO.java → BoardInsertAction.java
→ BoardFrontController.java → ActionForward.java → boardList.do
-----------------------------------------------------------------------------------------------------
○ 게시글 조회
boardList.jsp → boardDetail.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardDetailAction.java → BoardDAO.java → boardMapper.xml → BoardDAO.java(내용보기)
→ BoardDetailAction.java → BoardDAO.java → boardMapper.xml → BoardDAO.java(조회수증가)
→ BoardDetailAction.java → BoardFrontController.java → ActionForward.java
→ boardDetail.jsp
-----------------------------------------------------------------------------------------------------
○ 게시글 삭제
boardDetail.jsp → boardDelete.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardDeleteAction.java → BoardDAO.java → boardMapper.xml → BoardDAO.java
→ BoardDeleteAction.java → BoardFrontController.java → ActionForward.java
→ boardList.do
-----------------------------------------------------------------------------------------------------
○ 게시글 조회 화면 → 수정 화면
boardDetail.jsp → boardUpdateForm.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardUpdateFormAction.java → BoardDAO → boardMapper.xml → BoardDAO.java(글 조회)
→ BoardUpdateFormAction.java → boardUpdateForm.jsp
-----------------------------------------------------------------------------------------------------
○ 게시글 수정
boardUpdateForm.jsp → boardUpdate.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardUpdateAction.java → BoardDAO → boardMapper.xml → BoardDAO.java
→ BoardUpdateAction.java → BoardFrontController.java → ActionForward.java
→ boardList.do
-----------------------------------------------------------------------------------------------------
○ 게시글 검색
boardList.jsp → boardSearch.do(*.do) → web.xml → BoardFrontController.java(Servlet)
→ BoardSearchAction.java → BoardDAO.java → boardMapper.xml → BoardDAO.java
→ BoardSearchAction.java → BoardFrontController.java → ActionForward.java
→ boardSearchList.jsp
□ 작동 화면 및 코드
▼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="com.hanul.mybatis.boardMapper.xml">
<select id="boardSearchAll" resultType="BoardDTO">
SELECT * FROM tblBoard ORDER BY b_num DESC
</select>
<insert id="boardInsert" parameterType="BoardDTO">
INSERT INTO tblBoard
VALUES(b_num_seq.NEXTVAL,
#{b_subject },
#{b_pwd },
#{b_content },
#{b_writer},
SYSDATE,
0)
</insert>
<select id="boardDetail" parameterType="String" resultType="BoardDTO">
SELECT * FROM tblBoard WHERE b_num = #{b_num}
</select>
<update id="boardCount" parameterType="String">
UPDATE tblBoard SET b_readcount = b_readcount + 1 WHERE b_num = #{b_num}
</update>
<delete id="boardDelete" parameterType="String">
DELETE FROM tblBoard WHERE b_num = #{b_num}
</delete>
<update id="boardUpdate" parameterType="BoardDTO">
UPDATE tblBoard
SET b_writer = #{b_writer},
b_subject = #{b_subject},
b_content = #{b_content},
b_pwd = #{b_pwd}
WHERE b_num = #{b_num}
</update>
<select id="boardSearch" parameterType="SearchDTO" resultType="BoardDTO">
SELECT * FROM tblBoard WHERE UPPER(${part}) LIKE UPPER(#{searchData})
</select>
</mapper>
▼BoardDAO.java
package com.hanul.dao;
import java.io.InputStream;
import java.util.List;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import com.hanul.dto.BoardDTO;
import com.hanul.dto.SearchDTO;
public class BoardDAO {
//①SqlSessionFactory 설정
private static SqlSessionFactory sqlMapper;
static {
String resource = "com/hanul/mybatis/SqlMapConfig.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlMapper = new SqlSessionFactoryBuilder().build(inputStream);
} catch (Exception e) {
e.printStackTrace();
System.out.println("SqlSessionFactory Exception");
}
} //static
//전체 목록 검색
public List<BoardDTO> boardSearchAll() {
SqlSession session = sqlMapper.openSession();
List<BoardDTO> list = null;
list = session.selectList("boardSearchAll");
session.close();
return list;
} //boardSearchAll()
//작성한 글 등록
public int boardInsert(BoardDTO dto) {
SqlSession session = sqlMapper.openSession();
//alert 창을 사용할 경우에는 succ를 return 해야한다.
//PrintWriter 이용한 script 코드로 구현한 후 페이지 전환 처리
int succ = 0;
succ = session.insert("boardInsert", dto);
session.commit();
session.close();
return succ;
} //boardInsert()
//글 번호로 글 검색
public BoardDTO boardDetail(String b_num) {
SqlSession session = sqlMapper.openSession();
BoardDTO dto = null;
dto = session.selectOne("boardDetail", b_num); //출력될 결과가 하나기 때문에 selectOne을 사용, 여러 개일 경우엔 selectList
session.close();
return dto;
} //boardDetail()
//조회수 증가
public void boardCount(String b_num) {
SqlSession session = sqlMapper.openSession();
session.update("boardCount", b_num);
session.commit();
session.close();
} //boardCount()
//글 삭제
public void boardDelete(String b_num) {
SqlSession session = sqlMapper.openSession();
//alert 창을 사용하지 않을 경우에는 succ가 필요없다.
//ActionForward를 이용한 페이지 전환
session.delete("boardDelete", b_num);
session.commit();
session.close();
} //boardDelte()
//글 수정
public void boardUpdate(BoardDTO dto) {
SqlSession session = sqlMapper.openSession();
session.update("boardUpdate", dto);
session.commit();
session.close();
}//boardUpdate()
//조건 검색
public List<BoardDTO> boardSearch(SearchDTO dto) {
SqlSession session = sqlMapper.openSession();
//검색 결과가 아예 없을수도 있고 정확히 몇개인지 모르니 List로 받는다.
List<BoardDTO> list = null;
list = session.selectList("boardSearch", dto);
session.close();
return list;
} //boardSearch()
} //class
▼boardDetail.jsp : 비밀번호 입력 칸에서 엔터를 쳐도 화면 전환이 안되게끔 수정
<%@page import="com.hanul.dto.BoardDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%
//BoardDetailAction에서 보낸 dto를 받는다.
request.setCharacterEncoding("utf-8");
BoardDTO dto = (BoardDTO) request.getAttribute("dto");
pageContext.setAttribute("enter", "\r\n"); //JSTL 줄바꿈 처리를 위해 현재 페이지에서 사용할 객체 생성
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Board Detail</title>
<script type="text/javascript">
function fnDelete(b_pwd) {
var user_pwd = document.detailForm.user_pwd.value;
alert("User PW : " + user_pwd + "\nDB PW : " + b_pwd);
if(user_pwd == "") { //비밀번호가 미입력 시
alert("비밀번호를 입력하세요!");
document.detailForm.user_pwd.value = "";
document.detailForm.user_pwd.focus();
} else if(user_pwd != b_pwd) { //비밀번호 불일치
alert("비밀번호가 일치하지 않습니다!")
document.detailForm.user_pwd.value = "";
document.detailForm.user_pwd.focus();
} else { //비밀번호 일치 → confirm 창
if(confirm("정말 삭제하시겠습니까?")) {
location.href = "boardDelete.do?b_num=" + ${dto.b_num };
} else {
document.detailForm.user_pwd.value = "";
document.detailForm.user_pwd.focus();
}
}
}
function fnUpdate(b_pwd) {
var user_pwd = document.detailForm.user_pwd.value;
alert("User PW : " + user_pwd + "\nDB PW : " + b_pwd);
if(user_pwd == "") { //비밀번호가 미입력 시
alert("비밀번호를 입력하세요!");
document.detailForm.user_pwd.value = "";
document.detailForm.user_pwd.focus();
} else if(user_pwd != b_pwd) { //비밀번호 불일치
alert("비밀번호가 일치하지 않습니다!")
document.detailForm.user_pwd.value = "";
document.detailForm.user_pwd.focus();
} else { //비밀번호 일치 → 수정 화면(form)
location.href = "boardUpdateForm.do?b_num=" + ${dto.b_num };
}
}
</script>
</head>
<body>
<div align="center">
<h3>[글 내용 조회]</h3>
<table border="1" style="width: 80%;">
<tr>
<th>작성자</th>
<td>${dto.b_writer }</td>
<th>조회수</th>
<td align="center">${dto.b_readcount }</td>
</tr>
<tr>
<th>제목</th>
<td colspan="3">${dto.b_subject }</td>
</tr>
<tr>
<th>내용</th>
<%-- <td colspan="3">${dto.b_content }</td> --%> <!-- 줄바꿈 처리를 못하는 문제 발생 -->
<td colspan="3">
<%--=dto.getB_content().replace("\r\n", "<br />") --%> <!-- 자바 코드로 줄바꿈 처리 -->
${fn : replace(dto.b_content, enter, "<br />") }
</td>
</tr>
<tr>
<th>비밀번호</th>
<td colspan="3">
<!-- script에서 user_pwd에 접근하기 위한 폼, 폼에서 Enter키 입력으로 인한 화면 전환 방지 -->
<form name="detailForm" onsubmit="return false" >
<input type="password" name="user_pwd"/>
<input type="button" value="삭제" onclick="fnDelete('${dto.b_pwd}')"/>
<input type="button" value="수정" onclick="fnUpdate('${dto.b_pwd}')"/>
<input type="button" value="글 목록" onclick="location.href='boardList.do'"/>
</form>
</td>
</tr>
</table>
</div>
</body>
</html>
▼boardList.jsp
<%@page import="org.apache.jasper.tagplugins.jstl.core.ForEach"%>
<%@page import="com.hanul.dto.BoardDTO"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%
request.setCharacterEncoding("utf-8");
List<BoardDTO> list = (List<BoardDTO>)request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BoardList JSP</title>
</head>
<body>
<div align="center">
<h3>[게시판 전체 목록 보기]</h3>
<table border="1" style="width: 80%;">
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr>
<%--
<!-- JSTL core 문법을 이용한 출력 : b_num_seq에 의해서 번호의 순서가 맞지 않다.-->
<c:if test="${empty list }"> <!-- list.size()가 0이라면 -->
<tr align="center">
<td colspan="5">작성된 글이 없습니다.</td>
</tr>
</c:if>
<c:if test="${list != null }">
<c:forEach var="i" items="${list }">
<tr align="center">
<td>${i.b_num }</td>
<td>${i.b_subject }</td>
<td>${i.b_writer }</td>
<td>${i.b_date }</td>
<td>${i.b_readcount }</td>
</tr>
</c:forEach>
</c:if>
--%>
<!-- 향상된 for문을 이용한 출력 : 번호 순서가 맞지 않다 -->
<%--if(list.size() == 0) {
out.println("<tr align='center'><td colspan='5'>작성된 글이 없습니다.</td></tr>");
} else {
for(BoardDTO dto : list) {
out.println("<tr align='center'>");
out.println("<td>" + dto.getB_num() + "</td>");
out.println("<td>" + dto.getB_subject() + "</td>");
out.println("<td>" + dto.getB_writer() + "</td>");
out.println("<td>" + dto.getB_date() + "</td>");
out.println("<td>" + dto.getB_readcount() + "</td>");
out.println("</tr>");
}
}--%>
<%
if(list.size() == 0) {
out.println("<tr align='center'><td colspan='5'>작성된 글이 없습니다.</td></tr>");
} else {
for(int i = 0; i < list.size(); i++) {
out.println("<tr align='center'>");
//out.println("<td>" + list.get(i).getB_num() + "</td>");
out.println("<td>" + (list.size() - i) + "</td>");
out.println("<td><a href='boardDetail.do?b_num=" + list.get(i).getB_num() + "'>" + list.get(i).getB_subject() + "</a></td>");
out.println("<td>" + list.get(i).getB_writer() + "</td>");
out.println("<td>" + list.get(i).getB_date() + "</td>");
out.println("<td>" + list.get(i).getB_readcount() + "</td>");
out.println("</tr>");
}
}
%>
<tr align="center">
<td colspan="5">
<form action="boardSearch.do" method="post">
<select name="part">
<option value="b_subject">제목</option>
<option value="b_content">내용</option>
<option value="b_writer">작성자</option>
</select>
<input type="text" name="searchData" required="required"/>
<input type="submit" value="검색" />
<input type="button" value="글쓰기" onclick="location.href='boardInsertForm.do'"/>
</form>
<!-- boardInsertForm.do를 작성하지 않고 버튼을 누르면 404, 500에러가 나지 않고 빈 화면이 나온다.
BoardFrontController.java까지는 간 다음 서블렛에서 멈추기 때문 -->
</td>
</tr>
</table>
</div>
</body>
</html>
▼BoardFrontController.java
package com.hanul.controller;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hanul.action.Action;
import com.hanul.action.ActionForward;
import com.hanul.action.BoardDeleteAction;
import com.hanul.action.BoardDetailAction;
import com.hanul.action.BoardInsertAction;
import com.hanul.action.BoardListAction;
import com.hanul.action.BoardSearchAction;
import com.hanul.action.BoardUpdateAction;
import com.hanul.action.BoardUpdateFormAction;
@WebServlet("/BoardFrontController.do")
public class BoardFrontController extends HttpServlet {
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//0. 불필요한 코드를 지우고 서비스 메서드만 남겨둔다.
//1. 클라이언트가 어떤 요청을 했는지를 파악한다.
request.setCharacterEncoding("utf-8");
//localhost:8080/mbb/boardList.do
//mbb : context root
//mbb/boardList.do : uri-pattern
//uri-pattern에서 context root를 잘라내서 boardList.do만 남긴다.
String uri = request.getRequestURI(); //uri-pattern 값 : /mbb/XXX.do
String ctx = request.getContextPath(); //Context root 값 : /mbb
String command = uri.substring(ctx.length()); //실제 요청한 페이지 : /XXX.do
//System.out.println("uri : " + uri);
//System.out.println("ctx : " + ctx);
//System.out.println("command : " + command);
//2. 클라이언트의 요청(*.do → command)과 실제 처리할 비즈니스 로직(Action Class) 연결
Action action = null;
ActionForward forward = null;
if(command.equals("/boardList.do")) {
action = new BoardListAction(); //상위 객체(부모)쪽으로 업캐스팅 (다형성)
forward = action.execute(request, response);
} else if(command.equals("/boardInsertForm.do")) { //글쓰기 폼으로 화면 전환만 필요 (Action 클래스 필요 X, 화면 전환은 ActionForward가 담당)
forward = new ActionForward();
forward.setPath("board/boardInsertForm.jsp");
forward.setRedirect(false);
} else if(command.equals("/boardInsert.do")) {
action = new BoardInsertAction();
forward = action.execute(request, response); //forward에 null값이 리턴된다.
} else if(command.equals("/boardDetail.do")) {
action = new BoardDetailAction();
forward = action.execute(request, response);
} else if(command.equals("/boardDelete.do")) {
action = new BoardDeleteAction();
forward = action.execute(request, response);
} else if(command.equals("/boardUpdateForm.do")) {
action = new BoardUpdateFormAction();
forward = action.execute(request, response);
} else if(command.equals("/boardUpdate.do")) {
action = new BoardUpdateAction();
forward = action.execute(request, response);
} else if(command.equals("/boardSearch.do")) {
action = new BoardSearchAction();
forward = action.execute(request, response);
}
//3. 페이지 전환(프레젠테이션 로직) : sendRedirect(), forward()
if(forward != null) { //forward가 null 아니면 작동
if(forward.isRedirect()) { //true : sendRedirect() 페이지 전환
response.sendRedirect(forward.getPath());
} else { //false : forward() 페이지 전환
RequestDispatcher rd = request.getRequestDispatcher(forward.getPath());
rd.forward(request, response);
}
}
}
}
▼BoardSearchAction.java
package com.hanul.action;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.hanul.dao.BoardDAO;
import com.hanul.dto.BoardDTO;
import com.hanul.dto.SearchDTO;
public class BoardSearchAction implements Action {
@Override
public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//클라이언트 요청
request.setCharacterEncoding("utf-8");
String part = request.getParameter("part");
String searchData = request.getParameter("searchData");
SearchDTO dto = new SearchDTO();
dto.setPart(part);
dto.setSearchData("%" + searchData + "%");
//비즈니스 로직
BoardDAO dao = new BoardDAO();
List<BoardDTO> list = dao.boardSearch(dto);
request.setAttribute("list", list);
//프레젠테이션 로직
ActionForward forward = new ActionForward();
forward.setPath("board/boardSearchList.jsp");
forward.setRedirect(false);
return forward;
}
}
▼SearchDTO.java
package com.hanul.dto;
import java.io.Serializable;
public class SearchDTO implements Serializable {
private String part, searchData;
public SearchDTO() {}
public SearchDTO(String part, String searchData) {
super();
this.part = part;
this.searchData = searchData;
}
public String getPart() {
return part;
}
public void setPart(String part) {
this.part = part;
}
public String getSearchData() {
return searchData;
}
public void setSearchData(String searchData) {
this.searchData = searchData;
}
}
▼SqlMapConfig.xml : SearchDTO Alias 지정
<?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>
<properties resource="com/hanul/mybatis/db.properties" />
<typeAliases>
<typeAlias type="com.hanul.dto.BoardDTO" alias="BoardDTO"/>
<typeAlias type="com.hanul.dto.SearchDTO" alias="SearchDTO"/>
</typeAliases>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="${driver}" />
<property name="url" value="${url}" />
<property name="username" value="${username}" />
<property name="password" value="${password}" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/hanul/mybatis/boardMapper.xml" />
</mappers>
</configuration>
▼boardSearchList.jsp
<%@page import="com.hanul.dto.BoardDTO"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
request.setCharacterEncoding("utf-8");
List<BoardDTO> list = (List<BoardDTO>) request.getAttribute("list");
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>BoardSearchList</title>
</head>
<body>
<div align="center">
<h3>[검색 결과]</h3>
<table border="1" style="width: 80%;">
<tr>
<th>번호</th>
<th>제목</th>
<th>작성자</th>
<th>작성일</th>
<th>조회수</th>
</tr> <%
if(list.size() == 0) {
out.println("<tr align='center'><td colspan='5'>작성된 글이 없습니다.</td></tr>");
} else {
for(int i = 0; i < list.size(); i++) {
out.println("<tr align='center'>");
//out.println("<td>" + list.get(i).getB_num() + "</td>");
out.println("<td>" + (list.size() - i) + "</td>");
out.println("<td><a href='boardDetail.do?b_num=" + list.get(i).getB_num() + "'>" + list.get(i).getB_subject() + "</a></td>");
out.println("<td>" + list.get(i).getB_writer() + "</td>");
out.println("<td>" + list.get(i).getB_date() + "</td>");
out.println("<td>" + list.get(i).getB_readcount() + "</td>");
out.println("</tr>");
}
}
%>
<tr align="center">
<td colspan="5">
<input type="button" value="글쓰기" onclick="location.href='boardInsertForm.do'" />
<input type="button" value="글 목록" onclick="location.href='boardList.do'" />
</td>
</tr>
</table>
</div>
</body>
</html>
'취업성공패키지 SW 개발자 교육 > Web' 카테고리의 다른 글
[Web] 23. jQuery : 라이브러리 설정, 테이블 작성, 구구단, 선택자 (0) | 2020.06.09 |
---|---|
[MyBatis] 22. 쇼핑몰 화면 작성, 장바구니 구현, 로그인 세션 구현 (0) | 2020.06.08 |
[MyBatis] 20. 게시판 만들기 ③ : 게시글 조회, 조회수 증가, 게시글 삭제, 게시글 수정 (0) | 2020.06.04 |
[MyBatis] 19. 게시판 만들기 ② : 게시글 작성 (0) | 2020.06.03 |
[MyBatis] 18. 게시판 만들기 ① : MyBatis 준비 / DTO, DAO 작성 / MVC2 서블렛 구성 (0) | 2020.06.02 |