목표:게시판을 만들고 mysql에 첨부 파일과 폼에 입력한 데이터를 올린다
순차적으로 진행
데이터베이스
mysql
-- 게시판 생성 수업시간에 진도 나간 부분
CREATE DATABASE study;
-- 데이터 베이스가 없다면 생성해준다
USE STUDY;
-- 데이터 베이스 사용
-- #####################################################################################
DROP TABLE IF EXISTS TBOARD_PART;
CREATE TABLE IF NOT EXISTS TBOARD_PART (
FIDX TINYINT NOT NULL COMMENT 'P/K, 머릿글 번호',
FPART NVARCHAR(4) NOT NULL COMMENT '머릿글',
PRIMARY KEY (FIDX)
) COMMENT='게시판의 글머릿글에 사용';
INSERT INTO TBOARD_PART VALUES
('1', '학습'), ('2', '생활'), ('3', '취업'), ('4', '고민'), ('5', '과정');
-- #####################################################################################
DROP TABLE IF EXISTS TBOARD;
CREATE TABLE IF NOT EXISTS TBOARD (
FIDX INT NOT NULL COMMENT '일련번호, P/K, ',
FNUM INT NOT NULL DEFAULT 0 COMMENT '목록번호(질문), 답글의 경우 0',
FGROUP INT NOT NULL COMMENT '그룹번호, 1차 정렬 필드, 질문은 자신의 FIDX, 답글은 선택글의 FGROUP번호',
FLEVEL INT NOT NULL DEFAULT 0 COMMENT '질문은 0, 답글은 선택한 글의 FLEVEL+1',
FSTEP INT NOT NULL COMMENT '2차 정렬 필드, 질문은 0, 답글은 그룹내 선택한 목록의 FSTEP 이상인 글은 모두 1증가 이후 선택 목록의 FSTEP값을 갖는다, ',
FTOP ENUM('Yes', 'No') NOT NULL COMMENT '상단노출, 1페이지 상단에 노출하고자 하는 목록은 Yes(1)',
FPARTIDX TINYINT NOT NULL COMMENT '머릿글, 별도의 테이블을 만들어 관리, fk_tboard_fpartidx_tboardPart_fidx',
FSUBJECT NVARCHAR(50) NOT NULL COMMENT '게시판의 제목 필드',
FCONTENT TEXT NOT NULL COMMENT '게시판의 내용 필드',
FID VARCHAR(20) COMMENT '회원의 경우 아이디 저장, 이름은 회원명 저장, 비밀번호는 저장하지 않음',
FNAME NVARCHAR(20) NOT NULL COMMENT '작성자 이름, 회원의 경우 회원명 저장(Join으로 인한 검색속도 저하문제 보완)',
FPASSW VARCHAR(20) NULL COMMENT '삭제 수정을 위한 비밀번호, 회원의 경우 Null',
FHIT SMALLINT NOT NULL DEFAULT 0 COMMENT '글 조횟수',
FDELETED ENUM('Yes', 'No') NOT NULL COMMENT '작성자에 의해 삭제된 경우(1, Yes)',
FDATE DATETIME NOT NULL COMMENT '24시간 이내의 글은 new표시',
PRIMARY KEY (FIDX),
FOREIGN KEY (FPARTIDX) REFERENCES TBOARD_PART (FIDX)
ON UPDATE CASCADE
) COMMENT='JSP&SERVLET을 활용한 Q&A 게시판 수업을 위한 게시글 정보 테이블';
-- #####################################################################################
DROP TABLE IF EXISTS TBOARD_FILE;
CREATE TABLE IF NOT EXISTS TBOARD_FILE (
FIDX INT NOT NULL COMMENT '일련번호, P/K',
FBOARDIDX INT NOT NULL COMMENT 'F/K, 게시판의 목록 FIDX',
FFILENAME VARCHAR(30) NOT NULL COMMENT '업로드된 파일의 원래 이름',
FSAVENAME VARCHAR(30) NOT NULL COMMENT '업로드된 파일의 저장된 이름',
FFILESIZE INT NOT NULL COMMENT '업로드된 파일의 크기',
FDOWNLOAD INT NOT NULL DEFAULT 0 COMMENT '다운로드 수' ,
PRIMARY KEY (FIDX)
-- , FOREIGN KEY (FBOARDIDX) REFERENCES TBOARD (FIDX)
-- FOREIGN KEY는 관계를 맺어야하므로 해당 테이블만 가지고 테스트를 할 때는 막아두기
) COMMENT='게시글에 파일을 첨부할 경우 다중 파일 업로드가 가능하도록 별도의 테이블로 관리';
-- =====================================================================================
select MAX(FIDX) from TBOARD_FILE;
-- TBOARD_FILE에서 FIDX가 MAX(최대치)인 값 출력
select ifnull(MAX(FIDX),1) from TBOARD_FILE;
-- null 이면 1을 출력, 아니면 MAX(FIDX)출력
select ifnull(MAX(FIDX)+1,1) aidx from TBOARD_FILE;
-- TBOARD_FILE에서 fid가 null이 아니면 FIDX 최대 값에 1을 더하고 null이면 1을 출력한다
-- aidx는 가상 칼럼의 이름이다
-- ==================================================
desc TBOARD;
desc TBOARD_FILE;
-- ------------------------------
insert into TBOARD_FILE(FIDX, FBOARDIDX, FFILENAME, FSAVENAME,FFILESIZE)
value('"++"','"++"','"++"','"++"','"++"');
-- value는 한 칸 띄우고 시작(공백도 신경쓰기)
-- ----------해당 코드는 Servlet에 사용하기 위한 코드를 미리 만든 것으로 MYSQL에서는 작동하지 않는다-------------
INSERT INTO TBOARD_FILE (FIDX, FBOARDIDX, FFILENAME, FSAVENAME, FFILESIZE)
VALUE('1','1','memo.txt','memo.txt','1024');
INSERT INTO TBOARD_FILE (FIDX, FBOARDIDX, FFILENAME, FSAVENAME, FFILESIZE)
VALUE('2','1','memo.txt','memo.txt','1024');
-- 데이터 삽입
SELECT ifnull(MAX(FIDX)+1,1) aidx from TBOARD_FILE;
-- TBOARD_FILE에서 FIDX의 MAX(최대값)이 null이 아니면 최대값+1, null이면 1을 가상칼럼 aidx로 출력한다
select*from TBOARD_FILE;
select*from TBOARD;
select*from TBOARD_PART;
mysql에서 TBOARD_FILE 테이블을 생성하고 데이터 값을 넣은 후 출력시킨다

