본문 바로가기
자바 풀스택 공부

Day 53. [JSP/Servlet] 첨부파일, 회원기능 구현

by seung_nari 2022. 3. 22.

서버 프로그램 구현 - 개인 프로젝트

회원제 게시판

 

첨부파일, 페이지네이션, 게시판별 카테고리

인증(이메일), 댓글(비동기), 회원기능 구현

 

메세지 처리 페이지

> 로그인 실패 및 성공시 메시지

 

배피 프로그램 처리

Oauth

외부 RestAPI 연동(지도, 좌표)

 

점점 머리에 한계가 온다 이야아아아아아아아아아아앙


utils > FileDownload.java

 

package utils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

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("/download")
public class FileDownloader extends HttpServlet {

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String origin = req.getParameter("origin");
		String uuid = req.getParameter("uuid");
		String path = req.getParameter("path");
		
		String saveDir = "D:\\upload";
		
		File file = new File(new File(saveDir, path), uuid);
		String mime = getServletContext().getMimeType(file.toString());
		if(mime == null) {
			mime = "application/octet-stream";
		}		
		
		String fileName = new String(origin.getBytes("utf-8"), "iso-8859-1"); // utf-8을 iso-8859-1로 재해석한 것
		
		resp.setContentType(mime);
		resp.setHeader("Content-Disposition", "attachment; filename=" + fileName);
		
		FileInputStream fis = new FileInputStream(file);
		OutputStream os = resp.getOutputStream();
		
		int b;
		byte[] bytes = new byte[8192];
		while((b = fis.read(bytes, 0, bytes.length)) != -1) {
			os.write(bytes, 0, b);
		}
		fis.close();
		os.close();
	}
}

 

get.jsp

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html lang="ko">
    <head>
        <%@ include file="../common/head.jsp" %>
    </head>
    <body class="sb-nav-fixed">
        <%@ include file="../common/nav.jsp" %>
        <main class="mt-5 pt-5">
            <div class="container-fluid px-4">
                <h1 class="mt-4">Board</h1>
                <h2>${board.attachs}</h2>
                <div class="card mb-4">
                    <div class="card-body">
                        <form>
						  <div class="mb-3 mt-3">
						    <label for="bno" class="form-label"><i class="fas fa-list-ol"></i> bno</label>
						    <input type="text" class="form-control" id="bno" name="bno" value="${board.bno}" disabled>
						  </div>
						  <div class="mb-3">
						    <label for="title" class="form-label"><i class="fab fa-battle-net"></i> title</label>
						    <input type="text" class="form-control" id="title" name="title" value="${board.title}" disabled>
						  </div>
						  <div class="mb-3">
						    <label for="content" class="form-label"><i class="fab fa-battle-net"></i> content</label>
						    <textarea class="form-control" id="content" name="content" disabled>${board.content}</textarea>
						  </div>
						  <div class="mb-3">
						    <label for="regDate" class="form-label"><i class="fas fa-calendar"></i> regDate</label>
						    <input type="text" class="form-control" id="regDate" name="regDate" value="${board.regDate}" disabled>
						  </div>
						  <div class="mb-3">
						    <label for="writer" class="form-label"><i class="fas fa-feather-alt"></i> writer</label>
						    <input type="text" class="form-control" id="writer" name="writer" value="${board.writer}" disabled>
						  </div>
						  <div class="mb-3">
						    <label for="attach" class="form-label"><i class="fas fa-file-archive"></i> attach</label>
						    <ul class="list-group">
						    <c:forEach items="${board.attachs}" var="attach">
							  <li class="list-group-item list-group-item-info"><i class="fas fa-download"></i> <a href="${pageContext.request.contextPath}/download${attach.params}">${attach.origin}</a></li>
						    </c:forEach>
							</ul>
						  </div>
						  <a href="list${cri.params2}" class="btn btn-outline-secondary">list</a>
						  <c:if test="${not empty member && member.id == board.writer}">
						  <a href="modify${cri.params2}&bno=${board.bno}" class="btn btn-outline-warning">modify</a>
						  <a href="remove${cri.params2}&bno=${board.bno}" class="btn btn-outline-danger" onclick="return confirm('삭제하시겠습니까?')">remove</a>
						  </c:if>
						</form>
                    </div>
                </div>
            </div>
        </main>
        <%@ include file="../common/footer.jsp" %>
    </body>
</html>

 

domain > Board.java

 

