이전글
https://amongthestar.tistory.com/150
이번에 포스팅할 내용은 수강후기 게시판 전체보기와 게시글 입력이다.
게시글 상세보기 및 수정 삭제, 댓글 입력 삭제는 다음 포스팅에 게시할 예정이다.
지금까지 로직 진행은 다음과 같다.
1. 메인 화면에서 세번째 탭에 해당하는 "과정"을 클릭하면 과정 전체목록이 카드 형식으로 보인다.
2. 카드 하나를 클릭하면 해당하는 과정의 상세내용을 볼 수 있다.
3. 과정의 상세내용 하단에 수강후기 게시판을 볼 수 있다.
수강후기 DB관련 DTO (WBoardDTO.java)
package com.wmember.model;
public class WBoardDTO {
private int num;
private String userid;
private String subject;
private String content;
private String reg_date;
private int readcount;
private int classnum;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getUserid() {
return userid == null ? "" : userid.trim();
}
public void setUserid(String userid) {
this.userid = userid;
}
public String getSubject() {
return subject == null ? "" : subject.trim();
}
public void setSubject(String subject) {
this.subject = subject;
}
public String getContent() {
return content == null ? "" : content.trim();
}
public void setContent(String content) {
this.content = content;
}
public String getReg_date() {
return reg_date == null ? "" : reg_date.trim();
}
public void setReg_date(String reg_date) {
this.reg_date = reg_date;
}
public int getReadcount() {
return readcount;
}
public void setReadcount(int readcount) {
this.readcount = readcount;
}
public int getClassnum() {
return classnum;
}
public void setClassnum(int classnum) {
this.classnum = classnum;
}
}
courseDetail.jsp
게시판 영역이다. 검색영역, 글쓰기 버튼, 수강후기 게시판영역으로 이루어져있다.
<!-- 게시판 -->
<div class="board">
<br/>
<!-- 검색 시작-->
<div align="right" id="searchDiv">
<form name="search" id="search">
<select name="field" id="field">
<option value="userid">작성자</option>
<option value="subject">제목</option>
</select>
<input type="text" name="word" id="word">
<input type="button" value="찾기" id="btnSearch" class="btn btn-outline-secondary btn-sm">
<a href="#coll" id="writeBtn" class="btn btn-outline-dark btn-sm" data-toggle="collapse">글쓰기</a>
</form>
</div>
<!-- 검색 끝-->
<!-- 수강후기 게시판 -->
<div id="result" align="center"></div>
<!-- 글쓰기 폼 영역 -->
<div id="coll" class="collapse">
<form action="/Tutoring/board/boardinsert" method="post" id="wFrm">
<br/><br/>
<!-- 수강후기 등록하고자 하는 강의 번호 -->
<input type="hidden" id="classnum" name="classnum" value="${dto.classnum}">
<div class="input-group mb-3"><div class="input-group-prepend">
<span class="input-group-text">강의명</span></div>
<input type="text" class="form-control" id="classname" name="classname" readonly="readonly" value="${dto.classname}">
<div class="input-group-prepend"><span class="input-group-text">작성자</span></div>
<input type="text" class="form-control" id="userid" name="userid" readonly="readonly" value="${sessionScope.userid}">
</div>
<br/>
<div class="input-group mb-3"><div class="input-group-prepend">
<span class="input-group-text">제목</span></div>
<input type="text" class="form-control" id="subject" name="subject">
</div>
<br/>
<div class="input-group mb-3"><div class="input-group-prepend">
<span class="input-group-text">내용</span></div>
<textarea rows="5" cols="20" class="form-control" id="content" name="content"></textarea>
</div>
<div class="button">
<input type="reset" class="btn btn-gray" value="취소">
<input type="button" class="btn btn-primary" id="send" value="후기등록">
</div>
</form>
</div>
<!-- 글쓰기 폼 영역 끝-->
</div>
<!-- 게시판 끝-->
수강후기 게시판 영역은 div태그만 있고 내용이 없다. 테이블 태그는 보이지 않는다. 어떻게 구현할까?
페이지가 로드되자 마자 수강후기 리스트를 불러오도록 자바스크립트 함수를 기입한다.
<script>
$(document).ready(function(){
getData(1, "", "", ${dto.classnum}); //페이지 로드 시 수강후기 리스트 보기
//전체보기 함수
function getData(pageNum, field, word, classnum){
$.get("/Tutoring/board/boardlist",
{"pageNum":pageNum, "field":field, "word":word, "classnum":classnum},
function(d){
$("#result").html(d);
})
}//getData
//검색버튼 클릭
$("#btnSearch").on("click", function(){
getData(1, $("#field").val(), $("#word").val(), $("#classnum").val());
})//btnSearch
- $.get 함수로 "/Tutoring/board/boardlist"로 이동하고 들고온 값을 result div영역에 뿌린다.
WBoardListAction.java
(수강후기 게시판 전체 목록을 가져오는 서블릿. 경로는 "/Tutoring/board/boardlist"이다.)
package com.wboard.action;
import java.io.IOException;
import java.util.ArrayList;
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.wmember.model.PageUtil;
import com.wmember.model.WBoardDAO;
import com.wmember.model.WBoardDTO;
/**
* Servlet implementation class WBoardListAction
*/
@WebServlet("/board/boardlist")
public class WBoardListAction extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public WBoardListAction() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
WBoardDAO dao=WBoardDAO.getInstance();
String pageNum=request.getParameter("pageNum")==null? "1":request.getParameter("pageNum");
int currentPage=Integer.parseInt(pageNum);
int pageSize=5;
int startRow=(currentPage-1)*pageSize+1;
int endRow=currentPage*pageSize;
int count=0;
String field=request.getParameter("field")==null?"":request.getParameter("field");
String word=request.getParameter("word")==null?"":request.getParameter("word");
//어떤 강의인지 강의 번호를 가져오기
String classNumber=request.getParameter("classnum");
int classnum=Integer.parseInt(classNumber);
//수강후기 개수 출력
count=dao.getCount(field, word,classnum);
//총페이지 수
int totPage=(count/pageSize)+(count%pageSize==0?0:1);
int pageBlock=3;
int startPage=((currentPage-1)/pageBlock)*pageBlock+1;
int endPage=startPage+pageBlock-1;
if(endPage>totPage) endPage=totPage;
PageUtil pu=new PageUtil();
pu.setCurrentPage(currentPage);
pu.setEndPage(endPage);
pu.setPageBlock(pageBlock);
pu.setStartPage(startPage);
pu.setTotPage(totPage);
pu.setField(field);
pu.setWord(word);
pu.setClassnum(classnum);
ArrayList<WBoardDTO> arr=null;
if(word.equals("")) {
arr=dao.boardList(startRow, endRow, classnum);
}else {
arr=dao.boardList(field, word, startRow, endRow, classnum);
}
int rowNo=count-((currentPage-1)*pageSize); //매 페이지의 시작번호
request.setAttribute("rowNo", rowNo);
request.setAttribute("pu", pu);
request.setAttribute("board", arr);
request.setAttribute("count", count);
RequestDispatcher rd=request.getRequestDispatcher("listResult.jsp");
rd.forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
관리자 페이지에서 강의목록을 내보냈던 것과 마찬가지로 페이징, 전체 게시글 수, 게시글 목록을 request 객체를 이용해 listResult.jsp로 내보낸다.
PageUtil.java 내용은 앞서 관리자 기능에 대해 소개한 포스팅에 나와있다.
<WBoard.java의 boardList 메소드>(검색이 아닐때)
//검색 아닌 전체보기
public ArrayList<WBoardDTO> boardList(int startRow, int endRow, int classnum) {
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
ArrayList<WBoardDTO>arr=new ArrayList<WBoardDTO>();
try {
con=getConnection();
StringBuilder sb=new StringBuilder();
sb.append(" select * from");
sb.append(" (select aa.*, rownum rn from");
sb.append(" (select * from WBoard where classnum="+classnum);
sb.append(" order by num desc) aa");
sb.append(" where rownum<=?) where rn>=?");
ps=con.prepareStatement(sb.toString());
ps.setInt(1, endRow);
ps.setInt(2, startRow);
rs=ps.executeQuery();
while(rs.next()) {
WBoardDTO dto=new WBoardDTO();
dto.setNum(rs.getInt("num"));
dto.setContent(rs.getString("content"));
dto.setReadcount(rs.getInt("readcount"));
dto.setReg_date(rs.getString("reg_date"));
dto.setSubject(rs.getString("subject"));
dto.setUserid(rs.getString("userid"));
dto.setClassnum(rs.getInt("classnum"));
arr.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, ps, rs);
}
return arr;
}
이때 SQL문이 헷갈려서 고생을 했다.. (좀 막혔던 부분들을 생각해보면 다 전체목록 보기에 관한 기능 구현에 관해서다..)
지금까지 전체 목록을 볼때는 검색한 결과인지 아닌지만 가르면 됐는데, 지금의 수강후기 게시판은 "특정 강의에 대한" 수강후기라는 단서가 붙는다.
그래서 처음엔 바깥에 select를 한번 더 감싸고 where classnum=강의번호; 라고 조건절을 줬고 그 select문 안에서 rn을 미리 부여해놓고 5에서 10사이, 10에서 15사이 이런식으로 골라냈었다. 당연히 1페이지에는 2개, 2페이지에는 5개 이렇게 오류가 날 수 밖에 없었다. (사실 오류가 아니고 당연한 결과다.)
하지만 강의 페이지별로 수강후기 DB가 따로 있는게 아니고 전체 수강후기 DB에서 강의번호 별로 골라낸다.
따라서 바깥 select를 지우고, rownum where 절이 아닌 select * from wboard 뒤에 where classnum이라는 조건절을 추가해야한다. 즉 미리 classnum을 골라내고 rn을 계산해야하는 것이다.
<WBoard.java의 boardList 메소드>(검색일때)
//검색 전체보기
public ArrayList<WBoardDTO> boardList(String field, String word, int startRow, int endRow, int classnum) {
Connection con=null;
PreparedStatement ps=null;
ResultSet rs=null;
ArrayList<WBoardDTO>arr=new ArrayList<WBoardDTO>();
try {
con=getConnection();
StringBuilder sb=new StringBuilder();
sb.append(" select * from");
sb.append(" (select aa.*, rownum rn from");
sb.append(" (select * from WBoard where classnum="+classnum);
sb.append(" and upper ("+field+") like upper ('%"+word+"%')");
sb.append(" order by num desc) aa");
sb.append(" where rownum<=?) where rn>=?");
ps=con.prepareStatement(sb.toString());
ps.setInt(1, endRow);
ps.setInt(2, startRow);
rs=ps.executeQuery();
while(rs.next()) {
WBoardDTO dto=new WBoardDTO();
dto.setNum(rs.getInt("num"));
dto.setContent(rs.getString("content"));
dto.setReadcount(rs.getInt("readcount"));
dto.setReg_date(rs.getString("reg_date"));
dto.setSubject(rs.getString("subject"));
dto.setUserid(rs.getString("userid"));
dto.setClassnum(rs.getInt("classnum"));
arr.add(dto);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, ps, rs);
}
return arr;
}
<WBoard.java의 getCount 메소드>
//게시물수 출력
public int getCount(String field, String word, int classnum) {
Connection con=null;
Statement st=null;
ResultSet rs=null;
int count=0;
String sql="";
try {
con=getConnection();
st=con.createStatement();
if(word.equals("")) {
sql="select count(*) from WBoard where classnum="+classnum;
}else {
sql="select count(*) from WBoard where upper ("+field+") like upper ('%"+word+"%') and classnum="+classnum;
}
rs=st.executeQuery(sql);
if(rs.next()) {
count=rs.getInt(1);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, st, rs);
}
return count;
}
listResult.jsp
WBoardListAction.java에서 내보내진 값을 board란 이름에 담아서 뿌린다. 페이징 영역도 포함하고 있다.
그런데 courseDetail.jsp->WBoardListAction.java->listResult.jsp로 이동된 것이므로 $.get의 콜백함수에 의해 이 값들이 courseDetail.jap의 result div에 뿌려지게 된다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<body>
<h5 style="text-align: left"><span id="cntSpan">수강후기(${count}</span>)</h5>
<table class="table table-hover table-bordered table-sm">
<thead>
<tr>
<th style="width: 8%">글번호</th>
<th style="width: 13%">작성자</th>
<th>제목</th>
<th style="width: 8%">작성일</th>
<th style="width: 7%">조회수</th>
</tr>
</thead>
<tbody>
<c:forEach items="${board}" var="board" varStatus="st">
<tr>
<td>${rowNo-st.index}</td>
<td>${board.userid}</td>
<td><a href="/Tutoring/board/boardDetail?num=${board.num}">${board.subject}</a></td>
<td>${board.reg_date}</td>
<td>${board.readcount}</td>
</tr>
</c:forEach>
</tbody>
</table>
<div align="center">
<c:if test="${pu.startPage>pu.pageBlock}"> <!-- 이전 -->
<a href="javascript:getData(${pu.startPage-pu.pageBlock},'${pu.field}','${pu.word}', ${pu.classnum})">[이전]</a>
</c:if>
<c:forEach begin="${pu.startPage}" end="${pu.endPage}" var="i"><!-- 페이지 출력 -->
<c:if test="${i==pu.currentPage}"> <!-- 현재 페이지 -->
<c:out value="${i}"/>
</c:if>
<c:if test="${i!=pu.currentPage}"> <!-- 현재 페이지 아닌 경우 링크 부여-->
<a href="javascript:getData(${i},'${pu.field}','${pu.word}', ${pu.classnum})">${i}</a>
</c:if>
</c:forEach>
<c:if test="${pu.endPage<pu.totPage}"> <!-- 다음-->
<a href="javascript:getData(${pu.endPage+1},'${pu.field}','${pu.word}', ${pu.classnum})">[다음]</a>
</c:if>
</div>
</body>
</html>
다음은 수강후기 글쓰기에 대한 내용이다.
지금까지는 로그인 없이 볼 수 있는 내용들이었지만 수강후기를 쓰려고 하면 로그인을 해야한다.
글쓰기 버튼을 누르면 숨어있던 글쓰기 폼이 나타난다. 부트스트랩의 collapse 클래스를 이용했다.
courseDetail.jsp 내에 글쓰기 폼이 있으므로 후기등록 버튼을 눌렀을때 실행되는 자바스크립트 함수도 이곳에 적어준다.
//후기등록 버튼 클릭
$("#send").click(function(){ //후기등록 버튼 클릭
if(${sessionScope.userid==null}){
alert("로그인 필요");
location.href="/Tutoring/member/login";
}else{
var classnum=$("#classnum").val();
var userid=$("#userid").val();
var content=$("#content").val();
var subject=$("#subject").val();
var postString="classnum="+classnum+"&userid="+userid+"&content="+content+"&subject="+subject;
$.ajax({
type: "post",
url : "/Tutoring/board/boardinsert",
data: postString,
success:function(d){
alert("후기가 등록되었습니다!");
$("#result").html(d);
document.getElementById("wFrm").reset();
},
beforeSend: showRequest, //빈칸 확인
error: function(e){
alert("error:"+e);
}
})//ajax
}
})//send
}); //document ready
//빈칸확인 함수
function showRequest(){
if($("#subject").val()==""){
alert("제목을 입력하세요");
$("#subject").focus();
return false;
}
if($("#content").val()==""){
alert("내용을 입력하세요");
$("#content").focus();
return false;
}
return true;
}
로그인을 하지 않았을 경우 alert창을 띄우고 login화면으로 넘어간다.
로그인을 한 경우 $.ajax을 이용하여 비동기방식으로 수강후기가 입력되며, 새로고침을 하지 않아도 수강후기 화면이 업데이트 된다.
WBoardInsertAction.java
($.ajax를 통해 넘어온 수강후기 입력 서블릿. 경로는 "/Tutoring/board/boardinsert"이다.)
package com.wboard.action;
import java.io.IOException;
import java.io.PrintWriter;
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.wmember.model.WBoardDAO;
import com.wmember.model.WBoardDTO;
/**
* Servlet implementation class BoardInsertAction
*/
@WebServlet("/board/boardinsert")
public class WBoardInsertAction extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public WBoardInsertAction() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher rd=request.getRequestDispatcher("courseDetail.jsp");
rd.forward(request, response);
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
*/
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
WBoardDTO board=new WBoardDTO();
board.setClassnum(Integer.parseInt(request.getParameter("classnum")));
board.setUserid(request.getParameter("userid"));
board.setSubject(request.getParameter("subject"));
board.setContent(request.getParameter("content"));
WBoardDAO dao=WBoardDAO.getInstance();
int classNumber=Integer.parseInt(request.getParameter("classnum"));
int flag=0;
flag=dao.boardInsert(board);
if(flag==1){
response.sendRedirect("/Tutoring/class/CourseDetail?num="+classNumber);
}
}
}
WBoardDAO.java의 boardInsert메소드를 수행하여 수강후기가 입력되었으면 return된 flag 값을 받아오고 1일 경우 다시 CourseDetail로 넘어간다. 수강후기가 해당되는 강의 상세보기로 넘어가므로 num값을 미리 받아와야한다.
<WBoardDAO.java의 boardInsert메소드>
//디비셋팅
private static WBoardDAO instance=new WBoardDAO();
public static WBoardDAO getInstance() {
return instance;
}
private Connection getConnection() throws Exception{
Context initCtx=new InitialContext();
Context envCtx=(Context) initCtx.lookup("java:comp/env");
DataSource ds=(DataSource) envCtx.lookup("jdbc/wiser");
return ds.getConnection();
}
//게시물등록
public int boardInsert(WBoardDTO vo) {
Connection con=null;
PreparedStatement ps=null;
int flag=0;
try {
con=getConnection();
String sql="INSERT INTO WBoard(num, userid, subject, content, reg_date, "
+ "readcount, classnum)"
+ "VALUES(WBoard_seq.nextval,?,?,?,sysdate,0,?)";
ps=con.prepareStatement(sql);
ps.setString(1, vo.getUserid());
ps.setString(2, vo.getSubject());
ps.setString(3, vo.getContent());
ps.setInt(4, vo.getClassnum());
flag=ps.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
closeConnection(con, ps);
}
return flag;
}
//닫기 closeConnection
private void closeConnection(Connection con, PreparedStatement ps) {
try {
if(ps!=null) ps.close();
if(con!=null) con.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
private void closeConnection(Connection con, Statement st, ResultSet rs) {
try {
if(st!=null) st.close();
if(con!=null) con.close();
if(rs!=null) rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
courseDetail의 $.ajax으로 다시 돌아가면 result영역에 수강후기 게시판이 업데이트되어 나타난다.
게시글 상세보기 및 수정 삭제, 댓글과 관련된 포스팅은 다음에 하겠다.
https://github.com/kkj0712/JspProject_Tutoring
'Learning > JSP' 카테고리의 다른 글
JSP 개인프로젝트-영어 학습 사이트 만들기 (강의 장바구니 담기 및 삭제) (0) | 2020.08.19 |
---|---|
JSP 개인프로젝트-영어 학습 사이트 만들기 (수강후기 상세보기 및 수정 삭제, 댓글 입력 및 삭제) (0) | 2020.08.18 |
JSP 개인프로젝트-영어 학습 사이트 만들기 (강의목록 전체보기, 상세보기) (0) | 2020.08.18 |
JSP 개인프로젝트-영어 학습 사이트 만들기 (관리자 기능) (0) | 2020.08.18 |
JSP 개인프로젝트-영어 학습 사이트 만들기 (로그인, 회원가입) (0) | 2020.08.18 |