출력을 확인하고 ifnull문을 실행하여 결과값을 확인한다

게시판 폼 생성
파일 생성 위치 및 class 설정

reset.css
@charset "utf-8";
/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */
html {-webkit-text-size-adjust:100%;line-height:1.15}
body {margin:0;padding:0;}
main {display:block}
h1, h2, h3, h4, h5, h6, h7 {margin:0;padding:0;}
h1 {font-size:2em;margin:0}
hr {box-sizing:content-box;height:0;overflow:visible}
pre {font-family:monospace, monospace;font-size:1em}
/* ---------------- 사용자 설정 -----------------*/
ul, li, ol, dl, dt, dd {margin:0;padding:0;list-style: none;}
/* --------------- e:사용자 설정 ----------------*/
a {background-color:transparent}
abbr[title] {border-bottom:none;text-decoration:underline;text-decoration:underline dotted}
b, strong {font-weight:bolder}
code, kbd, samp {font-family:monospace, monospace;font-size:1em}
small {font-size:80%}
sub, sup {font-size:75%;line-height:0;position:relative;vertical-align:baseline}
sub {bottom:-.25em}
sup {top:-.5em}
img {border-style:none}
button, input, optgroup, select, textarea {font-family:inherit;font-size:100%;line-height:1.15;margin:0}
button, input {overflow:visible}
button, select {text-transform:none}
[type=button], [type=reset], [type=submit], button {-webkit-appearance:button}
[type=button]::-moz-focus-inner, [type=reset]::-moz-focus-inner, [type=submit]::-moz-focus-inner, button::-moz-focus-inner {border-style:none;padding:0}
[type=button]:-moz-focusring, [type=reset]:-moz-focusring, [type=submit]:-moz-focusring, button:-moz-focusring {outline:1px dotted ButtonText}
fieldset {padding:.35em .75em .625em}
legend {box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}
progress {vertical-align:baseline}
textarea {overflow:auto}
[type=checkbox], [type=radio] {box-sizing:border-box;padding:0}
[type=number]::-webkit-inner-spin-button, [type=number]::-webkit-outer-spin-button {height:auto}
[type=search] {-webkit-appearance:textfield;outline-offset:-2px}
[type=search]::-webkit-search-decoration {-webkit-appearance:none}
::-webkit-file-upload-button {-webkit-appearance:button;font:inherit}
details {display:block}
summary {display:list-item}
[hidden], template {display:none}
table {
border-collapse: collapse;
border-spacing: 0;
}
style.css
@charset "UTF-8";
@import url(reset.css);
@import url(https://cdn.jsdelivr.net/gh/moonspam/NanumSquare@1.0/nanumsquare.css);
html * {
font-family: 'NanumSquare', sans-serif;
color:#222;
}
/*-------------------------------------------------------*/
body {background-color:#fff; }
#container {
margin:0 auto;padding:0;
width:70%;min-width: 720px;
}
h3 {
width:100%; min-width:720px;margin:0 auto;
padding:10px 0;}
h3 span {
display:inline-block; border-bottom:3px solid #fd5a02;
}
.tableBox {
display:table; width:100%; min-width:720px;margin:0 auto;
border-top:3px solid #7b7b3f;border-bottom:3px solid #7b7b3f;
}
.row {display:table-row;}
.cell {
display:table-cell; padding:10px 5px;
vertical-align: top;
border-bottom:1px solid #7b7b3f;
}
.cell:nth-child(odd) {
width:150px;vertical-align: top;
text-align: center; background-color:#faefb8;
border-bottom:1px solid #fff;
}
.findArea {position:relative; margin-left:310px;margin-top:85px;}
#filelist {padding:2px;border:1px solid #ccc; width:300px;height:100px;overflow-y:auto;}
#filelist li:first-child {background-color:#408080;color:#fff;text-align:center;}
.boardFooter {text-align: right; width:10%; min-width:720px;padding:20px;}
.btn {padding: 3px 10px;border:1px solid #ccc;cursor:pointer;}
.btn:hover {background:#000;border-color:#000;color:#fff;font-weight:bold;}
input[type=text] {width:80%;}
input[type=file] {
opacity: 0; width: 85px;position:absolute;
visibility:visible;left:0px;top:-3px;
}
textarea {width:80%;height:150px;}
.fl {float:left;}
.fr {float:right;}
.cl {clear:left;}
.cr {clear:right;}
.cb {clear:both;}
write.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>게시판 글쓰기</title>
<!-- CSS 파일 연결 -->
<link href="style.css" rel="stylesheet" />
<!-- js 파일 연결-->
<script src="https://code.jquery.com/jquery-3.6.1.js"></script>
<script src="board_common.js"></script>
</head>
<body>
<div id="container">
<form name="fn" method="get" enctype="multipart/form-data">
<!-- form태그로 데이터를 넘긴다 -->
<input type="hidden" name="idx" id="idx" value=""/>
<input type="hidden" name="group" id="group" value=""/>
<input type="hidden" name="level" id="level" value=""/>
<input type="hidden" name="step" id="step" value=""/>
<input type="hidden" name="list" id="list" value=""/>
<h3><span>질문</span>게시판</h3>
<ul class="tableBox">
<li class="row">
<div class="cell"><label for="part">상단고정</label></div>
<div class="cell">
<input type="checkbox" name="top" id="top" value="Yes"/>
<label for="top">게시판 상단에 위치시키실 경우 선택하세요</label>
</div>
</li>
<li class="row">
<div class="cell"><label for="header">머릿글</label></div>
<div class="cell">
<select name="header" id="header">
<option value="">== 선택 ==</option>
<option value="학습">학습</option>
<option value="생활">생활</option>
<option value="취업">취업</option>
<option value="고민">고민</option>
<option value="과정">과정</option>
</select>
</div>
</li>
<li class="row">
<div class="cell">
<label for="writer">작성자</label>
</div>
<div class="cell">
<input type="text" name="writer" id="writer">
</div>
</li>
<li class="row">
<div class="cell">
<label for="subject">제목</label>
</div>
<div class="cell">
<input type="text" name="subject" id="subject"
value="Title" />
</div>
</li>
<li class="row">
<div class="cell">
<label for="content">내용</label>
</div>
<div class="cell">
<textarea name="content" id="content"></textarea>
</div>
</li>
<li class="row">
<div class="cell">
<label for="password">비밀번호</label>
</div>
<div class="cell">
<input type="password" name="password" id="password" />
</div>
</li>
<li class="row">
<div class="cell">
<label for="file">파일</label>
</div>
<div class="cell">
<ul id="filelist" class="fl">
<li>파일목록</li>
<li class="fl"></li>
</ul>
<div class="findArea">
<span id="btnFileUpload" class="btn">파일찾기</span>
<input type="file" class="file" name="file" id="file" multiple />
</div>
</div>
</li>
</ul>
<div class="boardFooter cl">
<span class="btn" id="btnReg">저장</span>
<span class="btn" id="btnCan">취소</span>
</div>
</form>
</div>
</body>
</html>

board_common.js
구현 기능
1. js로 파일명, 파일 크기 받기
2. 폼 제출시 공백 부분 안내
3. 취소 클릭시 원래 페이지로 돌아오면서 모든 내용 초기화
$().ready(function(){
//########################################################################
//============ 파일을 선택할 경우 ====================
$("#file").on("change", function() {
console.log("파일선택");//$("#file").on("change", function(){}) 작동 확인
//파일명 추출
var fileInput = document.getElementsByClassName("file");//("file")==>class 이름 주의할 것!!!
for( var i=0; i<fileInput.length; i++ ){
if( fileInput[i].files.length > 0 ){
for( var j = 0; j < fileInput[i].files.length; j++ ){
var fileName=fileInput[i].files[j].name; // 파일명 출력
}
}
}
//end:파일명 추출
var filesize=this.files[0].size;//파일 크기 추출
//작동 확인
console.log("파일명="+fileName);
console.log("파일 사이즈="+filesize);
});//e:$("#file").on("change");
//============ e:파일을 선택할 경우 ====================
//============ 저장을 클릭 한경우 ====================
$("#btnReg").on("click",function() {
console.log("저장 클릭");//$("#btnReg")on("click",function(){}) 동작 확인
//작성 여부 확인
if(fn.header.value=="") {
alert("말머리를 선택해주세요");
fn.header.focus();
return;
}
if(fn.writer.value=="") {
alert("작성자를 입력하세요");
fn.writer.focus();
return;
}
if(fn.subject.value=="") {
alert("제목을 입력하세요");
fn.subject.focus();
return;
}
if(fn.subject.value=="Title") {
alert("제목을 바꿔주세요");
fn.subject.focus();
return;
}
if(fn.content.value=="") {
alert("내용을 입력하세요");
fn.content.focus();
return;
}
if(fn.password.value=="") {
alert("비밀번호를 입력하세요");
fn.password.focus();
return;
}
if(fn.file.value=="") {
alert("파일을 첨부하세요");
fn.file.focus();
return;
}
//end:작성 확인
fn.action ="CW";//servelt과 연결
fn.method="post";// 연결
fn.submit();
});//
//============ e:저장을 클릭한 경우 ====================
//============ 취소를 클릭한 경우 ====================
$("#btnCan").on("click",function() {
console.log("취소 클릭 /r/n 모든 내용을 초기화합니다");
fn.method="get";//get 방식으로 연결
fn.action = "write.jsp";//원래 페이지로 돌아간다
fn.submit();
});//
//============ e:취소를 클릭한 경우 ====================
//########################################################################
});
게시판에 저장을 눌렀을 경우 빈 부분이 있다면 알람을 보낸다.
비밀번호의 경우 입력해도 보이지 않게 처리하였다.




파일을 첨부하였을 경우 파일명과 파일 사이즈를 표시한다

CtrlWrite.java
package pkgStudy;
import java.io.Console;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import javax.servlet.ServletException;
import javax.servlet.annotation.MultipartConfig;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.Part;
//만들던 프로젝트를 수정하여 import한 것이 많다
@WebServlet("/CW")
@MultipartConfig(
maxFileSize=1024*1024*5,//5m
maxRequestSize=1024*1024*50//50m
)
//@MultipartConfig은 post로 출력하기 위해 사용
public class CtrlWrite extends HttpServlet {
private static final long serialVersionUID = 1L;
public CtrlWrite() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//doGet은 현 프로젝트에서는 사용하지 않는다
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=UTF-8");
//한글화
PrintWriter out=response.getWriter();
//out.print를 사용할 수 있게 된다
//=============값이 넘어가는지 확인한다=========
String top=""; String header="";
String writer=""; String subject="";
String content=""; String password="";
//html에서 값 넘겨 받기. name값
//request.getParameter("top")는 JSP에서 넘겨받는 name=top 값.
//만약 request.getParameter("top")이 null이 아니고 공백이 아닐 때==>값이 들어있을 때
//실행하는 것
if(request.getParameter("top")!=null && !"".equals(request.getParameter("top")))
top=request.getParameter("top");
if(request.getParameter("header")!=null && !"".equals(request.getParameter("header")))
header=request.getParameter("header");
if(request.getParameter("writer")!=null && !"".equals(request.getParameter("writer")))
writer=request.getParameter("writer");
if(request.getParameter("subject")!=null && !"".equals(request.getParameter("subject")))
subject=request.getParameter("subject");
if(request.getParameter("content")!=null && !"".equals(request.getParameter("content")))
content=request.getParameter("content");
if(request.getParameter("password")!=null && !"".equals(request.getParameter("password")))
password=request.getParameter("password");
//연결되는지 확인
out.print(top);
out.print(header);
out.print(writer);
out.print(subject);
out.print(content);
out.print(password);
out.print("연결 성공!!");
}
}
폼에 입력한 데이터가 전부 넘어갔음을 알 수 있다.

'2022-코딩 수업 정리' 카테고리의 다른 글
| 게시판 만들기-3 (0) | 2022.10.05 |
|---|---|
| 게시판 만들기-2 (0) | 2022.10.01 |
| JSP, HTML 활용 코드 (0) | 2022.09.26 |
| html 안에서 JSP 코딩 태그 정리 (0) | 2022.09.26 |
| 이클립스 Encoding을 UTF-8로 바꾸기 (0) | 2022.09.26 |