20211130 11월의 마지막날 게시판과 글쓰기
·게시판
-오늘은 게시판에 대한 부분을 진행해봤다. 게시판 중에서도 특히 글쓰기를 통해 db에 데이터를 저장하고 등록하는 부분을 위주로 수업을 진행했다.
·게시판 관련 테이블
-우선 DB에 게시판과 관련된 데이터를 넣어야 하기 때문에 게시판의 특히 글쓰기와 관련된 테이블을 만들었다.
CREATE TABLE TBL_BOARD
(
BBS_SEQ NUMBER(12) NOT NULL,
USER_ID VARCHAR2(20),
BBS_NAME VARCHAR2(50),
BBS_EMAIL VARCHAR2(50),
BBS_PWD VARCHAR2(10),
BBS_TITLE VARCHAR(150),
BBS_CONTENT CLOB,
BBS_READ_CNT NUMBER(10),
REG_DATE DATE
);
-인덱스를 만들었고
CREATE UNIQUE INDEX XPK_BOARD ON TBL_BOARD(BBS_SEQ ASC);
-시퀀스를 만들었다. 여기서 시퀀스는 게시글의 순서를 계속 써줄 객체이다.
CREATE SEQUENCE SEQ_BBS_SEQ
INCREMENT BY 1
MAXVALUE 999999999999
MINVALUE 1
NOCACHE;
-list 페이지를 작성했다.
사실 html에 대한 부분은 교수님이 그냥 주셨고, 해당 html의 정보를 어떻게 사용하는지에 대한 부분을 작성했다.
<script>
$(document).ready(function(){
$("#btnWrite").on("click", function(){
document.bbsForm.bbsSeq.value = "";
//해당 페이지로 간다는 뜻.
document.bbsForm.action = "/board/write.jsp";
document.bbsForm.submit();
});
});
</script>
-버튼을 누르면 글쓰기 페이지로 가게 경로를 설정하고 submit해준다. 여기서 중요한 부분은, 게시판의 여러 form태그가 있지만
<form name="bbsForm" id="bbsForm" method="post">
<input type="hidden" name="bbsSeq" value="" />
<!-- 기존에 가지고 있던 서치타입과 서치벨류를 다시 돌아왔을 때 가져온다는 의미고 전에 있던 페이지로 돌아갈 때를 위한 curPage -->
<input type="hidden" name="searchType" value="" />
<input type="hidden" name="searchValue" value="" />
<input type="hidden" name="curPage" value="1" />
</form>
-필요한 정보만 가지고 가기 위해서 hidden form을 사용해서 submit을 해준다.
·테이블 하나엔 .java 하나
-교수님이 나중에 테이블 하나엔 꼭 .java파일 하나가 있어야 한다고 하셨다. board테이블을 만들었으니 해당 데이터베이스의 해당 테이블을 받는 자바파일이 필요하다.
package com.icia.web.model;
import java.io.Serializable;
public class Board implements Serializable {
private static final long serialVersionUID = 1L;
private long bbsSeq; //게시물 번호
private String userId; //게시자 아이디
private String bbsName; //게시자 명
private String bbsEmail; //게시자 이메일
private String bbsPwd; //게시자 비밀번호
private String bbsTitle; //게시물 제목
private String bbsContent; //게시물 내용
private long bbsReadCnt; //게시물 조회수
private String regDate; //등록일
//페이징 처리도 할 것이기 때문에 추가적인 변수를 넣긴 할 것.
public Board()
{
bbsSeq = 0;
userId = "";
bbsName = "";
bbsEmail = "";
bbsPwd = "";
bbsTitle = "";
bbsContent = "";
bbsReadCnt = 0;
regDate = "";
}
public long getBbsSeq() {
return bbsSeq;
}
public void setBbsSeq(long bbsSeq) {
this.bbsSeq = bbsSeq;
}
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public String getBbsName() {
return bbsName;
}
public void setBbsName(String bbsName) {
this.bbsName = bbsName;
}
public String getBbsEmail() {
return bbsEmail;
}
public void setBbsEmail(String bbsEmail) {
this.bbsEmail = bbsEmail;
}
public String getBbsPwd() {
return bbsPwd;
}
public void setBbsPwd(String bbsPwd) {
this.bbsPwd = bbsPwd;
}
public String getBbsTitle() {
return bbsTitle;
}
public void setBbsTitle(String bbsTitle) {
this.bbsTitle = bbsTitle;
}
public String getBbsContent() {
return bbsContent;
}
public void setBbsContent(String bbsContent) {
this.bbsContent = bbsContent;
}
public long getBbsReadCnt() {
return bbsReadCnt;
}
public void setBbsReadCnt(long bbsReadCnt) {
this.bbsReadCnt = bbsReadCnt;
}
public String getRegDate() {
return regDate;
}
public void setRegDate(String regDate) {
this.regDate = regDate;
}
}
-여기서 초기화를 해주는 부분은 반드시 들어가야 한다. 물론 데이터를 캡슐화하기 위해서 private으로 설정해줬고 이 변수들을 사용하려면 getter와 setter를 작성해줘야 한다.
이제 쿼리문을 위한 BoardDao.java를 작성해야 한다. 그 전에 SQLdeveloper에서 미리 쿼리문을 사용해서 insert문을 실행해보고 검증한 후에 쿼리문을 가져오는 것을 추천한다. 그래야 쿼리문 오류를 잡을 수 있기 때문이다.
package com.icia.web.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.icia.web.db.DBManager;
import com.icia.web.model.Board;
public class BoardDao {
//BOARD TABLE 인서트
//로그를 위한 객체
private static Logger logger = LogManager.getLogger(BoardDao.class);
//빈 생성자
public BoardDao()
{
}
//게시판 등록
public int boardInsert(Board board)
{
int count = 0;
Connection conn = null;
PreparedStatement pstmt = null;
StringBuilder sql = new StringBuilder();
sql.append("INSERT INTO TBL_BOARD ");
sql.append(" (BBS_SEQ, USER_ID, BBS_NAME, BBS_EMAIL, BBS_PWD, BBS_TITLE, ");
sql.append(" BBS_CONTENT, BBS_READ_CNT, REG_DATE) ");
sql.append(" VALUES (?, ?, ?, ?, ?, ?, ?, 0, SYSDATE) ");
//쿼리문에는 ;론 붙이지 말자!!! 쉽게 나는 오류!!!
try
{
int idx = 0;
conn = DBManager.getConnection();
//시퀀스 조회 추가
//얘는 시퀀스를 얻어와서 사용할 용도의 변수.
long bbsSeq = 0;
//현재 클래스 안에 있는 메소드이기 때문에 굳이 클래스 이름을 붙일 필요가 없음
bbsSeq = newBbsSeq(conn);
//board객체에 담으려고 한거
board.setBbsSeq(bbsSeq);
pstmt = conn.prepareStatement(sql.toString());
//DB에 넣으려고 작성한거
pstmt.setLong(++idx, bbsSeq);
//board.getBbsSeq();로 해도 됨.
//이미 위에 set메소드로 bbsSeq를 넣어놨기 때문에 이렇게 해도 된다는 것.
pstmt.setString(++idx, board.getUserId());
pstmt.setString(++idx, board.getBbsName());
pstmt.setString(++idx, board.getBbsEmail());
pstmt.setString(++idx, board.getBbsPwd());
pstmt.setString(++idx, board.getBbsTitle());
pstmt.setString(++idx, board.getBbsContent());
count = pstmt.executeUpdate();
}
catch(SQLException e)
{
logger.error("[BoardDao] boardInsert SQLException", e);
}
finally
{
DBManager.close(pstmt, conn);
}
return count;
}
//시퀀스를 가져올 메소드
private long newBbsSeq(Connection conn)
{
//매개변수로 커넥션 객체를 가져오는 이유는
//이미 해당 메소드를 호출한 곳에서 이미 connection을 이뤄놨기 때문에 해당 커넥션
//객체를 가져오는 것이 맞음. 자원낭비를 안하기 위해서.
long bbsSeq = 0;
PreparedStatement pstmt = null;
ResultSet rs = null;
StringBuilder sql = new StringBuilder();
sql.append(" SELECT SEQ_BBS_SEQ.NEXTVAL ");
sql.append(" FROM DUAL ");
try
{
pstmt = conn.prepareStatement(sql.toString());
rs = pstmt.executeQuery();
if(rs.next())
{
//인덱스 1번째꺼를 가져온다.
//컬럼이 두개면 1번, 2번 주면 됨.
//원래 알리아스로 받아왔음. 1부분이
//근데 어차피 결과가 하나뿐임.
bbsSeq = rs.getLong(1);
}
}
catch(SQLException e)
{
logger.error("[BoardDao] newBbsSeq SQLException", e);
}
//finally를 붙일 필요가 없는 이유는, 아직 또 쿼리문을 실행해야하기 때문에
//닫지 않는 것이다.
return bbsSeq;
}
}
-여기의 메소드들은 userDao와 크게 다르지 않다. 다만, 한가지 시퀀스를 사용하기 때문에, 시퀀스를 얻어오는 메소드를 하나 더 정의해야 한다는 점이다. 이 때, 매개변수로 Connection 객체를 넘기는 이유는 DB와 연결된 그 상태 그대로 쿼리를 진행하겠다는 의미이다. 그리고 finally에 db를 닫아줘서도 안된다. 왜냐하면 다시 돌아가서 Board에 인서트하는 쿼리를 진행할 것이기 때문이다. 또한 시퀀스.NEXTVAL은 select 구문으로 가져오는 것이기 때문에 ResultSet객체로 받아야 한다.
이제 write 페이지를 만들어준다.
<%
//로그
Logger logger = LogManager.getLogger("/board/write.jsp");
HttpUtil.requestLogString(request, logger);
//리스트 페이지를 거쳐왔기 때문에 굳이 쿠키값을 확인해서 돌려보내지는 않았지만 그래도
//해주는 것이 좋음.
String cookieUserId = CookieUtil.getValue(request, "USER_ID");
int chkVal = 0;
if(StringUtil.isEmpty(cookieUserId))
{
chkVal = 1; //1이면 값이 없다는 뜻.
response.sendRedirect("/");
}
//값이 없을 때 ""처리하겠다는 매개변수 3개짜리
//리스트 페이지로 다시 돌아가게 하는 것.
String searchType = HttpUtil.get(request, "searchType", "");
String searchValue = HttpUtil.get(request, "searchValue", "");
long curPage = HttpUtil.get(request, "curPage", (long)1);
//롱타입으로 강제 형변환한다.
//리스트 페이지를 통해 넘어오니까 예외처리는 하지 않았음
UserDao userDao = new UserDao();
User user = userDao.userSelect(cookieUserId);
if(chkVal == 0)
{
%>
==========html의 전반의 내용================
<%
}
%>
-이 부분은 chkVal이 0이 아니면, 즉, 1이면 html을 보여주지 않겠다는 의미이고, 1이 되는 경우는 쿠키에 아이디가 없을 때이다.
<script>
$(document).ready(function(){
//제목에 깜빡이기.
$("#bbsTitle").focus();
//작성 버튼이 클릭되었을 때
$("#btnWrite").on("click", function(){
if( $.trim($("#bbsTitle").val()).length <=0 )
{
alert("제목을 입력해주세요");
$("#bbsTitle").val("");
$("#bbsTitle").focus();
return;
}
if( $.trim($("#bbsContent").val()).length <=0 )
{
alert("내용을 입력해주세요.");
$("#bbsContent").val("");
$("#bbsContent").focus();
return;
}
document.writeForm.submit();
});
//리스트 버튼이 눌렸을 때.
$("#btnList").on("click", function(){
document.bbsForm.action = "/board/list.jsp";
document.bbsForm.submit();
});
});
위의 jQuery로 writeForm을 submit해준다. 이 때 위에는 적혀있지 않지만, writeProc.jsp로 action이 설정되어 있다. 그렇다면 writeProc.jsp에서 나머지 쿼리실행 등에 대한 모든 처리를 해준다.
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
//로그
Logger logger = LogManager.getLogger("/board/writeProc.jsp");
HttpUtil.requestLogString(request, logger);
String cookieUserId = CookieUtil.getValue(request, "USER_ID");
//로그인이 되어있는지부터 확인해야됨.
boolean bSuccess = false;
String errorMsg = "";
//TBL_USER 테이블에 있는 값들은 가져올 필요가 없음.
String bbsTitle = HttpUtil.get(request, "bbsTitle", "");
String bbsContent = HttpUtil.get(request, "bbsContent", "");
if(!StringUtil.isEmpty(cookieUserId))
{
//쿠키 값이 있으면 아래 실행
UserDao userDao = new UserDao();
User user = userDao.userSelect(cookieUserId);
if(user != null)
{
if(StringUtil.equals(user.getStatus() , "Y"))
{
//정상 사용자임.
if(!StringUtil.isEmpty(bbsTitle) && !StringUtil.isEmpty(bbsContent))
{
//둘 다 값이 있어야 인서트가 가능함.
//객체 생성
BoardDao boardDao = new BoardDao();
Board board = new Board();
board.setUserId(cookieUserId);
board.setBbsTitle(bbsTitle);
board.setBbsContent(bbsContent);
if( boardDao.boardInsert(board) >0)
{
bSuccess = true;
}
else
{
//굳이 bSuccess에 false를 넣어줄 필요가 없음 이미 false임.
errorMsg = "게시물 등록중 오류가 발생했습니다.";
}
}
else
{
//값이 없음.
errorMsg = "게시물 입력 값이 올바르지 않습니다.";
}
}
else
{
CookieUtil.deleteCookie(request, response, "USER_ID");
errorMsg = "부적합한 사용자입니다.";
response.sendRedirect("/");
}
}
else
{
CookieUtil.deleteCookie(request, response, "USER_ID");
errorMsg = "올바른 접근이 아닙니다.";
response.sendRedirect("/");
}
}
else
{
//쿠키 값이 없음.
CookieUtil.deleteCookie(request, response, "USER_ID");
errorMsg = "올바른 접근이 아닙니다.";
response.sendRedirect("/");
}
%>
<!DOCTYPE html>
<html>
<head>
<%@ include file="/include/head.jsp" %>
<script>
$(document).ready(function(){
<%
if( bSuccess == true)
{
%>
alert("게시물이 등록되었습니다.");
<%
}
else
{
%>
alert("<%= errorMsg %>");
<%
}
%>
//여기서 굳이 searchValue 등의 값들을 가져가지 않는 이유는 글쓰고 나서는 가장 최근 페이지를
//보여주면 되기 때문. 굳이 검색 속성들을 가져올 필요가 없음.
location.href = "/board/list.jsp";
});
</script>
</head>
<body>
</body>
</html>
-위의 방법으로 게시글에 대한 인서트문을 날림. 여기서 왜
String bbsTitle = HttpUtil.get(request, "bbsTitle", "");
String bbsContent = HttpUtil.get(request, "bbsContent", "");
이렇게 두 변수만 선언하고 값을 넣어주냐면, 다른 값들은 사용하지 않을 것이기 때문이다. 이렇게 하면 db에 내가 입력한 게시글에 대한 정보가 등록되게 된다. 물론 아직 페이지에서 조회할 수는 없다. 아마도 내일 작성할 듯 싶다.
·어려움
-사실 어느정도 이해는 되고, 따라가기는 하지만, 그래도 아직 헷갈리고 어려운 부분이 많다. 오늘 한 부분들도 내가 직접 게시판2를 만들고 Board2와 BoardDao2와 list2, write2, writeProc2 그리고 오라클에서 새로운 테이블과 인덱스 시퀀스를 만들어서 직접 처음부터 다 다시해봤지만 그래도 역시 많이 참고하면서 했다. 어렵다. 이렇게 갑자기 어려울 수 있나 싶을 정도로 어렵지만, 그래도 재밌고 또 신기하다. 그래서 더 열심히 해야할 것 같다. 오류가 나는 경우도 많이 있어서 비대면 수업이지만 내일도 수업에 나갈 것이다. 아무래도 현장에 있어야 교수님이 오류를 찾아주시기 더 편하고 나 역시 시간이 절약될 것 같기 때문이다. 내일 길이 조금 얼어서 위험하다고는 하는데 조금 무섭지만 그래도 최대한 가려한다. 이제 조금만 더 코드를 복습하고 운동을 하고 자야겠다. 파이팅!
Author And Source
이 문제에 관하여(20211130 11월의 마지막날 게시판과 글쓰기), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@ysparkr841/20211130-11월의-마지막날-게시판과-글쓰기저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)