일반게시판
< 게시글 작성 (첨부파일 1개) >
1) 게시글 작성 화면 요청
2) 게시글 작성 요청
* BOARD 테이블
* CATEGORY 테이블
* ATTACHMENT 테이블
1) 게시글 작성 화면 요청
1. 게시글 작성 화면 요청
- 로그인한 회원만 보이는 게시글 작성 버튼 작성
<% if (loginUser != null) { %>
<a href="<%= contextPath %>/enrollForm.bo" class="btn btn-info btn-sm">글작성</a>
<% } %>
2. BoardEnrollForm.java (Servlet)
- 게시글 작성 화면 응답
- DB의 CATEGORY테이블을 조회해서 option태그로 띄워줌
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 카테고리 목록 조회
ArrayList<Category> list = new BoardService().selectCategoryList();
request.setAttribute("list", list);
request.getRequestDispatcher("views/board/boardEnrollForm.jsp").forward(request, response);
}
3. BoardService.java (자바클래스)
- selectCategoryList() : 카테고리가 담긴 ArrayList 반환
public ArrayList<Category> selectCategoryList() {
Connection conn = getConnection();
ArrayList<Category> list = new BoardDao().selectCategoryList(conn);
close(conn);
return list;
}
4. BoardDao.java (자바클래스)
- selectCategoryList() : 카테고리가 담긴 ArrayList 반환
public ArrayList<Category> selectCategoryList(Connection conn) {
// SELECT문 => ResultSet => 여러행 => List
ArrayList<Category> list = new ArrayList();
PreparedStatement pstmt = null;
ResultSet rset = null;
String sql = prop.getProperty("selectCategoryList");
try {
pstmt = conn.prepareStatement(sql);
rset = pstmt.executeQuery();
while(rset.next()) {
list.add(new Category(rset.getInt("CATEGORY_NO"),
rset.getString("CATEGORY_NAME")));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(rset);
close(pstmt);
}
return list;
}
- SQL문 (SELECT)
<entry key="selectCategoryList">
SELECT CATEGORY_NO, CATEGORY_NAME
FROM CATEGORY
</entry>
2) 게시글 작성 요청
1. 게시글 작성 화면
- 넘겨받은 카테고리 목록을 변수로 저장
<%@ page import="java.util.ArrayList, com.kh.board.model.vo.Category" %>
<%
ArrayList<Category> list = (ArrayList<Category>)request.getAttribute("list");
%>
- 게시글 입력할 form태그 작성. 파일을 첨부하는 경우 enctype속성을 multipart/form-data로 설정
- 내용이 많을 수 있으므로 post방식으로 요청
<form action="<%= contextPath %>/insert.bo" method="post" enctype="multipart/form-data">
<!-- 제목, 내용, 카테고리, 제출버튼, 글쓴이, 첨부파일 -->
<!-- 작성자의 회원번호를 hidden으로 같이 넘겨서 board 테이블에 INSERT하게 만들 것 -->
<input type="hidden" name="userNo" value="<%= loginUser.getUserNo() %>">
<table align="center">
<tr>
<th width="150">카테고리</th>
<td width="600">
<select name="category">
<% for(Category c : list) { %>
<option value="<%= c.getCategoryNo() %>"><%= c.getCategoryName() %></option>
<% } %>
</select>
</td>
</tr>
<tr>
<th>제목</th>
<td><input type="text" name="title" required></td>
</tr>
<tr>
<th>내용</th>
<td><textarea name="content" style="resize: none;" rows="10" required></textarea></td>
</tr>
<tr>
<th>첨부파일</th>
<td><input type="file" name="upfile"></td>
</tr>
</table>
<br>
<div align="center">
<button type="reset">취소하기</button>
<button type="submit">작성하기</button>
</div>
</form>
2. BoardImsertController.java (Servlet)
- 매핑값 : /insert.bo
- enctype을 multipart/form-data로 전송했기때문에 MultipartRequest객체로 값을 다뤄야 함
- MultipartRequest 객체 생성자에 매개변수로 전달할 값 : request, savePath, maxSize, 인코딩, 파일명을 수정시켜주는 객체
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1) 인코딩 설정 (POST)
request.setCharacterEncoding("UTF-8");
// 2) 값 뽑기
// 스텝 0. 조건문 : enctype이 multipart/form-data로 잘 전송되었을 경우 전반적인 내용들이 수정되도록 조건을 걸어줌
if(ServletFileUpload.isMultipartContent(request)) {
// 스텝 1. 전송되는 파일을 처리할 작업
// 1-1. 전송파일 용량 제한
int maxSize = 10 * 1024 * 1024; // 10MByte
// 1-2. 전달된 파일을 저장할 서버의 폴더 경로 알아내기
// 메소드를 써서 알아냄 - getRealPath() 호출 => 인자값으로 WebContent부터 board_upfiles폴더까지의 경로를 제시
HttpSession session = request.getSession();
ServletContext application = session.getServletContext();
String savePath = application.getRealPath("/resources/board_upfiles/");
// 스텝 2. 서버에 업로드 작업(파일명 수정)
MultipartRequest multiRequest = new MultipartRequest(request, savePath, maxSize, "UTF-8", new MyFileRenamePolicy());
// 2) 값 뽑기
// 카테고리 번호, 제목, 내용, 게시글을 작성한 회원번호 Board객체로 가공
String category = multiRequest.getParameter("category");
String title = multiRequest.getParameter("title");
String content = multiRequest.getParameter("content");
String userNo = multiRequest.getParameter("userNo");
// 3) VO객체로 가공 => 첫번째 INSERT문에 해당(BOARD테이블)
Board b = new Board();
b.setCategory(category);
b.setBoardTitle(title);
b.setBoardContent(content);
b.setBoardWriter(userNo);
// 두번째 INSERT -> 선택적(첨부파일이 있을 경우에만 INSERT)
Attachment at = null;
// => 첨부파일이 있으면 "원본파일명" / 첨부파일이 없으면 null 리턴
if(multiRequest.getOriginalFileName("upfile") != null) {
// 첨부파일이 있다 => VO객체로 가공
at = new Attachment();
// 원본파일명
at.setOriginName(multiRequest.getOriginalFileName("upfile"));
// 수정파일명
at.setChangeName(multiRequest.getFilesystemName("upfile"));
// 파일 경로
at.setFilePath("resources/board_upfiles");
}
// 4) 서비스 요청
int result = new BoardService().insertBoard(b, at);
// 5) 응답페이지 지정
if (result > 0) { // 성공
request.getSession().setAttribute("alertMsg", "게시글 작성에 성공했습니다.");
response.sendRedirect(request.getContextPath() + "/list.bo?cpage=1");
} else { // 실패
// 첨부파일이 있을 때만(at != null), delete() 호출해서 파일 삭제
if(at != null) {
new File(savePath + at.getChangeName()).delete();
}
request.setAttribute("errorMsg", "게시글 작성 실패");
request.getRequestDispatcher("views/common/errorPage.jsp").forward(request, response);
}
}
}
- MyFileRenamePolicy.java (자바클래스)
- 인터페이스를 구현 (implements FileRenamePolicy)
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.oreilly.servlet.multipart.FileRenamePolicy;
// 인터페이스를 구현
public class MyFileRenamePolicy implements FileRenamePolicy {
@Override
public File rename(File originFile) {
// 원본 파일명 뽑기 => 매개변수로 전달받은 원본 파일로부터
String originName = originFile.getName();
// 수정파일명 만들기 (규칙)
// 파일이 업로드된 시간 (년월일시분초) + 5자리 랜덤값(10000 ~ 99999) + 확장자
// 1. 파일이 업로드된 시간 추출
String currentTime = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
// 2. 5자리 랜덤값
int ranNum = (int)(Math.random() * 99999 + 10000);
// 3. 확장자 뽑기
String ext = originName.substring(originName.lastIndexOf("."));
// 4. 1+2+3 조합해서 수정파일명을 변수에 담기
String changeName = "kakao_" + currentTime + "_" + ranNum + ext;
// 기존 파일을 수정된 파일명으로 적용시켜서 리턴
return new File(originFile.getParent(), changeName);
}
}
3. BoardService.java (자바클래스)
- insertBoard() : 게시글내용을 담은 Board객체와 첨부파일 내용을 담은 Attachment객체 전달
- DAO에 두 번 요청 (게시글 등록 요청 / 첨부파일이 있을 경우)
- 두 등록이 모두 성공해야 성공 → 트랜잭션처리
public int insertBoard(Board b, Attachment at) {
Connection conn = getConnection();
// 1) BOARD테이블에 INSERT
int result1 = new BoardDao().insertBoard(conn, b);
// 2) ATTACHMENT테이블에 INSERT
int result2 = 1; // 0이 돌아오면 실패로
if (at != null) {
result2 = new BoardDao().insertAttachment(conn, at);
}
// 3) 트랜잭션 처리
if((result1 * result2) > 0) commit(conn);
else rollback(conn);
close(conn);
return (result1 * result2);
}
4. BoardDao.java (자바 클래스)
- 두 개의 메소드 작성
- insertBoard() : BOARD게시판에 INSERT문 실행
public int insertBoard(Connection conn, Board b) {
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("insertBoard");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, Integer.parseInt(b.getCategory()));
pstmt.setString(2, b.getBoardTitle());
pstmt.setString(3, b.getBoardContent());
pstmt.setInt(4, Integer.parseInt(b.getBoardWriter()));
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
- SQL문
<entry key="insertBoard">
INSERT
INTO
BOARD
(
BOARD_NO,
BOARD_TYPE,
CATEGORY_NO,
BOARD_TITLE,
BOARD_CONTENT,
BOARD_WRITER
)
VALUES
(
SEQ_BNO.NEXTVAL,
1,
?,
?,
?,
?
)
</entry>
- insertAttachment() : ATTACHMENT테이블에 INSERT문 실행
public int insertAttachment(Connection conn, Attachment at) {
int result = 0;
PreparedStatement pstmt = null;
String sql = prop.getProperty("insertAttachment");
try {
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, at.getOriginName());
pstmt.setString(2, at.getChangeName());
pstmt.setString(3, at.getFilePath());
result = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally {
close(pstmt);
}
return result;
}
- SQL문
- 게시글 번호로 직전에 실행되는 insertBoard에서 발생한 시퀀스의 번호값을 가져옴
<entry key="insertAttachment">
INSERT
INTO
ATTACHMENT
(
FILE_NO,
REF_BNO,
ORIGIN_NAME,
CHANGE_NAME,
FILE_PATH
)
VALUES
(
SEQ_FNO.NEXTVAL,
SEQ_BNO.CURRVAL,
?,
?,
?
)
</entry>
'개발 > Web' 카테고리의 다른 글
[Java] Servlet - Request / Session / Application / Page 객체 (0) | 2022.11.18 |
---|---|
[Java] Sevlet/JSP - 일반게시판 - 게시글 수정 (첨부파일 1개) (0) | 2022.11.18 |
[Java] Sevlet/JSP - 일반게시판 - 게시글 리스트 조회 / 페이징 처리 (0) | 2022.11.18 |
[Java] Sevlet/JSP - 공지사항 - 공지사항 리스트 조회 (0) | 2022.11.18 |
[Java] Sevlet/JSP - 회원서비스 - 회원 탈퇴 (0) | 2022.11.18 |