- 작업순서
- 데이터 베이스(테이블, 테스트 데이터)
- VO 클래스
- DAO 클래스
- Service 클래스
- Controller 클래스
- view page
- sql
DROP TABLE BOARD_TBL;
CREATE TABLE BOARD_TBL(
BNO NUMBER(10) PRIMARY KEY,
TITLE VARCHAR2(500) NOT NULL,
CONTENT VARCHAR2(4000) NOT NULL,
WRITER VARCHAR2(100) NOT NULL,
imageFileName VARCHAR2(100),
WRITEDATE DATE DEFAULT SYSDATE
);
INSERT INTO BOARD_TBL(BNO, TITLE, CONTENT, WRITER)
VALUES (1, '제목임1', '내용임1', '관리자1');
INSERT INTO BOARD_TBL(BNO, TITLE, CONTENT, WRITER)
VALUES (2, '제목임2', '내용임2', '관리자2');
INSERT INTO BOARD_TBL(BNO, TITLE, CONTENT, WRITER)
VALUES (3, '제목임3', '내용임3', '관리자3');
INSERT INTO BOARD_TBL(BNO, TITLE, CONTENT, WRITER)
VALUES (4, '제목임4', '내용임4', '관리자4');
COMMIT;
SELECT * FROM BOARD_TBL;
-- SELECT MAX(BNO)+1 AS baordNo FROM BOARD_TBL;
maven 프로젝트로 변경
- pom.xml
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-dbcp</artifactId>
<version>10.1.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>
</dependencies>
- package 트리
- common 패키지 ConnectionUtil 클래스, EncodingFilter 필터 생성
- EncodingFilter
package com.common;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpFilter;
@WebFilter("/*")
public class EncodingFilter extends HttpFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
chain.doFilter(request, response);
}
}
- ConnectionUtil
package com.common;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;
public class ConnectionUtil {
private static final String RESOURCE = "java:/comp/env";
private static final String RESOURCE_NAME = "jdbc/oracle";
public static DataSource getDatasource() {
DataSource dataSource = null;
try {
Context ctx = new InitialContext();
Context envCtx = (Context) ctx.lookup(RESOURCE);
dataSource = (DataSource) envCtx.lookup(RESOURCE_NAME);
} catch (NamingException e) {
e.printStackTrace();
}
return dataSource;
}
}
- FileDownload 서블릿
package com.common;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/fileDownload")
public class FileDownload extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String fileRepo = "c:/file_repo";
String bno = request.getParameter("bno");
String fileName = request.getParameter("imageFileName");
File downloadFile = new File(fileRepo + "/" + bno, fileName);
fileName = URLEncoder.encode(fileName, "utf-8");
response.setHeader("Cache-Control", "no-cache");
response.addHeader("Content-disposition", "attachment; fileName=" + URLEncoder.encode(fileName, "utf-8"));
try (
OutputStream out = response.getOutputStream();
InputStream in = new FileInputStream(downloadFile);
){
byte[] buffer = new byte[1024*8];
int count = 0;
while ((count = in.read(buffer)) != -1) {
out.write(buffer, 0, count);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
- domain 패키지에 BoardVO 생성
- BoardVO
package com.domain;
import java.util.Date;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BoardVO {
private int bno;
private String title;
private String content;
private String writer;
private String imageFileName;
private Date writeDate;
}
- controller 패키지 BoardController 서블릿 생성
- BoardController
package com.controller;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
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 org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.apache.commons.io.FileUtils;
import com.dao.BoardDao;
import com.domain.BoardVO;
import com.service.BoardService;
@WebServlet("/board/*")
public class BoardController extends HttpServlet {
private BoardService service;
@Override
public void init() throws ServletException {
BoardDao dao = new BoardDao();
service = new BoardService(dao);
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doHandle(request, response);
}
private void doHandle(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getPathInfo();
String contextPath = request.getContextPath();
final String PREFIX = "/WEB-INF/views/board/";
final String SUFFIX = ".jsp";
RequestDispatcher rd = null;
String nextPage = null;
if(pathInfo == null || pathInfo.equals("/") || pathInfo.equals("/list")) { // 글 목록
List<BoardVO> boardList = service.boardList();
request.setAttribute("list", boardList);
nextPage = "list";
} else if(pathInfo.equals("/detail")) { // 글 상세
String paramBno = request.getParameter("bno");
int bno = Integer.parseInt(paramBno);
BoardVO board = service.findBoard(bno);
request.setAttribute("board", board);
nextPage = "detail";
} else if(pathInfo.equals("/writeForm")) { // 글 쓰기 폼
nextPage = "writeForm";
} else if(pathInfo.equals("/write")) { // 글 쓰기 처리
Map<String, String> req = getMultipartRequest(request);
String imageFileName = req.get("imageFileName");
BoardVO vo = BoardVO.builder()
.title(req.get("title"))
.content(req.get("content"))
.writer(req.get("writer"))
.imageFileName(req.get("imageFileName"))
.build();
int boardNo = service.addBoard(vo);
// 이미지 파일을 첨부한 경우
if(imageFileName != null && imageFileName.length() > 0) {
File srcFile = new File("c:/file_repo/temp", imageFileName);
File destFile = new File("c:/file_repo/" + boardNo);
destFile.mkdirs();
FileUtils.moveFileToDirectory(srcFile, destFile, false);
}
response.sendRedirect(contextPath + "/board");
return;
} else if(pathInfo.equals("/modBoard")) { // 글 수정 처리
Map<String, String> req = getMultipartRequest(request);
String paramBno = req.get("bno");
int bno = Integer.parseInt(paramBno);
String title = req.get("title");
String content = req.get("content");
String imageFileName = req.get("imageFileName");
BoardVO vo = BoardVO.builder()
.bno(bno)
.title(title)
.content(content)
.imageFileName(imageFileName).build();
service.modBoard(vo);
if(imageFileName != null) { // 이미지 파일이 있을 때
String originFileName = req.get("originFileName");
// 새로운 이미지 업로드
File srcFile = new File("c:/file_repo/temp", imageFileName);
File destFile = new File("c:/file_repo/" + bno);
destFile.mkdirs();
FileUtils.moveFileToDirectory(srcFile, destFile, false);
// 기존 이미지 삭제
if(originFileName != null) {
File oldFile = new File("c:/file_repo/" + bno + "/" + originFileName);
oldFile.delete();
}
}
response.sendRedirect(contextPath + "/board");
return;
} else if(pathInfo.equals("/removeBoard")) { // 삭제처리
Map<String, String> req = getMultipartRequest(request);
String paramBno = req.get("bno");
int bno = Integer.parseInt(paramBno);
service.removeBoard(bno);
File targetDir = new File("c:/file_repo/" + bno);
if(targetDir.exists()) { // 대상 폴더가 존재한다면..
FileUtils.deleteDirectory(targetDir);
}
response.sendRedirect(contextPath + "/board");
return;
}
else {
System.out.println("없는 페이지");
}
rd = request.getRequestDispatcher(PREFIX + nextPage + SUFFIX);
rd.forward(request, response);
}
private Map<String, String> getMultipartRequest(HttpServletRequest request) {
Map<String, String> boardMap = new HashMap<>();
File currentDirPath = new File("c:/file_repo/temp");
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload repository = new ServletFileUpload(factory);
repository.setFileSizeMax(1024 * 1024 * 10);
try {
List<FileItem> items = repository.parseRequest(request);
for(FileItem item : items) {
if(item.isFormField()) { // 파일이 아니면
boardMap.put(item.getFieldName(), item.getString("utf-8"));
} else { // 파일이면
if(item.getSize() > 0) {
String fileName = item.getName(); // 파일이름
boardMap.put(item.getFieldName(), fileName);
File uploadFile = new File(currentDirPath, fileName);
item.write(uploadFile);
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return boardMap;
}
}
- service 패키지 BoardService 생성
- BoardService
package com.service;
import java.util.List;
import com.dao.BoardDao;
import com.domain.BoardVO;
import lombok.AllArgsConstructor;
@AllArgsConstructor
public class BoardService {
private BoardDao dao;
public List<BoardVO> boardList() {
return dao.selectAll();
}
public BoardVO findBoard(int bno) {
return dao.selectOne(bno);
}
public int addBoard(BoardVO vo) {
return dao.insertBoard(vo);
}
public void modBoard(BoardVO vo) {
dao.updateBoard(vo);
}
public void removeBoard(int bno) {
dao.deleteBoard(bno);
}
}
- dao 패키지 BoardDao 생성
- BoardDao
package com.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;
import javax.sql.DataSource;
import com.common.ConnectionUtil;
import com.domain.BoardVO;
public class BoardDao {
private DataSource dataSource;
public BoardDao() {
dataSource = ConnectionUtil.getDatasource();
}
// 글 목록
public List<BoardVO> selectAll() {
List<BoardVO> list = new ArrayList<>();
String query = "SELECT * FROM board_tbl ORDER BY bno DESC";
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
){
while (rs.next()) {
BoardVO vo = BoardVO.builder()
.bno(rs.getInt("bno"))
.title(rs.getString("title"))
.content(rs.getString("content"))
.writer(rs.getString("writer"))
.imageFileName(rs.getString("imageFileName"))
.writeDate(rs.getDate("writeDate")).build();
list.add(vo);
}
} catch (Exception e) {
e.printStackTrace();
}
return list;
}
// 글 상세
public BoardVO selectOne(int bno) {
BoardVO vo = null;
String query = "SELECT * FROM board_tbl WHERE bno=?";
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
){
pstmt.setInt(1, bno);
try (ResultSet rs = pstmt.executeQuery();){
if(rs.next()) {
vo = BoardVO.builder()
.bno(rs.getInt("bno"))
.title(rs.getString("title"))
.content(rs.getString("content"))
.writer(rs.getString("writer"))
.imageFileName(rs.getString("imageFileName"))
.writeDate(rs.getDate("writeDate")).build();
}
}
} catch (Exception e) {
e.printStackTrace();
}
return vo;
}
// 새로운 글번호 생성
public int getNewBno() {
int boardNo = 0;
String query = "SELECT MAX(bno)+1 AS boardNo FROM board_tbl";
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
ResultSet rs = pstmt.executeQuery();
){
if(rs.next()) {
boardNo = rs.getInt("boardNo");
}
} catch (Exception e) {
e.printStackTrace();
}
return boardNo;
}
// 글 쓰기
public int insertBoard(BoardVO vo) {
String query = "INSERT INTO board_tbl(bno, title, content, writer, imageFileName) VALUES(?, ?, ?, ?, ?)";
int boardNo = getNewBno();
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
){
pstmt.setInt(1, boardNo);
pstmt.setString(2, vo.getTitle());
pstmt.setString(3, vo.getContent());
pstmt.setString(4, vo.getWriter());
pstmt.setString(5, vo.getImageFileName());
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
return boardNo;
}
// 글 수정
public void updateBoard(BoardVO vo) {
String imageFileName = vo.getImageFileName();
int bno = vo.getBno();
String query = "UPDATE board_tbl SET title=?, content=?";
if(imageFileName != null) { // 이미지 파일이 있을 때
query += ", imageFileName=? where bno=?";
} else { // 이미지 파일이 없을 때
query += " where bno=?";
}
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
){
pstmt.setString(1, vo.getTitle());
pstmt.setString(2, vo.getContent());
if(imageFileName != null) { // 이미지 파일이 있을 때
pstmt.setString(3, imageFileName);
pstmt.setInt(4, bno);
} else { // 이미지 파일이 없을 때
pstmt.setInt(3, bno);
}
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
// 삭제 처리
public void deleteBoard(int bno) {
String query = "delete from board_tbl where bno=?";
try (
Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(query);
){
pstmt.setInt(1, bno);
pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
}
}
}
- jsp 파일 트리
- webapp / WEB-INF / views / board / list.jsp, detail.jsp
- list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<h1>게시물 목록</h1>
<div class="container my-3">
<form id="listForm">
<table class="table">
<tr>
<th>번호</th>
<th>제목</th>
<th>내용</th>
<th>작성자</th>
<th>파일명</th>
<th>작성일</th>
</tr>
<c:forEach items="${list }" var="b">
<tr>
<td>${b.bno}</td>
<td><a href="${b.bno}" class="title">${b.title}</a></td>
<td>${b.content}</td>
<td>${b.writer}</td>
<td>${b.imageFileName }</td>
<td>${b.writeDate }</td>
</tr>
</c:forEach>
</table>
</form>
<a href="${contextPath}/board/writeForm" class="btn btn-primary">글쓰기로</a>
</div>
<%@ include file="../layout/footer.jsp"%>
<script>
$(function() {
let listForm = $('#listForm');
$('.title').on('click', function(e){
e.preventDefault();
// let bnoData = "<input type='hidden' name='bno' value='"+$(this).data('bno')+"'/>";
let bnoData = "<input type='hidden' name='bno' value='"+$(this).attr('href')+"'/>";
listForm.append(bnoData)
.attr('action', '${contextPath}/board/detail')
.submit();
});
});
</script>
- detail.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<div class="jumbotron my-3">
<h1>게시글조회</h1>
</div>
<form id="viewForm" enctype="multipart/form-data">
<table class="table">
<tr>
<th>글번호</th>
<td>${board.bno }
<input type="hidden" name="bno" value="${board.bno}">
</td>
<th>조회수</th>
<td>000</td>
</tr>
<tr>
<th>작성자</th>
<td>${board.writer}</td>
<th>조회수</th>
<td>${board.writeDate }</td>
</tr>
<tr>
<th>제목</th>
<td colspan="3">
<input type="text" name="title" class="form-control" value="${board.title }" readonly="readonly">
</td>
</tr>
<tr>
<th>내용</th>
<td colspan="3"><textarea rows="10" name="content" class="form-control" readonly="readonly">${board.content}</textarea></td>
</tr>
<tr>
<th>첨부이미지</th>
<td colspan="3">
<input type="file" name="imageFileName" class="form-control viewMode">
<div class="my-2">
<c:if test="${not empty board.imageFileName }">
<input type="hidden" name="originFileName" value="${board.imageFileName}">
<div class="preview">
<img class="originImg" src="${contextPath }/fileDownload?bno=${board.bno}&imageFileName=${board.imageFileName}" width="300px">
</div>
</c:if>
<c:if test="${empty board.imageFileName }">
<div class="preview">
<p>등록된 이미지 없음</p>
</div>
</c:if>
</div>
</td>
</tr>
<tr>
<td colspan="4">
<button type="button" class="btn btn-info toModForm">수정하기</button>
<button type="button" class="btn btn-danger remove">삭제</button>
<button type="button" class="btn btn-secondary toList">목록</button>
</td>
</tr>
<tr class="viewMode">
<td colspan="4">
<button type="button" class="btn btn-info modify">수정</button>
<button type="button" class="btn btn-danger backViewMode">취소</button>
</td>
</tr>
</table>
</form>
</div>
<%@ include file="../layout/footer.jsp"%>
<script>
$(function() {
$('.viewMode').hide(); // 파일폼 숨김 / 수정, 취소 버튼 숨김
let viewForm = $('#viewForm');
let titleObj = $('input[name="title"]');
let contentObj = $('textarea[name="content"]');
let imageFile = "${board.imageFileName}";
let pTag = $('.preview p').html;
let originImg = $('.originImg').clone();
let titleVal = titleObj.val();
let contentVal = contentObj.val();
$('.toModForm').on('click', function() {
$('input[name="title"], textarea[name="content"]').attr("readonly", false);
$('.viewMode').show(); // 파일폼 나타내기
$(this).closest('tr').hide();
});
// 뷰모드
$('.backViewMode').on('click', function() {
$('input[name="title"], textarea[name="content"]').attr("readonly", true);
$('.viewMode').hide(); // 파일폼 나타내기
$(this).closest('tr').prev().show();
$('.preview').html(originImg); // 수정전 이미지 복원
$('input[type="file"]').val(''); // 파일폼 초기화
titleObj.val(titleVal); // 수정전 제목 복원
contentObj.val(contentVal); // 수정전 내용 복원
if(imageFile == '' || imageFile == null) {
$('.preview').html(pTag);
}
});
// 목록으로
$('.toList').on('click', function() {
viewForm.attr({
'action' : '${contextPath}/board',
'method' : 'get'
}).empty().submit(); // empty() 파라미터 정보 삭제
});
// 수정 처리
$('.modify').on('click', function() {
viewForm.attr({
'action' : '${contextPath}/board/modBoard',
'method' : 'post'
}).submit();
});
// 삭제 처리
$('.remove').on('click', function() {
viewForm.attr({
'action' : '${contextPath}/board/removeBoard',
'method' : 'post'
}).submit();
});
$('input[type="file"]').on('change', function(){
if(this.files[0]) {
let reader = new FileReader(); // 파일읽기 객체
reader.onload = function(e) { // 파일을 읽으면 이벤트 발생
let value = e.target.result;
if(value.startsWith("data:image/")) {
let imgTag = "<img src='"+value+"' width='200px'>";
$('.preview').html(imgTag);
} else { // 이미지 파일이 아닌 경우
alert('이미지 파일만 등록됩니다.');
$('input[name="imageFileName"]').val('');
$('.preview').html('');
}
}
reader.readAsDataURL(this.files[0]); // 파일 읽기 메소드 호출
}
});
});
</script>
- writeForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ include file="../layout/header.jsp"%>
<div class="container">
<div class="jumbotron">
<h1>글 작성</h1>
</div>
<form action="${contextPath}/board/write" method="post" enctype="multipart/form-data">
<div class="form-group">
제목 : <input type="text" class="form-control" name="title">
</div>
<div class="form-group">
내용 : <textarea rows="10" class="form-control" name="content"></textarea>
</div>
<div class="form-group">
작성자 : <input type="text" class="form-control" name="writer">
</div>
<div class="form-group">
첨부파일 : <input type="file" class="form-control" name="imageFileName">
</div>
<button class="btn btn-primary">등록</button>
</form>
<div class="preview"></div>
</div>
<%@ include file="../layout/footer.jsp"%>
<script>
$(function(){
$('input[type="file"]').on('change', function(){
if(this.files[0]) {
let reader = new FileReader(); // 파일읽기 객체
reader.onload = function(e) { // 파일을 읽으면 이벤트 발생
let value = e.target.result;
if(value.startsWith("data:image/")) {
let imgTag = "<img src='"+value+"' width='200px'>";
$('.preview').html(imgTag);
} else { // 이미지 파일이 아닌 경우
alert('이미지 파일만 등록됩니다.');
$('input[name="imageFileName"]').val('');
$('.preview').html('');
}
}
reader.readAsDataURL(this.files[0]); // 파일 읽기 메소드 호출
}
});
});
</script>
- webapp / WEB-INF / views / layout / header.jsp, footer.jsp
- header.jsp
부트스트랩4 사용
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<c:set var="contextPath" value="${pageContext.request.contextPath }" />
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.1/jquery.min.js" integrity="sha512-aVKKRRi/Q/YV+4mjoKBsE4x3H+BkegoM/em46NNlCqNTmUYADjBbeNefNxYV7giUp0VxICtqdrbqU7iVaeZNXA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<nav class="navbar navbar-expand-sm bg-dark navbar-dark">
<!-- Links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" href="#">Link 1</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link 2</a>
</li>
</ul>
</nav>
- footer.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<div class="jumbotron">
푸터영역
</div>
</body>
</html>
실행
- 글쓰기
- 이미지 업로드
이미지 업로드하면 파일 업로드 경로에 게시글 번호와 같은 폴더가 생기고
그 폴더안에 이미지가 들어감
- 등록된 상태
- 게시글 조회
조회시 제목 내용이 readonly로 바뀌었고 첨부 버튼은 숨겨짐
- 수정하기
readonly가 해제 되고 첨부 버튼이 나타남
기존 조회에 있던 |수정하기|삭제|목록| 버튼이 숨겨지고,
|수정|취소| 버튼이 보여짐
- 이미지 바꾸기
이미지를 다른 이미지로 바꾸고 수정 버튼을 눌러서 적용하면
기존 이미지는 삭제되고 새로운 파일이 업로드됨
- 삭제하기
삭제 버튼 누르면 글이 삭제된다
파일 경로로 가면 폴더도 삭제돼있음
'학습 > JSP' 카테고리의 다른 글
32. Ajax CRUD(로그인 중복 체크(간단) / json 연습) (0) | 2022.12.13 |
---|---|
31. 파일 업로드(메소드 분리와 js파일 외부로 빼기)와 회원가입 & 로그인 & 비밀번호 암호화 (0) | 2022.12.09 |
29. 파일 업로드 (0) | 2022.11.30 |
28. 게시판(기본) (0) | 2022.11.25 |
27. JSTL - Core 태그 라이브러리 사용(2) (0) | 2022.11.24 |
댓글