package domain;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data @NoArgsConstructor @AllArgsConstructor
public class Board {
	// int(기본형), Integer(참조형) : null 처리 가능여부 
	private Long bno ; // PK
	private String title;
	private String content;
	private int hitcount; // 0
	private String regDate;
	private int category;
	
	private String writer; // FK
	// 아이디, 조회수, 작성시각
	
	private List<Attach> attachs = new ArrayList<>();
	
	public Board(String title, String content, String writer) {
		this.title = title;
		this.content = content;
		this.writer = writer;
	}
	
	public Board(String title, String content, String writer, int category) {
		this.title = title;
		this.content = content;
		this.writer = writer;
		this.category = category;
	}

	public Board(Long bno, String title, String content, int category) {
		super();
		this.bno = bno;
		this.title = title;
		this.content = content;
		this.category = category;
	}

	public Board(Long bno, String title, String content, int hitcount, String regDate, int category, String writer) {
		super();
		this.bno = bno;
		this.title = title;
		this.content = content;
		this.hitcount = hitcount;
		this.regDate = regDate;
		this.category = category;
		this.writer = writer;
	}
}

 

domain > Attach.java

 

package domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data @NoArgsConstructor @AllArgsConstructor
public class Attach {
	private String uuid;
	private String origin;
	private String path;
	private boolean image;
	private int ord;
	private Long bno;
	
	public String getParams() {
		return "?uuid=" + uuid + "&path=" + path + "&origin=" + origin;
	}
}

 

AttachDao.java

 

package dao;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.internal.compiler.batch.Main;

import domain.Attach;
import domain.Board;
import domain.Criteria;
import utils.DBConn;

public class AttachDao {
	private static AttachDao attachDao = new AttachDao();
	public static AttachDao getInstance() {
		return attachDao;
	}
	private AttachDao() {
	}
	
	public List<Attach> list(Long bno) {
		List<Attach> list = new ArrayList<>();
		try {
			Connection conn = DBConn.getConnection();
			
			// 문장 생성
			String sql = "SELECT /*+ INDEX(TBL_ATTACH IDX_ATTACH_UUID_BNO) */ * FROM TBL_ATTACH WHERE BNO = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setLong(1,  bno);
			// 결과집합 생성
			ResultSet rs = pstmt.executeQuery();
			
			// 결과집합 순회 후 데이터 바인딩
			while(rs.next()) {
				int idx = 1;
				Attach attach = new Attach(
						rs.getString(idx++),
						rs.getString(idx++),
						rs.getString(idx++),
						rs.getBoolean(idx++),
						rs.getInt(idx++),
						bno);
				list.add(attach);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return list;
	}
	
	public void insert(Attach attach) {
		try {
			Connection conn = DBConn.getConnection();
			
			// 문장 생성
			String sql = "INSERT INTO TBL_Attach "
					+ "VALUES (?, ?, ?, ?, ?, ?)";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			// 파라미터 바인딩
			int idx = 1;
			pstmt.setString(idx++, attach.getUuid());
			pstmt.setString(idx++, attach.getOrigin());
			pstmt.setString(idx++, attach.getPath());
			pstmt.setBoolean(idx++, attach.isImage());
			pstmt.setInt(idx++, attach.getOrd());
			pstmt.setLong(idx++, attach.getBno());
			
			// 문장 실행(반영)
			pstmt.executeUpdate();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void modify(Board board) {
		try {
			Connection conn = DBConn.getConnection();
			
			// 문장 생성
			String sql = "UPDATE TBL_BOARD SET\r\n" + 
					"TITLE = ?,\r\n" + 
					"CONTENT = ?,\r\n" + 
					"REGDATE = SYSDATE\r\n" + 
					"WHERE BNO = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			// 파라미터 바인딩
			pstmt.setString(1, board.getTitle());
			pstmt.setString(2, board.getContent());
			pstmt.setLong(3, board.getBno());
			
			// 문장 실행(반영)
			pstmt.executeUpdate();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	public void remove(Long bno) {
		try {
			Connection conn = DBConn.getConnection();
			
			// 문장 생성
			String sql = "DELETE TBL_BOARD\r\n" + 
					"WHERE BNO = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			// 파라미터 바인딩
			pstmt.setLong(1, bno);
			
			// 문장 실행(반영)
			pstmt.executeUpdate();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	public Board get(Long bno) {
		Board board = null;
		try {
			Connection conn = DBConn.getConnection();
			
			String sql = "UPDATE TBL_BOARD SET\r\n" + 
					"HITCOUNT = HITCOUNT + 1\r\n" + 
					"WHERE BNO = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			
			// 파라미터 바인딩
			pstmt.setLong(1, bno);
			
			// 문장 실행(반영)
			pstmt.executeUpdate();
			
			// 문장 생성
			sql = "SELECT BNO, TITLE, CONTENT, HITCOUNT, \r\n" + 
					"CASE\r\n" + 
					"    WHEN SYSDATE - REGDATE > 1 THEN TO_CHAR(REGDATE, 'YY/MM/DD')\r\n" + 
					"    ELSE TO_CHAR(REGDATE, 'HH24:MI:SS')\r\n" + 
					"END REGDATE,\r\n" + 
					"CATEGORY, WRITER FROM TBL_BOARD WHERE BNO = ?";
			pstmt = conn.prepareStatement(sql);
			pstmt.setLong(1, bno);
			
			// 결과집합 생성
			ResultSet rs = pstmt.executeQuery();
			
			// 결과집합 순회 후 데이터 바인딩
			while(rs.next()) {
				int idx = 1;
				board = new Board(rs.getLong(idx++), rs.getString(idx++), rs.getString(idx++), 
						rs.getInt(idx++), rs.getString(idx++), rs.getInt(idx++),rs.getString(idx++));
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return board;
	}
	
	public int count(Criteria cri) {
		int count = 0;
		try {
			Connection conn = DBConn.getConnection();
			
			// 문장 생성
			String sql = "SELECT COUNT(BNO) FROM TBL_BOARD WHERE CATEGORY = ?";
			PreparedStatement pstmt = conn.prepareStatement(sql);
			pstmt.setInt(1, cri.getCategory());
			
			// 결과집합 생성
			ResultSet rs = pstmt.executeQuery();
			
			// 결과집합 순회 후 데이터 바인딩
			if(rs.next()) {
				count = rs.getInt(1 );
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return count;
	}
}

 

controller.board > Register.java

 

package controller.board;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.UUID;

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 domain.Attach;
import domain.Board;
import domain.Criteria;
import domain.Member;
import javafx.scene.input.Mnemonic;
import service.BoardService;
import service.MemberService;

@WebServlet("/board/register")
public class Register extends HttpServlet{
	private BoardService boardService = BoardService.getInstance();
	private MemberService memberService = MemberService.getInstance();
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 세션 고정값 지정
		req.getSession().setAttribute("member", memberService.login(new Member("javaman", "5678", null)));

		if(req.getSession().getAttribute("member") == null) {
			resp.sendRedirect(req.getContextPath() + "/member/login");
			return;
		}
			
		Criteria criteria = new Criteria();
		if(req.getParameter("pageNum") != null) {
			criteria.setPageNum(Integer.parseInt(req.getParameter("pageNum")));
		}
		if(req.getParameter("amount") != null) {
			criteria.setAmount(Integer.parseInt(req.getParameter("amount")));
		}
		if(req.getParameter("category") != null) {
			criteria.setCategory(Integer.parseInt(req.getParameter("category")));
		}
		req.setAttribute("cri", criteria);
			
		req.getRequestDispatcher("/WEB-INF/jsp/board/register.jsp").forward(req, resp);
		
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Criteria criteria = new Criteria();
		Board board = upload(req, criteria);
		System.out.println(board);
		boardService.register(board);
		resp.sendRedirect("list" + criteria.getParams2());
		
	}
	
	private Board upload(HttpServletRequest req, Criteria cri) {
		Board board = new Board();
		String saveDir = "D:\\upload";
		int size = 10 * 1024 * 1024;
		
		File currentDir = new File(saveDir);
		DiskFileItemFactory factory = new DiskFileItemFactory();
		factory.setRepository(currentDir);
		factory.setSizeThreshold(size);
		
		ServletFileUpload upload = new ServletFileUpload(factory);
		try {
			List<FileItem> items = upload.parseRequest(req);
			for(FileItem fi : items) {
				if(fi.isFormField()) {
					if(fi.getFieldName().equals("title")) {
						board.setTitle(fi.getString("utf-8"));
					}
					if(fi.getFieldName().equals("content")) {
						board.setContent(fi.getString("utf-8"));
					}
					if(fi.getFieldName().equals("writer")) {
						board.setWriter(fi.getString("utf-8"));
					}
					if(fi.getFieldName().equals("amount")) {
						cri.setAmount(Integer.parseInt(fi.getString("utf-8")));
					}
					if(fi.getFieldName().equals("category")) {
						board.setCategory(cri.getCategory());;
					}
				}
				else {
					if(fi.getSize() == 0) {
						continue;
					}

					String origin = fi.getName();
					int idxDot = origin.lastIndexOf(".");
					String ext = "";
					
					if(idxDot != -1) {
						ext = origin.substring(idxDot);
					}
					
					UUID uuid = UUID.randomUUID();
					String name = uuid + ext;
					
					File upPath = new File(currentDir + "\\" + getTodayStr());
					if(!upPath.exists()) {
						upPath.mkdirs();
					}
					
					fi.write(new File(upPath, name));
					
					Attach attach = new Attach(name, origin, getTodayStr(), fi.getContentType().contains("image"), 1, null);
					board.getAttachs().add(attach);
				}
			}
			
		} catch (Exception e){
			// TODO: handle exception
			e.printStackTrace();
		}
		
		return board;
	}
	
	private String getTodayStr() {
		return new SimpleDateFormat("yyyy/MM/dd").format(System.currentTimeMillis());
	}
}

 

register.jsp

 

						  <input type = "hidden" name = "amount" value = "${cri.amount}">
						  <input type = "hidden" name = "category" value = "${cri.category}">
						  <input type = "hidden" name = "pageNum" value = "${cri.pageNum}">
						  <a href="list" class="btn btn-outline-secondary">list</a>
						  <button class="btn btn-outline-primary">register</button>

 

Modify.java

 

package controller.board;

import java.io.IOException;

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 domain.Board;
import domain.Criteria;
import domain.Member;
import service.BoardService;

@WebServlet("/board/modify")
public class Modify extends HttpServlet{
	private BoardService boardService = BoardService.getInstance();
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		Long bno = Long.parseLong(req.getParameter("bno"));
		Member member = (Member) req.getSession().getAttribute("member");
		if(member == null || !member.getId().equals(boardService.get(bno).getWriter())) {
			resp.sendRedirect(req.getContextPath() + "/board/list");
			return;
		}
		
		Criteria criteria = new Criteria();
		if(req.getParameter("pageNum") != null) {
			criteria.setPageNum(Integer.parseInt(req.getParameter("pageNum")));
		}
		if(req.getParameter("amount") != null) {
			criteria.setAmount(Integer.parseInt(req.getParameter("amount")));
		}
		if(req.getParameter("category") != null) {
			criteria.setCategory(Integer.parseInt(req.getParameter("category")));
		}
		req.setAttribute("cri", criteria);
		
		req.setAttribute("board", boardService.get(bno));
		req.getRequestDispatcher("/WEB-INF/jsp/board/modify.jsp").forward(req, resp);
	}
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		req.setCharacterEncoding("utf-8");
		String title = req.getParameter("title");
		String content = req.getParameter("content");
		String bno = req.getParameter("bno");
		
		Criteria criteria = new Criteria();
		criteria.setPageNum(Integer.parseInt(req.getParameter("pageNum")));
		criteria.setAmount(Integer.parseInt(req.getParameter("amount")));
		criteria.setCategory(Integer.parseInt(req.getParameter("category")));
		
		Board board = new Board(Long.parseLong(bno), title, content, criteria.getCategory());
		boardService.modify(board);
		resp.sendRedirect("list" + criteria.getParams2());
	}
}

 

SQL

 

-- TBL_ATTACH 첨부파일
-- 물리적 파일이름 문자50글자, 원본 파일 이름 문자 500, 경로, 글번호 숫자, 이미지 여부 불린(문자) 1
DROP TABLE TBL_ATTACH;
CREATE TABLE TBL_ATTACH(
    UUID VARCHAR2(50) CONSTRAINT PK_ATTACH PRIMARY KEY,
    ORIGIN VARCHAR2(500) NOT NULL,
    PATH CHAR(10),
    IMAGE CHAR(1) DEFAULT '0',
    ORD NUMBER DEFAULT 1,
    BNO CONSTRAINT FK_ATTACH_BNO REFERENCES TBL_BOARD(BNO)
);

CREATE UNIQUE INDEX IDX_ATTACH_UUID_BNO ON TBL_ATTACH(UUID, BNO DESC);
-- 목록
SELECT /*+ INDEX(TBL_ATTACH IDX_ATTACH_UUID_BNO) */ * FROM TBL_ATTACH WHERE BNO = 190;

-- 상제
SELECT * FROM TBL_ATTACH WHERE UUID = '1';

SELECT * FROM TBL_ATTACH;

댓글