SMTP :

Simple Mail Transfer Protocol의 약자.

인터넷을 통해 이메일 메시지를 보내고 받는 데 사용되는 통신 프로토콜

 

 

 

이메일 보내기 기능 구현

 

POP 서버명 : pop.naver.com

SMTP 서버명 : smtp.naver.com

POP 포트 : ___, 보안연결(SSL) 필요

SMTP 포트 : ___, 보안 연결(SSL) 필요

된다!

 

MailForm.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>MUSTHAVE 메일 템플릿</h2>

	<table border="1" width="100%">
		<tr>
			<td width="50">내용</td>
			<td>__CONTENT__</td>
		</tr>
		<tr>
			<td>이미지</td>
			<td><img
				src="https://github.com/goldenrabbit2020/musthave_jsp/blob/main/GOLDEN-RABBIT_LOGO_150.png?raw=true"
				alt="골든래빗"></td>
		</tr>
	</table>
</body>
</html>

 

EmailSendMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>이메일 전송하기</h2>
	<form method="post" action="SendProcess.jsp">
		<table border="1">
			<tr>
				<td>
				보내는 사람 : <input type="text" name="form" value="" />
				</td>
			</tr>

			<tr>
				<td>
				받는 사람 : <input type="text" name="to" value="" />
				</td>
			</tr>

			<tr>
				<td>
				제목 : <input type="text" name="subject" size="50" value="" />
				</td>
			</tr>

			<tr>
				<td>
				형식 : 
				 <input type="radio" name="format" value="text" checked/>Text
				 <input type="radio" name="format" value="html"/>HTML
				</td>
			</tr>

			<tr>
				<td>
				<textarea name="content" cols="60" rows="10"></textarea>
				</td>
			</tr>

			<tr>
				<td>
				<button type="submit">전송하기</button>
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

 

NaverSMTP.java

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>이메일 전송하기</h2>
	<form method="post" action="SendProcess.jsp">
		<table border="1">
			<tr>
				<td>
				보내는 사람 : <input type="text" name="form" value="" />
				</td>
			</tr>

			<tr>
				<td>
				받는 사람 : <input type="text" name="to" value="" />
				</td>
			</tr>

			<tr>
				<td>
				제목 : <input type="text" name="subject" size="50" value="" />
				</td>
			</tr>

			<tr>
				<td>
				형식 : 
				 <input type="radio" name="format" value="text" checked/>Text
				 <input type="radio" name="format" value="html"/>HTML
				</td>
			</tr>

			<tr>
				<td>
				<textarea name="content" cols="60" rows="10"></textarea>
				</td>
			</tr>

			<tr>
				<td>
				<button type="submit">전송하기</button>
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

 

 

 

Ajax 통신

 

스크립트에서 서버에 요청

 

(1번) 클라이언트가 서버로 요청, 페이지 이동 발생, 처리

페이지를 띄울 때 이미지를 처리하는 과정(2번)에서 이미지가 크다면 시간이 좀 걸리겠지

그럼 다음 3번을 실행하기 전 2번이 실행되는 시간 동안 화면 비동기 처리

 

jsp 싱글스레드 구성으로 한번에 하나의 일만 처리 가능

비동기처리가 가능하게 만드는 ajax 통신

 

기본형식)

$.ajax({
	url : './PopupCookie.jsp',
	type : 'get',
	data : {inactiveToday : chkVal}, // 자바에선 객체, 비동기 통신방식에서는 제이슨 형식 
	dataType : "text",
	success : function(resData) {
		if (resData != '') location.reload();
	  }
	});

 

url - 이동할 페이지이다. 이동한 페이지에서 데이터를 처리하고 다시 현페이지로 돌아온다. 필요한 경우 데이터를 전달할 수 있다.

 

type - 전달 방식을 의미한다. GET/POST가 있다.

 

data - 데이터 처리를 할 페이지에게 전달할 정도이다. Array 형식일 때 위와 같이 적으면 된다.

 

dataType - 전달받는 인자의 형식.

 

success - 데이터 처리가 성공했을 경우 해당 함수(함수가 아니어도 되는듯 하다)를 실행한다.

json으로 처리할 경우 데이터를 처리하는 페이지에서 전달해주는 값이 인자로 받아진다.

 

ajaxClient1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.1/jquery.min.js"></script> <!-- 제이쿼리  -->
<script>
	$(function(){
		$("#buttonSubmit").on("click",function(){
			$.ajax({
				url:"./ajaxServer1.jsp",
				type:"post",
				data:$("#theForm").serialize(),
				dataType: 'json',
				success:function(res){
					alert("성공");
					$("#result_name").html(res.name);
					$("#result_ph_number").html(res.ph_number);
					$("#result_address").html(res.address);
				},
				error: function(err) {
					alert("실패 원인 : " + err);
				}
			});
		});
	});
</script>
</head>
<body>
<form id="theForm">
    <table border="1">
        <tr>
            <th>이름</th>
            <td><input type="text" id="name" name="name"></td>
        </tr>
        <tr>
            <th>번호</th>
            <td><input type="text" id="ph_number" name="ph_number"></td>
        </tr>
        <tr>
            <th>주소</th>
            <td><input type="text" id="address" name="address"></td>
        </tr>
    </table>
    <br>
    <input id="buttonSubmit" type="button" value="제출">
</form>
<br>
<table border="1">
    <tr>
        <th>[확인] 이름</th>
        <td style="width: 200px;"><span id="result_name"></span></td>
    </tr>
    <tr>
        <th>[확인] 번호</th>
        <td><span id="result_ph_number"></span></td>
    </tr>
    <tr>
        <th>[확인] 주소</th>
        <td><span id="result_address"></span></td>
    </tr>
</table>
</body>
</html>

 

ajaxServer1.jsp

<%@ page language="java" contentType="application/json; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String name = request.getParameter("name");
    String ph_number = request.getParameter("ph_number");
    String address = request.getParameter("address");
%>

{
    "name": "<%= name %>",
    "ph_number": "<%= ph_number %>",
    "address": "<%= address %>"
}

위의 폼에서 이름과 번호, 주소를 입력하고 전송을 누르면 아래의 폼으로 정보가 전송된다.

 

jsp 에서 제이쿼리문을 쓸 때는 주석 때문에 오류가 나는 경우가 많으니 주석을 최소화할 것!

 

0705)

게시판 상세보기 화면과 파일 다운로드 기능 구현

다운로드에 마우스를 가져다 놓았을 때 화면 하단에 <a href="../mvcboard/download.do?ofile=${dto.ofile}&sfile=${dto.sfile}&idx=${dto.idx}">[다운로드]</a> 에 대한 정보가 떠야 한다.

 

파일다운로드가 잘 되는 모습이다.

 

 

글을 쓴 사람에게만 수정, 삭제

비밀번호를 알아야 삭제를 할 수 있게 만든다.

 

pass.jsp

뷰에서 패스컨트롤러로 이동할 때 넘어가는 값 : mode, idx

패스컨트롤러에서 Pass.jsp로 이동할 때 넘어가는 값 : mode

pass.jsp에서 pass, idx, mode 를 파라메터로 받아 넘긴다. 패스컨트롤러로

request객체에 forword로 제어권을 넘겨줘 pass.jsp까지 값이 전달된다.

 

 

뷰 → 패스컨트롤러 → 에디트컨트롤러 → 에디트.jsp

mode, idx → idx → 쿼리스트링으로 idx 넘기기

 

브라우저는 화면을 한 페이지, 한 페이지 넘어갈 때마다 새로운 화면을 서버에게 요청하는 것이다.

그렇기 때문에 한 화면 단위로 파라메터를 넘겨 받아야 동작 처리가 가능하다.


수정하기 → 첨부한 파일도 수정해야한다.

수정을 위한 글 인덱스 번호, 전의 파일과 새로운 파일 정보를 가지고 있어야함.

문제 ) 수정하기 버튼을 누르면 수정한 내용이 전송되고 DB에도 연결되지만

다운로드 폴더에서 파일이 삭제 되지 않는다. (미해결)

한글도 깨짐.. (해결)

 

 

미션 )

  1. 첨부파일이 있는 경우에만 [Down]표시 (완료)
  2. [Down]클릭 시 파일 다운로드가 가능하도록 하기 (완료)

 

 

이메일 보내기 기능 구현 ( 다음 정리 포스팅 주제 )

 

POP 서버명 : pop.naver.com

SMTP 서버명 : smtp.naver.com

 


맥)

스프링툴 3. (래거시 프로젝트가 보여야한다) 으로 해야함..

spring legacy project

다음 주 화)

시험!

 

▼ 눈물이 차올랐던 어제까지의 이야기

더보기

어제 맥북의 오류를 해결했다.. 임포트를 잘 못 한거였음.

그런데.. 파일 업로드부터 cos.jar 라이브러리를 쓰는 파일들을 또 작동이 되지 않는다..ㅠ

맥으로 어떻게 공부를 해야할까.. 코드에 문제가 없으면 대부분 라이브러리나 경로 설정의 문제라고 한다. 그런데 두 가지를 체크해봐도 이상이 없어서 뭐가 문제인지 정말 알 수가 없다.. !

주말동안 코드를 옮겨 적어보며 뭐가 문제인지 다시 차분하게 체크를 해봐야겠다. 

💡 이클립스는 파일이름이나 변수명을 함부로 바꾸면 그때부터 오류가 날 확률이 높아진다..!

💡 Windows 로고 키 + Prt Sc 키를 동시에 누르면 화면이 1초 정도 깜박인 후
     내PC→ 사진 → 스크린샷 폴더에 이미지가 자동으로 저장

 

 

🛠 더 알아볼 것

더보기
  • 어플리케이션 내장 객체의 쓰임, 활용
  • 업로드는 메타데이터 폴더에 파일 업로드하는 것 까지만 하면 되는 거였음.
  • 맥에서는 다운로드 목록이 안보인다. 이 부분 확인할 것.

 

💡 이제는 주소값으로 파라메터를 가지고 온다!!!! 그렇기 때문에 주소값이 중요하다.

모델2방식 → 게시판을 만들 때 작성했던 List.jsp 파일의 코드들을 ListControllar에 옮긴다.


 

모델2방식으로 게시판을 만들기 위해 작성한 파일들

 

  • java Resources > model2.board > MVCBoardDAO.java
  • java Resources > model2.board > MVCBoardDTO.java
  • java Resources > model2.mvcboard > ListControllar.java

 

  • webapp > MVCBoard > index.jsp
  • webapp > MVCBoard > List.jsp
  • webapp > MVCBoard > Edit.jsp
  • webapp > MVCBoard > Pass.jsp
  • webapp > MVCBoard > View.jsp
  • webapp > MVCBoard > Write.jsp

 

  • model2.mvcboard > Downloadcontroller
  • model2.mvcboard > Editcontroller
  • model2.mvcboard > Listcontroller
  • model2.mvcboard > Passcontroller
  • model2.mvcboard > Viewcontroller
  • model2.mvcboard > Writecontroller

 

JSFunction 도 수정했다.


구현한 기능들은 기존의 게시판 만들기를 했을 때 했던 것과 거의 똑같다.

 

 

🌀 DB와 연결해 구현한 기능들을 수행해주는 DAO와 DTO

 

MVCBoardDAO.java

package model2.board;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import common.DBConnPool;
import model1.board.BoardDTO;

public class MVCBoardDAO extends DBConnPool{

   // 검색 조건에 맞는 게시물의 개수를 반환합니다.
   public int selectCount(Map<String , Object> map) {
      
      int totalCount = 0;
      
      String query = "select count(*)"
               +" from mvcboard ";
      
      if(map.get("searchWord") != null) {
         query += " where " + map.get("searchField")
         + " like '%" + map.get("searchWord") + "%' ";
      }
      
      try {
         
         psmt = con.prepareStatement(query);
         rs = psmt.executeQuery();
         
         if(rs.next()) {
            totalCount = rs.getInt(1);
         }
      } catch (Exception e) {
         e.printStackTrace();
      }
      
      return totalCount;
   }
   // 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).
   public List<MVCBoardDTO> selectListPage (Map<String , Object> map){
      
      List<MVCBoardDTO> board = new ArrayList<>();

      String query = " select * "
            + " from ( "
            + " select rownum rNum, Tb.* "
            + " from ( "
            + " select * "
            + " from mvcboard ";
      
      if(map.get("searchWord") != null) {
         query += " where " + map.get("searchField")
               + " like '%" + map.get("searchWord") + "%' ";
      }
            
      query += " order by idx desc"
            + " ) Tb "
            + " ) "
            + " where rnum between ? and ? ";
      
//      페이징을 하기 위한 조건인 물음표 두개
      
      try {
         
         psmt = con.prepareStatement(query);
         psmt.setString(1, map.get("start").toString());
         psmt.setString(2, map.get("end").toString());
         rs = psmt.executeQuery();
         
         while(rs.next()) {
            
            MVCBoardDTO dto = new MVCBoardDTO();
            
            dto.setIdx(rs.getString("idx"));
            dto.setName(rs.getString("Name")); 
            dto.setTitle(rs.getString("title"));
            dto.setContent(rs.getString("content"));
            dto.setPostDate(rs.getString("postdate"));
            dto.setOfile(rs.getString("Ofile"));
            dto.setSfile(rs.getString("Sfile"));
            dto.setDowncount(rs.getInt("downcount"));
            dto.setPass(rs.getString("Pass"));
            dto.setVisitcount(rs.getInt("Visitcount"));
            
            /*
             * System.out.println(rs.getString("idx"));
             * System.out.println(rs.getString("Name"));
             */
            
            board.add(dto);
            
         }
         
         
      } catch (Exception e) {
         e.printStackTrace();
      }
      
      return board;
   }
      
   // 게시글 데이터를 받아 DB에 추가합니다(파일 업로드 지원).
   public int insertWrite(MVCBoardDTO dto) {
      
      int result = 0;
      
      String query = "insert into mvcboard" //select into 는 새로운 정보를 삽입할 때 사용
               + " (idx, name, title, content, ofile, sfile, pass) "
               + " values ( seq_board_num.nextval, ?,?,?,?,?,?) ";   
      try {
         
         psmt = con.prepareStatement(query);
         psmt.setString(1, dto.getName());
         psmt.setString(2, dto.getTitle());
         psmt.setString(3, dto.getContent());
         psmt.setString(4, dto.getOfile());
         psmt.setString(5, dto.getSfile());
         psmt.setString(6, dto.getPass());
         
         result = psmt.executeUpdate();
         
         
      } catch (Exception e) {
         e.printStackTrace();
      }
      
      
      
      return result;
   }
      
   // 주어진 일련번호에 해당하는 게시물을 DTO에 담아 반환합니다.
   public MVCBoardDTO selectView(String idx) {
	  
	   MVCBoardDTO dto = new MVCBoardDTO();
		
		String query = " select * from mvcboard where idx=? ";
		
		try {
			
			psmt = con.prepareStatement(query);
			psmt.setString(1, idx);
			rs = psmt.executeQuery();
			
			if(rs.next()) {
				
	            dto.setIdx(rs.getString("idx"));
	            dto.setName(rs.getString("Name")); 
	            dto.setTitle(rs.getString("title"));
	            dto.setContent(rs.getString("content"));
	            dto.setPostDate(rs.getString("postdate"));
	            dto.setOfile(rs.getString("Ofile"));
	            dto.setSfile(rs.getString("Sfile"));
	            dto.setDowncount(rs.getInt("downcount"));
	            dto.setPass(rs.getString("Pass"));
	            dto.setVisitcount(rs.getInt("Visitcount"));
			}
			
		}catch (Exception e) {
			System.out.println("게시물 조회 증가 중 예외발생");
			e.printStackTrace();
		}
		
		return dto;
   }
      
   // 주어진 일련번호에 해당하는 게시물의 조회수를 1 증가시킵니다.
   public void updateVisitCount(String idx) {
	   
		String query = " update mvcboard "
				+ " set visitcount = visitcount + 1 "
				+ " where idx = ? ";
		
		try {
			
	         psmt = con.prepareStatement(query);
	         psmt.setString(1, idx);
	         psmt.executeQuery();
			
		}catch (Exception e) {
			e.printStackTrace();
		}
   }
      
   // 다운로드 횟수를 1 증가시킵니다.
   public void downCountPlus(String idx) {
	   
	   String query = " update mvcboard "
				+ " set downcount = downcount + 1 "
				+ " where idx = ? ";
		
		try {
			
	         psmt = con.prepareStatement(query);
	         psmt.setString(1, idx);
	         psmt.executeQuery();
			
		}catch (Exception e) {
			System.out.println("파일 다운로드 수 증가 중 예외발생");
			e.printStackTrace();
		}
	   
   }
      
   // 입력한 비밀번호가 지정한 일련번호의 게시물의 비밀번호와 일치하는지 확인합니다.
   public boolean confirmPassword(String pass, String idx) {
	   
	   boolean flag = true;
	   
	   // 아이디, 패스워드가 일치하면 true
	   String query = " select count(*) from mvcboard "
			   + " where pass = ? and idx = ? ";
	   
	   try {
	         psmt = con.prepareStatement(query);
	         psmt.setString(1, pass);
	         psmt.setString(2, idx);
	         rs= psmt.executeQuery();
	         rs.next();
	         
	         if (rs.getInt(1) == 0) {
	        	 flag = false;
	         }
		
	} catch (Exception e) {
		System.out.println("비밀번호 확인 중 예외발생");
		e.printStackTrace();
	}
	   
	   return flag;
   }
      
   // 지정한 일련번호의 게시물을 삭제합니다.
   public int deletePost(String idx) {

	   int result = 0;
	   
	   String query = " delete from mvcboard where idx = ? ";
		
		try {
			psmt = con.prepareStatement(query);
			psmt.setString(1, idx);
			
			result = psmt.executeUpdate();
			
		}catch (Exception e) {
			System.out.println("게시물 삭제 중 예외발생");
			e.printStackTrace();
		}
	   
	   return result;
   }
      
   // 게시글 데이터를 받아 DB에 저장되어 있던 내용을 갱신합니다(파일 업로드 지원).
   
}

 

MVCBoardDTO.java

package model2.board;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class MVCBoardDTO {
	private String idx;
	private String name;
	private String title;
	private String content;
	private String postDate;
	private String ofile;
	private String sfile;
	private int downcount;
	private String pass;
	private int visitcount;
}

 


 

페이지 경로를 찾아주는 location.href, history.back() , history.forward() 를 쓰기 위해

JSFunction을 수정했다.

 

JSFunction.java

package utils;

import java.io.PrintWriter;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspWriter;

public class JSFunction {
   // location.href = "페이지 경로"
   // history.back() , history.forward()
   
   public static void alertLocation(String msg, String url, JspWriter out) {
      try {
         String script = ""
               + "<script>"
                    + "    alert('" + msg + "');"
                    + "    location.href='" + url + "';"
                    + "</script>";
         
         out.print(script);
         
      }catch(Exception e) {
         
      }
   }
   
   public static void alertBack(String msg, JspWriter out) {
        try {
            String script = ""
                          + "<script>"
                          + "    alert('" + msg + "');"
                          + "    history.back();"
                          + "</script>";
            out.println(script);
        }
        catch (Exception e) {}
    }
   
   public static void alertLocation(HttpServletResponse resp, String msg, String url) {
            // System.out.println("alertLocation()");
      try {
         
         resp.setContentType("text/html;charset=UTF-8");
         PrintWriter out = resp.getWriter();
         String script = ""
               + "<script>"
                    + "    alert('" + msg + "');"
                    + "    location.href='" + url + "';"
                    + "</script>";
         
         out.print(script);
         
      }catch(Exception e) {
         
      }
   }
   
   public static void alertBack(HttpServletResponse resp,String msg) {
        try {
           
         resp.setContentType("text/html;charset=UTF-8");
         PrintWriter out = resp.getWriter();
           
            String script = ""
                          + "<script>"
                          + "    alert('" + msg + "');"
                          + "    history.back();"
                          + "</script>";
            out.println(script);
        }
        catch (Exception e) {}
    }
}

 


 

이번 정리에서는 구현한 기능들을 이미지로 살펴보며 해당 이미지의 화면이 나오게 하기 위해 어떤 코드를 작성했는지 살펴보려 한다.

 

 

1. Index

 

Index.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<!-- 대문 페이지 -->
	<h2>파일 첨부형 게시판</h2>
	<a href="../mvcboard/list.do">게시판 목록 바로가기</a>


</body>
</html>

 

▼  list 화면에서 기능을 수행해주는 ListController.java

더보기
package model2.mvcboard;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
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.jasper.runtime.ProtectedFunctionMapper;

import fileupload.MyfileDAO;
import model1.board.BoardDTO;
import model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;
import utils.BoardPage;

@WebServlet("/mvcboard/list.do")
public class ListController extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		MVCBoardDAO dao = new MVCBoardDAO();
		
		Map<String , Object> param = new HashMap<>();
		
		String searchField = req.getParameter("searchField");
		String searchWord = req.getParameter("searchWord");
		
		if (searchWord != null){
			param.put("searchField",searchField);
			param.put("searchWord",searchWord);
		}
		
		
		// --------------------- 페이징 ---------------------
		
		int totalCount = dao.selectCount(param); // 게시물 전체 개수
		
		// 어플리케이션 내장객체 ServletContext로 가지고 오기
		ServletContext application = getServletContext();
		int pageSize = Integer.parseInt(application.getInitParameter("POSTS_PER_PAGE"));
		int blockPage = Integer.parseInt(application.getInitParameter("PAGES_PER_BLOCK"));
		
		// 기본적으로 1 페이지에서 시작
		int pageNum = 1;
		String pageTemp = req.getParameter("pageNum"); // 바뀐 번호를 이용해 페이지 출력
		// 페이지 번호를 이용해서 잘라오기, 페이징하기 위한 기준값으로 pagNum 사용
		if(pageTemp != null && !pageTemp.equals("")){  
			pageNum = Integer.parseInt(pageTemp);
		}
		
		// (현재페이지 - 1) * POSTS_PER_PAGE + 1
		int start = (pageNum - 1) * pageSize + 1;
		// 현재페이지 * POSTS_PER_PAGE
		int end = pageNum * pageSize;
		
		// Map에 담기
		param.put("start",start); 
		param.put("end",end);
		
		List<MVCBoardDTO> boardLists = dao.selectListPage(param);
		dao.close();
		
		// 매핑했던 주소를 넘겨준다. (index.jsp에서 받았던 페이지 주소)
		String pagingImg  = BoardPage.pagingStr(totalCount, pageSize, blockPage, pageNum, "../mvcboard/list.do");
		
		param.put("pagingImg", pagingImg);
		param.put("totalCount", totalCount);
		param.put("pageSize", pageSize);
		param.put("pageNum", pageNum);
		
		req.setAttribute("boardLists", boardLists);
		req.setAttribute("map", param);
		
			// http://localhost:9999/FristJsp
			req.getRequestDispatcher("/MVCBoard/List.jsp").forward(req, resp); // 제어권을 넘긴다
	}
	
}

 

문제) 

webapp > MVCBoard > List.jsp 에서 검색하기를 누르면

http://localhost:9999/FristJsp/mvcboard/list.do 로 이동

→ /mvcboard/list.do를 서블릿에서 매핑했기 때문이다!

이게 이렇게 돼야 하는데 지금보니 안된다! 이렇게 될 수 있게 매핑을 해볼 것.

 

 

2.  List

 

직접 List.jsp를 실행하면 아무것도 나오지 않는다. → 순수 html 코드만 들어있음.

페이지를 넘겨주기 때문, 컨트롤러로 !

컨트롤러를 거쳐야지만 실행

 

List.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>파일 첨부형 게시판 - 목록 보기(List)</h2>

	<!-- 폼태그에 action 속성이 생략되면 현재 페이를 요청한다 (현재 주소창의 URL) -->
	<form method="get">
		<table border="1" width="90%">
			<tr>
				<td align="center">
				<select name="searchField">
						<option value="title">제목</option>
						<option value="content">내용</option>
				</select> 
				<input type="text" name="searchWord" /> 
				<input type="submit" value="검색하기" />
				</td>
			</tr>
		</table>
	</form>

	<table border="1" width="90%">
		<tr>
			<th width="10%">번호</th>
			<th width="*">제목</th>
			<th width="15%">작성자</th>
			<th width="10%">조회수</th>
			<th width="15%">작성일</th>
			<th width="8%">첨부</th>
		</tr>

		<c:choose>

			<c:when test="${empty boardLists }">
				<tr>
					<td colspan="6" align="center">등록된 게시물이 없습니다^^*</td>
				</tr>
			</c:when>

			<c:otherwise>
				<c:forEach var="row" items="${boardLists }" varStatus="loop">
					<tr>
						<td>
						<!-- 페이지 단위로 번호 출력하기(버츄얼넘버) --> 
						 ${map.totalCount - (((map.pageNum - 1) * map.pageSize) + loop.index) }

						</td>
						<td>
						<a href="../mvcboard/view.do?idx=${row.idx }">${row.title }</a></td>
						<td>${row.name }</td>
						<td>${row.visitcount }</td>
						<td>${row.postDate }</td>
						<td>[Down]</td>
					</tr>
				</c:forEach>
			</c:otherwise>

		</c:choose>
		
		</table>
		
		    <table border="1" width="90%">
    	<tr align="center">
    		<td>
    			${map.pagingImg}
    		</td>
    		<td align="right">
    			<button type="button" onclick="location.href='../mvcboard/write.do'">글쓰기</button>
    		</td>
    	</tr>
    </table>
</body>
</html>

 

▼ View의 기능을 수행해주는 ViewController.java

더보기
package model2.mvcboard;

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 model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;


@WebServlet("/mvcboard/view.do")
public class ViewController extends HttpServlet {
   
   protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
      
      MVCBoardDAO dao = new MVCBoardDAO();
      String idx = req.getParameter("idx");
      
      // 조회수 증가
      dao.updateVisitCount(idx);
      
      // 해당글 조회
      MVCBoardDTO dto = dao.selectView(idx);
      
      dao.close();
      
      dto.setContent(dto.getContent().replaceAll("\r\n", "<br>"));
      
      req.setAttribute("dto", dto);
      
        req.getRequestDispatcher("/MVCBoard/View.jsp").forward(req, resp);
   }

}

 

 

3. View

 

View.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h2>파일 첨부형 게시판 - 상세보기(View)</h2>
	<table border="1" width="90%">
	<colgroup>
	<col width="15%" />
	<col width="35%"/>
	<col width="15%"/>
	<col width="*%"/>
	</colgroup>
		<tr>
			<td>번호</td>
			<td>${dto.idx }</td>
			<td>작성자</td>
			<td>${dto.name }</td>
		</tr>
		<tr>
			<td>작성일</td>
			<td>${dto.postDate }</td>
			<td>조회수</td>
			<td>${dto.visitcount }</td>
		</tr>
		<tr>
			<td>제목</td>
			<td colspan="3">${dto.title }</td>
		</tr>
		<tr>
			<td>내용</td>
			<td colspan="3" height="100px">${dto.content }</td>
		</tr>
		<tr>
			<td>첨부파일</td>
			<td>
			<c:if test="${not empty dto.ofile}">
			${dto.ofile }
				<a href="../mvcboard/download.do?ofile=${dto.ofile}&sfile=${dto.sfile}&idx=${dto.idx}">[다운로드]</a>
				</c:if>
			</td>
			<td>다운로드수</td>
			<td>${dto.downcount}</td>
		</tr>
		<tr>
			<td colspan="4" align="center">
			<button type="button" onclick="location.href='../mvcboard/pass.do?mode=edit&idx=${dto.idx}';">수정하기</button>
			<button type="button" onclick="location.href='../mvcboard/pass.do?mode=delete&idx=${dto.idx}';">삭제하기</button>
			<button type="button" onclick="location.href='../mvcboard/list.do';">목록 바로가기</button>
			</td>
		</tr>
	</table>
</body>
</html>

 

▼ WriteController.java

글을 쓰고, 파일을 올리는 기능을 처리한다.

더보기
package model2.mvcboard;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.text.SimpleDateFormat;

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 com.oreilly.servlet.MultipartRequest;

import fileupload.FileUtil;
import model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;
import utils.JSFunction;

@WebServlet("/mvcboard/write.do")
public class WriteController extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		
		
		req.getRequestDispatcher("/MVCBoard/Write.jsp").forward(req, resp);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 어플리케이션 객체 생성
		// ServletContext application = getServletContext(); 이렇게 받아와도 된다
		String saveDirectory = req.getServletContext().getRealPath("Uploads");
		int maxPostSize = 1024 * 1000; //(1MB)
		
		// 객체를 생성해서 업로드하는 부분을 모듈화시킨다
		// 클래스 (업로드, 다운로드, 삭제)
		// MultipartRequest(request,저장할 경로,파일의최대대크기,인코딩,이름정책)
		
		MultipartRequest mr = FileUtil.uploadFile(req, saveDirectory, maxPostSize);
		
		if (mr == null) {
			JSFunction.alertLocation(resp, "첨부 파일이 제한 용량을 초과합니다.", "../mvcboard/write.do");
			return;
		}
		
		MVCBoardDTO dto = new MVCBoardDTO();
		dto.setName(mr.getParameter("name"));
		dto.setTitle(mr.getParameter("title"));
		dto.setContent(mr.getParameter("content"));
		dto.setPass(mr.getParameter("pass"));
		
		String fileName = mr.getFilesystemName("ofile");
		if (fileName != null) {
			String ext = fileName.substring(fileName.lastIndexOf(".")); //  파일 확장자   .txt
			String now = new SimpleDateFormat("yyyyMMdd_HmsS").format(new Date());  // 20240101123456
			String newFileName = now + ext;   // 20240101123456.txt
			
			File oldFile = new File(saveDirectory + File.separator + fileName);
			File newFile = new File(saveDirectory + File.separator + newFileName);
			oldFile.renameTo(newFile);
			
			dto.setOfile(fileName);
			dto.setSfile(newFileName);
		}
		
		// 데이터를 받아 DB에 추가
		MVCBoardDAO dao = new MVCBoardDAO();
		int result = dao.insertWrite(dto);
		dao.close();
		
		if  (result > 0) {
			resp.sendRedirect("../mvcboard/list.do");
		}else {
			resp.sendRedirect("../mvcboard/write.do");
		}
	}

}

 

 

4. Write

글쓰기 버튼을 누르면 글을 쓰는 화면이 나오고 글을 쓰고 파일을 올릴 수 있다.

작성자와 제목, 내용과 비밀번호는 필수다. (아직 필수제약 조건을 걸지 않음)

글을 쓰고 작성 완료를 누르면 쓴 글이 목록보기 화면에 올라온 것을 볼 수 있다.

 

Write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<script>

   function validateForm(form){
      
   }

</script>

</head>
<body>
<h2> 파일 첨부형 게시판 - 글쓰기 (Write)</h2>
   <form name writefrm method = "post" enctype="multipart/form-data" action ="../mvcboard/write.do" onsubmit="return validateForm(this)">
      <table border="1" width="90%">
          <tr>
              <td>작성자</td>
              <td>
                  <input type="text" name="name" style="width:150px;" />
              </td>
          </tr>
          <tr>
              <td>제목</td>
              <td>
                  <input type="text" name="title" style="width:90%;" />
              </td>
          </tr>
          <tr>
              <td>내용</td>
              <td>
                  <textarea name="content" style="width:90%;height:100px;"></textarea>
              </td>
          </tr>
          <tr>
              <td>첨부 파일</td>
              <td>
                  <input type="file" name="ofile" />
              </td>
          </tr>
          <tr>
              <td>비밀번호</td>
              <td>
                  <input type="password" name="pass" style="width:100px;" />
              </td>
          </tr>
          <tr>
              <td colspan="2" align="center">
                  <button type="submit">작성 완료</button>
                  <button type="reset">RESET</button>
                  <button type="button" onclick="location.href='../mvcboard/list.do';">
                      목록 바로가기
                  </button>
              </td>
          </tr>
      </table>  
   </form>

</body>
</html>

 

▼ PassController.java

더보기
package model2.mvcboard;

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 javax.servlet.http.HttpSession;
import javax.swing.filechooser.FileNameExtensionFilter;

import fileupload.FileUtil;
import model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;
import utils.JSFunction;

@WebServlet("/mvcboard/pass.do")
public class PassController extends HttpServlet {
	
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 비밀번호를 받는 폼을 제공한다
		// System.out.println("PassController"); 화면이동이 잘 되는지 보기
		
		// 수정, 삭제를 판단해주는 mode
		req.setAttribute("mode", req.getParameter("mode"));
		req.getRequestDispatcher("/MVCBoard/Pass.jsp").forward(req, resp);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 받은 비밀번호를 처리한다
		String idx = req.getParameter("idx");
		String mode = req.getParameter("mode");
		String pass = req.getParameter("pass");
		
		MVCBoardDAO dao = new MVCBoardDAO();
		
		// 패스워드 확인
		boolean confirmed = dao.confirmPassword(pass, idx);
		
		if (confirmed) {
			// 비밀번호 일치해서 삭제한다면
			if (mode.equals("delete")) {
				dao = new MVCBoardDAO();
				MVCBoardDTO dto = dao.selectView(idx);
				// 받은 정보를 기반으로 파일 삭제
				int result = dao.deletePost(idx);
				dao.close();
				
				if (result > 0) {
					// 게시물의 파일 삭제하기
					String saveFileName = dto.getSfile();
					if (saveFileName != null) {
						FileUtil.deleteFile(req, "/Uploads", saveFileName);
					}
				}
				JSFunction.alertLocation(resp, "게시글이 삭제되었습니다.", "../mvcboard/list.do");
			// 수정하기인지 확인
			}else if (mode.equals("edit")){
				dao = new MVCBoardDAO();
				// 서블릿에서 session 객체 생성하기
				HttpSession session = req.getSession();
				// 공부를 위해 사용하는 방법, 보안때문에 이렇게 하면 안됨
				session.setAttribute(pass, pass);
				resp.sendRedirect("../mvcboard/edit.do?idx=" + idx);
			}
				
		}else {
			// 비밀번호 불일치
			JSFunction.alertBack(resp, "비밀번호 검증에 실패했습니다.");
		}
		
	}

}

 

 

5. Pass.jsp

글을 작성한 사람만 수정, 삭제가 가능하게 하기 위해 비밀번호 확인을 한다.

그리고 비밀번호가 맞으면 수정하기나 글 삭제 페이지로 넘어가고 맞지 않으면 비밀번호 확인에 실패했다는 메세지와 함께 다시 비밀번호 확인 창이 나온다.

 

Pass.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<script>
function validateForm(form) {
	
}
</script>
<body>
	<form name="writeFrm" method="post" action="../mvcboard/pass.do"
		onsubmit="return validateForm(this);">
		<!-- 히든폼을 사용하면 직접 값을 받지 않아도 값을 넘길 수 있다 -->
		<input type="hidden" name="idx" value="${param.idx }"> <input
			type="hidden" name="mode" value="${param.mode }">
		<table border="1" width="90%">
			<tr>
				<td>비밀번호</td>
				<td><input type="password" name="pass" style="width: 100px;" />
				</td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button type="submit">검증하기</button>
					<button type="reset">RESET</button>
					<button type="button"
						onclick="location.href='../mvcboard/list.do';">목록바로가기</button>

				</td>
			</tr>
		</table>
	</form>
</body>
</html>

 

 

6. Edit, Delete

비밀번호 확인에 성공하면 수정하기, 글 삭제하기로 넘어간다.

글을 삭제하면 삭제했다는 메세지를 띄운다. (수정하기 기능 구현은 아직 구현되지 않았다.)

 

Edit.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h2>파일 첨부형 게시판 - 수정하기(Edit)</h2>
	<form>
		<table>
			<tr>
				<td>작성자</td>
				<td><input type="text" name="name" style="width: 150px;"
					value="${dto.name }" /></td>
			</tr>
			<tr>
				<td>제목</td>
				<td><input type="text" name="name" style="width: 90%;"
					value="${dto.title }" /></td>
			</tr>
			<tr>
				<td>내용</td>
				<td><textarea name="content" style="width: 90%; height: 100px;"
						value="${dto.content }"></textarea></td>
			</tr>
			<tr>
				<td>첨부파일</td>
				<td><input type="file" name="ofile" /></td>
			</tr>
			<tr>
				<td colspan="2" align="center">
					<button type="submit">작성 완료</button>
					<button type="reset">RESET</button>
					<button type="button"
						onclick="location.href='../mvcboard/list.do';">목록 바로가기</button>
				</td>
			</tr>
		</table>
	</form>
</body>
</html>

 

 

💡 모든 요청은 컨트롤러를 이용해 처리

get은 뷰 페이지 띄우고 post는 그 뷰를 입력해 처리

 

윈도우 파일 다운로드 위치)

C:\work\jspworkspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\FristJsp\Uploads

 

 

PrintWriter 생성 시 response 의 getWriter()

 

/mvcboard/view.do

viewController.java

 

view.jsp 띄우기


 

일단은 어쩔 수 없으니 학원컴퓨터로 수업을 열심히 듣자.

한동안 맥만 쓰다 윈도우 낯설어질 뻔 했는데 오히려 좋아 굿  ^^

 

Windows 로고 키 + Shift 키 + S를 누릅니다. → 윈도우 캡쳐

큰 프로젝트의 경우 모델2방식으로 처리를 해야 한다.

 

 

🍀 서블릿

 

지금은 자바 클래스, 컨트롤러로서의 역할을 한다.

 

JSP 는 큰 틀에서는 html 언어로, 그 안에 <% %>를 이용해 자바언어 넣어주기

서블릿은 반대. 자바 언어 안에 html 넣어주기

 

 

ServletTest.jsp

<%@page import="java.util.Calendar"%>
<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<%
Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
int second = c.get(Calendar.SECOND);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h1>
		현재 시간
		<%=hour%>시
		<%=minute%>분
		<%=second%>초
	</h1>
</body>
</html>

 

ServletTest.java

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Calendar;

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("/ServletTest")
public class ServletTest extends HttpServlet{
	// 서블릿 클래스는 무조건 HttpServlet 상속을 받아야 한다.

	// get, post 방식 사용 
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 요청이 들어오면 get 방식에 대해 요청 처리
		resp.setContentType("text/html"); // 일반적인 타입
		resp.setCharacterEncoding("utf-8");
		
		Calendar c = Calendar.getInstance();
		int hour = c.get(Calendar.HOUR_OF_DAY);
		int minute = c.get(Calendar.MINUTE);
		int second = c.get(Calendar.SECOND);
		
		PrintWriter out = resp.getWriter();
		out.write("<!DOCTYPE html>");
		out.write("<html>");
		out.write("<head>");
		out.write("<meta charset=\"EUC-KR\">");
		out.write("<title>Insert title here</title>");
		out.write("</head>");
		out.write("<body>");
		out.write("<h1>");
		out.write(Integer.toString(hour));
		out.write("시");
		out.write(Integer.toString(minute));
		out.write("분");
		out.write(Integer.toString(second));
		out.write("초");
		out.write("</h1>");
		out.write("</body>");
		out.write("</html>");
		// URL을 통해 요청
		
	}

}

 

Servlet Life-Sycle

init() - 서블릿이 메모리에 로드될 때 한번만 호출

doGet() - GET 방식으로 date 전송 시 호출

doPost() - POST 방식으로 date 전송 시 호출

service() - 모든 요청은 service()를 통해 do__()메소드로 이동

destroy() - 서블릿이 메모리에서 해제되면 호출

 

 

request 객체에서 주소를 가지고 오는 함수

  • request.getContextPath()
  • 예)  http://localhost:8080/project/list.jsp
  • [return] /project

 

  • request.getRequestURI() : 프로젝트 + 파일경로까지 가져옵니다.
  • 예)  http://localhost:8080/project/list.jsp
  • [return]  /project/list.jsp  
  • String url = request.getRequestURI.split("/");
  • String Name = url[url.length -1];       // list.jsp

 

  • request.getRequestURL() : 전체 경로를 가져옵니다. 
  • 예) http://localhost:8080/project/list.jsp
  • [return]  http://localhost:8080/project/list.jsp

 

  • request.ServletPath() : 파일명만 가져옵니다.
  • 예) http://localhost:8080/project/list.jsp
  • [return]  /list.jsp

 

  • request.getRealPath() : 서버 or 로컬 웹 애플리케이션 절대경로를 가져옵니다. 
  • 예) http://localhost:8080/projectname/list.jsp
  • [return]  c:\project\webapps\projectname\

 

출처: https://yi-chi.tistory.com/12 [2chi:티스토리]

+어플리케이션 내장 객체도 알아보기

 

 

🍀 절대경로와 상대경로

→ 페이지 이동을 위해 꼭 알아야 함!

http://localhost:9999/FristJsp 절대경로

http://localhost:9999/FristJsp/Servlet/DirectServletPrint.jsp 절대경로

http://localhost:9999/Servlet/DirectServletPrint.do → not found (경로 표시가 안되어 있다.)

"../Servlet/DirectServletPrint.do" 상대경로

"FristJsp/Servlet/DirectServletPrint.do" 절대경로

 

💡 같은 위치의 파일이 있다고 생각하면 안되고 url의 주소로 생각해야 한다.

http://localhost:9999/FristJsp/Servlet/DirectServletPrint.jsp 와 

http://localhost:9999/FristJsp/Servlet/DirectServletPrint.do 의 경우, 같은 위치에 파일이 있는 것이 아님. 주소를 나타낸 것일 뿐. 

 

 

🌀 doPost() 방식

DirectServletPrint.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<form method="post" action="../Servlet/DirectServletPrint.do"> <!-- 상대경로 -->
	<input type="submit" value="바로가기">
	</form>
</body>
</html>

 

DirectServletPrint.java

package servlet;

import java.io.IOException;
import java.io.PrintWriter;

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("/Servlet/DirectServletPrint.do")
public class DirectServletPrint extends HttpServlet {
	
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html;charset=UTF-8");
        PrintWriter writer = resp.getWriter();
      
        writer.println("<html>");
        writer.println("<head><title>DirectServletPrint</title></head>");
        writer.println("<body>");
        writer.println("<h2>서블릿에서 직접 출력합니다.</h2>");
        writer.println("<p>jsp로 포워드하지 않습니다.</p>");
        writer.println("</body>");
        writer.println("</html>");
        writer.close();
	}

}

 

 

🍀 서블릿 매핑

브라우저는 URL을 이용해 웹 프로젝트에 접근,

👉 http:// IP주소: 포트번호 / 프로젝트 이름/<패키지 이름>.<클래스 이름>

클래스 이름이 길어지면 입력하기 불편, 보안 취약의 문제로 실제 서블릿 클래스 파일 이름을 대체할 수 있는 별명을 붙이는 것이 바로 매핑

매핑하는 방법은 web.xml 파일에 직접 작성하는 방법과 서블릿 어노테이션을 사용하는 방법 두 가지가 있는데 이번 수업에서는 서블릿 어노테이션을 이용해보았다.

 

 

AnnoMapping.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<p>
		<strong>${message}</strong> 
		<br> 
		<a href="<%=request.getContextPath() %>/Servlet/AnnoMapping.do">바로가기</a>
	</p>
</body>
</html>

 

AnnoMapping.java

package servlet;

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;

@WebServlet("/Servlet/AnnoMapping.do")
public class AnnoMapping extends HttpServlet {

	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		request.setAttribute("message", "@WebServlet으로 매핑");
		request.getRequestDispatcher("/Servlet/AnnoMapping.jsp").forward(request, response);
	}

}

 

 

▼ 질문) 서블릿에서 매핑 시 이름 뒤에 붙는 do, one, mvc 의 차이

더보기

서블릿에서 매핑 시 이름 뒤에 붙는 do, one, mvc 등의 접미사는 특정한 차이를 나타내지 않습니다. 이 접미사들은 단순히 URL 패턴을 식별하기 위해 사용되는 문자열일 뿐입니다. 예를 들어, *.do, *.one, *.mvc와 같은 패턴은 각각 do, one, mvc로 끝나는 모든 요청 URL을 서블릿으로 매핑하는 것을 의미합니다.

이러한 패턴은 개발자가 URL 구조를 논리적으로 구분하고 쉽게 식별할 수 있도록 도와줍니다. 예를 들어:

  • .do: 주로 일반적인 요청을 처리할 때 사용
  • .one: 특정한 기능이나 모듈을 구분할 때 사용
  • .mvc: MVC 패턴에서 컨트롤러 요청을 처리할 때 사용

이처럼 접미사는 개발자의 의도와 프로젝트의 구조에 따라 자유롭게 사용할 수 있습니다.

출처) 노션 AI

 

👉 @WebServlet("/mvcboard/list.do")

<a href="../mvcboard/list.do">게시판 목록 바로가기</a>

 

💡 서블릿을 만들 때 설정해두었던 매핑 이름이 @WebServlet(__)에 나온다.

서블릿을 사용할 파일에 가서

<a href="../mvcboard/list.do">게시판 목록 바로가기</a>

이런 식으로 매핑한 이름의 경로를 적어주면 된다.

 

 

 

한번의 매핑으로 여러 가지 요청 처리하기

 

🌀 doGet() 방식

FrontController.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<h3>한 번의 매핑으로 여러 가지 요청 처리하기</h3>
	<ol>
	  <!--화면에서 ${ } 정보를 읽어온다 -->
		<li>URL : ${uri }</li> 
		<li>요청명 : ${commandStr }</li>
	</ol>
	<ul>
		<li><a href="../Servlet/regist.one">회원가입</a></li>
		<li><a href="../Servlet/login.one">로그인</a></li>
		<li><a href="../Servlet/freeboard.one">자유게시판</a></li>
	</ul>
</body>
</html>

 

FrontController.java

package servlet;

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;

@WebServlet("*.one")
public class FrontController extends HttpServlet {
	
	// 생명주기
	// init() 처음 서블릿이 동작될 때 알아서 호출
	// service() => doGet(), doPost()의 역할을 수행 - 요청이 있을 때
	// destory() 서블릿이 종료될 때 알아서 호출

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String uri = req.getRequestURI(); // /FristJsp/Servelt/AnnoMapping.one
		int lastSlash = uri.lastIndexOf("/");
		String commendStr = uri.substring(lastSlash); // /AnnoMapping.one

		if (commendStr.equals("/regist.one")) {
			registFunc(req);
		} else if (commendStr.equals("/login.one")) {
			loginFunc(req);
		} else if (commendStr.equals("/freeboard.one")) {
			freeboardFunc(req);
		}
		
		// 뷰로 이동
		req.setAttribute("uri", uri);
		req.setAttribute("commandStr", commendStr);
		req.getRequestDispatcher("/Servlet/FrontController.jsp").forward(req, resp); // 제어권을 넘긴다
	}

	void registFunc(HttpServletRequest req) {
		req.setAttribute("resultValue", "<h4>회원가입</h4>");
	}

	void loginFunc(HttpServletRequest req) {
		req.setAttribute("resultValue", "<h4>로그인</h4>");
	}

	void freeboardFunc(HttpServletRequest req) {
		req.setAttribute("resultValue", "<h4>자유게시판</h4>");
	}

}

 

 

 

🍀 MVC 방식(패턴)

리엑트, 뷰 → 노드js 프론트엔드

스프링, 스프링부트 백엔드

전자정부 프레임 기반이 스프링. 자바 수요가 많은 이유.

Go 언어도 전자정부의 표준언어로 지정

 

서블릿은 컨트롤러의 역할. → 모델과 뷰를 연결해주는 중간자

클라이언트 → 프레젠테이션 계층 (서블릿) → DTO→

비즈니스 계층 → DTO→ 퍼시스턴트 계층 = 영속 계층(DAO) → DB

비즈니스 계층 → DTO→ 퍼시스턴트 계층 = moel 이라고 한다.

클라이언트는 뷰(V), 프레젠테이션 계층은 컨트롤러 뷰(C), 비즈니스+퍼시스턴스는 모델(M)

→ MVC 방식(패턴)이라고 한다.

 

 

우리가 만들어볼 MVC 구조

클라이언트 → 서블릿 → DAO → DB

 

DB)

musthave 계정에서

-- mvc2

create table mvcboard (
idx number primary key,
name varchar2(50) not null,
title varchar2(200) not null, 
content varchar2(2000) not null, 
postdate date default sysdate not null,
ofile varchar2(200),
sfile varchar2(30),
downcount number(5) default 0 not null,
pass varchar2(50) not null,
visitcount number default 0 not null
);

insert into mvcboard (idx, name, title, content, pass)
    values (seq_board_num.nextval, '김유신', '자료실 제목1 입니다.','내용','1234');
insert into mvcboard (idx, name, title, content, pass)
    values (seq_board_num.nextval, '장보고', '자료실 제목2 입니다.','내용','1234');
insert into mvcboard (idx, name, title, content, pass)
    values (seq_board_num.nextval, '이순신', '자료실 제목3 입니다.','내용','1234');
insert into mvcboard (idx, name, title, content, pass)
    values (seq_board_num.nextval, '강감찬', '자료실 제목4 입니다.','내용','1234');
insert into mvcboard (idx, name, title, content, pass)
    values (seq_board_num.nextval, '대조영', '자료실 제목5 입니다.','내용','1234');


commit;

 

 

model2.board 패키지)

MVCBoardDAO.java

package model2.board;

import common.DBConnPool;

public class MVCBoardDAO extends DBConnPool {

	// 검색 조건에 맞는 게시물의 개수를 반환합니다.

	// 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).

	// 게시글 데이터를 받아 DB에 추가합니다(파일 업로드 지원).

	// 주어진 일련번호에 해당하는 게시물을 DTO에 담아 반환합니다.

	// 주어진 일련번호에 해당하는 게시물의 조회수를 1 증가시킵니다.

	// 다운로드 횟수를 1 증가시킵니다.

	// 입력한 비밀번호가 지정한 일련번호의 게시물의 비밀번호와 일치하는지 확인합니다.

	// 지정한 일련번호의 게시물을 삭제합니다.

	// 게시글 데이터를 받아 DB에 저장되어 있던 내용을 갱신합니다(파일 업로드 지원).

}

 

MVCBoardDTO.java

package model2.board;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class MVCBoardDTO {
	private String idx;
	private String name;
	private String title;
	private String content;
	private java.sql.Date postDate;
	private String ofile;
	private String sfile;
	private int downcount;
	private String pass;
	private int visitcount;
}

 

model2.mvcboard 패키지)

ListController.java

package model2.mvcboard;

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 org.apache.jasper.runtime.ProtectedFunctionMapper;

import fileupload.MyfileDAO;
import model2.board.MVCBoardDAO;

@WebServlet("/mvcboard/list.do")
public class ListController extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		MVCBoardDAO dao = new MVCBoardDAO();
			
			req.getRequestDispatcher("/MVCBoard/List.jsp").forward(req, resp); // 제어권을 넘긴다
	}
	
}

 

webapp에서 MVCBoard 폴더)

index.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
	pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
	<!-- 대문 페이지 -->
	<h2>파일 첨부형 게시판</h2>
	<a href="../mvcboard/list.do">게시판 목록 바로가기</a>
</body>
</html>

 

List.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Insert title here</title>
</head>
<body>
<h2>파일 첨부형 게시판 - 목록 보기(List)</h2>
</body>
</html>

 

listcontroller

package model2.mvcboard;

import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
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.jasper.runtime.ProtectedFunctionMapper;

import fileupload.MyfileDAO;
import model1.board.BoardDTO;
import model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;
import utils.BoardPage;

@WebServlet("/mvcboard/list.do")
public class ListController extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		MVCBoardDAO dao = new MVCBoardDAO();
		
		Map<String , Object> param = new HashMap<>();
		
		String searchField = req.getParameter("searchField");
		String searchWord = req.getParameter("searchWord");
		
		if (searchWord != null){
			param.put("searchField",searchField);
			param.put("searchWord",searchWord);
		}
		
		
		// --------------------- 페이징 ---------------------
		
		int totalCount = dao.selectCount(param); // 게시물 전체 개수
		
		// 어플리케이션 내장객체 ServletContext로 가지고 오기
		ServletContext application = getServletContext();
		int pageSize = Integer.parseInt(application.getInitParameter("POSTS_PER_PAGE"));
		int blockPage = Integer.parseInt(application.getInitParameter("PAGES_PER_BLOCK"));
		
		// 기본적으로 1 페이지에서 시작
		int pageNum = 1;
		String pageTemp = req.getParameter("pageNum"); // 바뀐 번호를 이용해 페이지 출력
		// 페이지 번호를 이용해서 잘라오기, 페이징하기 위한 기준값으로 pagNum 사용
		if(pageTemp != null && !pageTemp.equals("")){  
			pageNum = Integer.parseInt(pageTemp);
		}
		
		// (현재페이지 - 1) * POSTS_PER_PAGE + 1
		int start = (pageNum - 1) * pageSize + 1;
		// 현재페이지 * POSTS_PER_PAGE
		int end = pageNum * pageSize;
		
		// Map에 담기
		param.put("start",start); 
		param.put("end",end);
		
		List<MVCBoardDTO> boardLists = dao.selectListPage(param);
		dao.close();
		
		// 매핑했던 주소를 넘겨준다. (index.jsp에서 받았던 페이지 주소)
		String pagingImg  = BoardPage.pagingStr(totalCount, pageSize, blockPage, pageNum, "../mvcboard/list.do");
		
		param.put("pagingImg", pagingImg);
		param.put("totalCount", totalCount);
		param.put("pageSize", pageSize);
		param.put("pageNum", pageNum);
		
		req.setAttribute("boardLists", boardLists);
		req.setAttribute("map", param);
		
			// http://localhost:9999/FristJsp
			req.getRequestDispatcher("/MVCBoard/List.jsp").forward(req, resp); // 제어권을 넘긴다
	}
	
}

 

package model2.mvcboard;

import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.text.SimpleDateFormat;

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 com.oreilly.servlet.MultipartRequest;

import fileupload.FileUtil;
import model2.board.MVCBoardDAO;
import model2.board.MVCBoardDTO;
import utils.JSFunction;

@WebServlet("/mvcboard/write.do")
public class WriteController extends HttpServlet {

	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		
		
		req.getRequestDispatcher("/MVCBoard/Write.jsp").forward(req, resp);
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

		// 어플리케이션 객체 생성
		// ServletContext application = getServletContext(); 이렇게 받아와도 된다
		String saveDirectory = req.getServletContext().getRealPath("Uploads");
		int maxPostSize = 1024 * 1000; //(1MB)
		
		// 객체를 생성해서 업로드하는 부분을 모듈화시킨다
		// 클래스 (업로드, 다운로드, 삭제)
		// MultipartRequest(request,저장할 경로,파일의최대대크기,인코딩,이름정책)
		
		MultipartRequest mr = FileUtil.uploadFile(req, saveDirectory, maxPostSize);
		
		if (mr == null) {
			JSFunction.alertLocation(resp, "첨부 파일이 제한 용량을 초과합니다.", "../mvcboard/write.do");
			return;
		}
		
		MVCBoardDTO dto = new MVCBoardDTO();
		dto.setName(mr.getParameter("name"));
		dto.setTitle(mr.getParameter("title"));
		dto.setContent(mr.getParameter("content"));
		dto.setPass(mr.getParameter("pass"));
		
		String fileName = mr.getFilesystemName("ofile");
		if (fileName != null) {
			String ext = fileName.substring(fileName.lastIndexOf(".")); //  파일 확장자   .txt
			String now = new SimpleDateFormat("yyyyMMdd_HmsS").format(new Date());  // 20240101123456
			String newFileName = now + ext;   // 20240101123456.txt
			
			File oldFile = new File(saveDirectory + File.separator + fileName);
			File newFile = new File(saveDirectory + File.separator + newFileName);
			oldFile.renameTo(newFile);
			
			dto.setOfile(fileName);
			dto.setSfile(newFileName);
		}
		
		// 데이터를 받아 DB에 추가
		MVCBoardDAO dao = new MVCBoardDAO();
		int result = dao.insertWrite(dto);
		dao.close();
		
		if  (result > 0) {
			resp.sendRedirect("../mvcboard/list.do");
		}else {
			resp.sendRedirect("../mvcboard/write.do");
		}
	}

}

 

package model2.board;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import common.DBConnPool;

public class MVCBoardDAO extends DBConnPool {

	// 검색 조건에 맞는 게시물의 개수를 반환합니다. 
	// 전체 레코드의 개수를 알아야 페이징을 할 수 있다.
	public int selectCount(Map<String, Object> map) {
		
		int totalcount = 0;
		
		String query = " select count(*) from mvcboard ";
		
		if (map.get("searchWord") != null) {
			query += " where " + map.get("searchField")
			+ " like '%" + map.get("searchWord") + "%'";
		}
		
		try {
			
			psmt = con.prepareStatement(query);
			rs = psmt.executeQuery();
			
			if (rs.next()) {
				totalcount = rs.getInt(1);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return totalcount;
	}

	// 검색 조건에 맞는 게시물 목록을 반환합니다(페이징 기능 지원).
	public List<MVCBoardDTO> selectListPage(Map<String, Object> map){
		
		List<MVCBoardDTO> board = new ArrayList<>();
		
		String query = " select * "
				+ " from ("
				+ " select rownum rNum, Tb.*"
				+ " from ("
				+ " select *"
				+ " from mvcboard ";
		
		if(map.get("searchWord") != null) {
			query += " where " + map.get("searchField")
					+ " like '%" + map.get("searchWord") + "%'";
		}
				
		query += " order by idx desc "
				+ " ) Tb"
				+ " )"
				+ " where rnum between ? and ? ";
		
		try {
			
			psmt = con.prepareStatement(query);
			psmt.setString(1, map.get("start").toString());
			psmt.setString(2, map.get("end").toString());
			rs = psmt.executeQuery();
			
			while (rs.next()) {
				
				MVCBoardDTO dto = new MVCBoardDTO();
				
	            dto.setIdx(rs.getString("idx"));
	            dto.setName(rs.getString("Name")); 
	            dto.setTitle(rs.getString("title"));
	            dto.setContent(rs.getString("content"));
	            dto.setPostDate(rs.getString("postdate"));
	            dto.setOfile(rs.getString("Ofile"));
	            dto.setSfile(rs.getString("Sfile"));
	            dto.setDowncount(rs.getInt("downcount"));
	            dto.setPass(rs.getString("Pass"));
	            dto.setVisitcount(rs.getInt("Visitcount"));
				
				board.add(dto);
				
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return board;
		
	}

	// 게시글 데이터를 받아 DB에 추가합니다(파일 업로드 지원).
	public int insertWrite(MVCBoardDTO dto) {
		
		int result = 0;
		
		String query = " insert into mvcboard "
				+ " (idx, name, title, content, ofile, sfile, pass) "
				+ " values ( seq_board_num.nextval,?,?,?,?,?,?)";
		
		try {
			
			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getName());
			psmt.setString(2, dto.getTitle());
			psmt.setString(3, dto.getContent());
			psmt.setString(4, dto.getOfile());
			psmt.setString(5, dto.getSfile());
			psmt.setString(6, dto.getPass());
			result = psmt.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return result;
	}


	// 주어진 일련번호에 해당하는 게시물을 DTO에 담아 반환합니다.

	// 주어진 일련번호에 해당하는 게시물의 조회수를 1 증가시킵니다.

	// 다운로드 횟수를 1 증가시킵니다.

	// 입력한 비밀번호가 지정한 일련번호의 게시물의 비밀번호와 일치하는지 확인합니다.

	// 지정한 일련번호의 게시물을 삭제합니다.

	// 게시글 데이터를 받아 DB에 저장되어 있던 내용을 갱신합니다(파일 업로드 지원).

}

파일 업로드, 다운로드 기능 구현

 

cos.jar 라는 라이브러리를 사용

파일을 업로드하면 내 Pc의 파일명과 서버에서 전송받는 파일의 파일명이 다르다.

여러 클라이언트가 a라는 파일을 올리면 각 다른 사람이 이름만 동일하게 파일을 올려도 파일명이 중복된다.

 

클라이언트 측에서 보내는 파일을 원본파일이라고 하고, 서버에서 받을 때는 원본파일에 새로운 이름을 붙여 파일명 중복을 막는다.

File Rename Policy(파일이름 중복 정책)

 

💡 form 태그에 enctype="multipart/form-data” 추가
  • <form> 태그의 enctype 속성은 폼 데이터(form data)가 서버로 제출될 때 해당 데이터가 인코딩되는 방법을 명시.
  • 이 속성은 <form> 요소의 method 속성값이 “post”인 경우에만 사용.

 

HTML5 에서 enctype 세 가지

1. application/x-www-form-urlencoded : 기본값. 모든 문자들은 서버로 보내기 전 인코딩됨을 명시
2. multipart/form-date: 모든 문자를 인코딩하지 않음을 명시, 서버로 전송할때 사용
3. text/plain : 디버깅용, 공백을 +로 인코딩(실제 서비스에서 사용 X)

 

날짜, 시간으로 파일 이름을 저장하면 중복될 일이 없다!

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="com.oreilly.servlet.MultipartRequest"%>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%
	// MultipartRequest(request, 저장할 경로, 파일의 최대크기, 인코딩, 이름정책)
	
	// MultipartRequest 객체 생성
	
	String saveDirectory = application.getRealPath("Uploads");
	int maxPostSize = 1024 * 1000; // (1MB)
	String encoding = "UTF-8"; // 인코딩방식의 (거의)표준
	
	try {
		// MultipartRequest 객체 생성 => 파일 업로드 실행
		MultipartRequest mr = new MultipartRequest(request, saveDirectory, maxPostSize, encoding);
		
		// 새로운 파일명 생성 
		String fileName = mr.getFilesystemName("attachedFile"); // 현재 파일 이름 abc.txt
		String ext = fileName.substring(fileName.lastIndexOf(".")); // 파일 확장자 .txt 를 가지고 오는 것
		String now = new SimpleDateFormat("yyyymmdd_HmsS").format(new Date()); // 20230702123456
		String newFileName = now + ext; // 20230702123456.txt
				
	}catch(Exception e){
		
	}
%>

MultipartRequest mr = new MultipartRequest(request,saveDirectory,maxPostSize,encoding);

에서 밑줄이 그어지는 오류가 뜬다.

 


이걸 시작으로 망한 오늘의 수업.. 이때까진 맥으로 수업을 들었는데 

 

결국 학원 컴퓨터로 세팅했다ㅠㅠㅠㅠㅠ

 

학원PC에서도 엉망으로 설치해서 포트번호가 이렇게 됐다..

포트번호 1522

orcl1

1234


 

파일 업로드 기능

 

FileUpload 폴더

Download.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="java.io.FileInputStream" %>
<%@ page import="java.io.FileNotFoundException" %>
<%@ page import="java.io.File" %>
<%@ page import="java.io.InputStream" %>
<%@ page import="java.io.OutputStream" %>
<%@ page import="utils.JSFunction" %>

<%
	String saveDirectory = application.getRealPath("Uploads");
	String saveFilename = request.getParameter("sName");
	String originalFilename = request.getParameter("oName");
	
	try{
		
		File file = new File(saveDirectory,saveFilename); 
		InputStream inStream = new FileInputStream(file);
		
		// 한글 파일명 깨짐 방지
	    String client = request.getHeader("User-Agent");
	    if (client.indexOf("WOW64") == -1) {  // 익스플로워
	        originalFilename = new String(originalFilename.getBytes("UTF-8"), "ISO-8859-1");
	    }
	    else {
	        originalFilename = new String(originalFilename.getBytes("KSC5601"), "ISO-8859-1");
	    }
		
	    response.reset();
	    response.setContentType("application/octet-stream");
	    response.setHeader("Content-Disposition","attachment; filename=\"" + originalFilename + "\"");
	    response.setHeader("Content-Length","" + file.length());
	    
	    OutputStream outStream =  response.getOutputStream();
	    
	    byte b[] = new byte[(int)file.length()];
	    int readBuffer = 0;
	    while((readBuffer = inStream.read(b)) > 0){
	    	outStream.write(b,0,readBuffer);
	    }
	    
	    inStream.close();
	    outStream.close();
		
	}catch(FileNotFoundException e){
		e.printStackTrace();
	}catch(Exception e){
		e.printStackTrace();
	}

%>

 

FileList.jsp

<%@ page import="java.net.URLEncoder"%>
<%@ page import="java.util.List"%>
<%@ page import="fileupload.MyfileDAO"%>
<%@ page import="fileupload.MyfileDTO"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
	MyfileDAO dao = new MyfileDAO();
	List<MyfileDTO> fileLists = dao.myFileList();
	dao.close();
%>
<html>
<head><title>FileUpload</title></head>
<body>
    <h2>DB에 등록된 파일 목록 보기</h2>
    <a href="FileUploadMain.jsp">파일 등록하기</a>
    <table border="1">
       <tr>
            <th>No</th><th>작성자</th><th>제목</th><th>카테고리</th>
            <th>원본 파일명</th><th>저장된 파일명</th><th>작성일</th><th>첨부파일</th>
       </tr>
    <%
    	for(MyfileDTO f : fileLists ){
    %>
       <tr>
       	 <td><%= f.getIdx() %></td>
         <td><%= f.getName() %></td>
         <td><%= f.getTitle() %></td>
         <td><%= f.getCate() %></td>
         <td><%= f.getOfile() %></td>
         <td><%= f.getSfile() %></td>
         <td><%= f.getPostdate() %></td>
       	 
       	 <td>
       	 	<a href="Download.jsp?oName=<%= URLEncoder.encode(f.getOfile(),"UTF-8") %>&sName=<%=URLEncoder.encode(f.getSfile(),"UTF-8") %>">[다운로드]</a>
       	 </td>
       	 
       </tr>
    <%} %> 
    </table>      
</body>
</html>

 

FileUploadMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>
	function validateForm(form){
		
	}
</script>
</head>
<body>
	<h3>파일 업로드</h3>
	
	<form name="fileForm" method="post" enctype="multipart/form-data" 
			action="UploadProcess.jsp" onsubmit="return validateForm(this);">
		작성자 : <input type="text" name="name" value="머스트해브" /><br />
        제목 : <input type="text" name="title" /><br /> 
        카테고리(선택사항) : 
            <input type="checkbox" name="cate" value="사진" checked />사진 
            <input type="checkbox" name="cate" value="과제" />과제 
            <input type="checkbox" name="cate" value="워드" />워드 
            <input type="checkbox" name="cate" value="음원" />음원 <br /> 
        첨부파일 : <input type="file" name="attachedFile" /> <br />
        <input type="submit" value="전송하기" />
	</form>
</body>
</html>

 

UploadProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="com.oreilly.servlet.MultipartRequest" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.io.File" %>
<%@ page import="fileupload.MyfileDAO"%>
<%@ page import="fileupload.MyfileDTO"%>
<%
	//MultipartRequest(request,저장할 경로,파일의최대대크기,인코딩,이름정책)
	
	String saveDirectory = application.getRealPath("Uploads");
	int maxPostSize = 1024 * 1000; //(1MB)
	String encoding = "UTF-8";

	try{
		// MultipartRequest객체 생성 => 파일 업로드 실행
		MultipartRequest mr = new MultipartRequest(request,saveDirectory,maxPostSize,encoding);
		
		// 새로운 파일명 생성
		String fileName = mr.getFilesystemName("attachedFile"); // 현재 파일 이름     abc.txt
		String ext = fileName.substring(fileName.lastIndexOf(".")); //  파일 확장자   .txt
		String now = new SimpleDateFormat("yyyyMMdd_HmsS").format(new Date());  // 20240101123456
		String newFileName = now + ext;   // 20240101123456.txt
		
		File oldFile = new File(saveDirectory + File.separator + fileName);
		File newFile = new File(saveDirectory + File.separator + newFileName);
		oldFile.renameTo(newFile);

		String name = mr.getParameter("name");
		String title = mr.getParameter("title");
		String[] cateArray = mr.getParameterValues("cate");
		
		StringBuffer cateBuf = new StringBuffer();
		
		if(cateArray == null){
			cateBuf.append("선택 없음");
		}else{
			for(String s : cateArray){
				cateBuf.append(s + ",");
			}
		}
		
		MyfileDTO dto = new MyfileDTO();
		dto.setName(name);
		dto.setTitle(title);
		dto.setCate(cateBuf.toString());
		dto.setOfile(fileName);
		dto.setSfile(newFileName);
		
		MyfileDAO dao = new MyfileDAO();
		int result = dao.insertFile(dto);
		dao.close();
		
		response.sendRedirect("FileList.jsp");
		
	}catch(Exception e){
		e.printStackTrace();
	    request.getRequestDispatcher("FileUploadMain.jsp").forward(request, response);
	}
	
	
%>

 

DB에 파일 데이터가 들어간다.

 


맥에서 다시 세팅 시 참고)

자바 17버전, 톰켓 9버전, 강사님 파일로 실행

오라클 XE 맞춰주기

 

MVC2방식으로 게시판 구성하기에 앞서

 

MVC란?

MVC는 Model-View-Controller의 약자로, 소프트웨어 설계 패턴 중 하나입니다. 이 패턴은 애플리케이션을 세 가지 역할로 분리하여 개발과 유지 보수를 효율적으로 수행할 수 있도록 돕습니다. Model은 데이터와 비즈니스 로직을 처리하며, View는 사용자 인터페이스를 담당하고, Controller는 Model과 View 사이의 상호작용을 관리합니다.

EL → jsp에서 기존 표현식을 대체, 자체적으로 출력기능이 있다.

(자바 서블릿에서는 사용X)

${표현식(변수, 수식, 메소드)}

 

 

 

영역객체에서 데이터(속성) 읽어오기

 

ImplicitObjMain.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%
    pageContext.setAttribute("scopeValue", "페이지 영역");
    request.setAttribute("scopeValue", "레퀘스트 영역");
    session.setAttribute("scopevalue", "세션 영역");
    application.setAttribute("scopevalu", "어플리케이션 영역");
    %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>각 영역에 지정된 속성 읽기</h3>
페이지 영역 : <%= pageContext.getAttribute("scopeValue") %>
<p>페이지 영역 : ${pageScope.scopeValue }</p>
<p>리퀘스트 영역 : ${requestScope.scopeValue }</p>
<p>세션 영역 : ${sessionScope.scopeValue }</p>
<p>어플리케이션 영역 : ${applicatioScope.scopeValue }</p>

<h3>영역 지정 없이 속성 읽기</h3>
<p>${scopeValue }</p> <!-- 최초로 발견된 영역에서 읽어온다, 작은 범위에서 큰 범위로 값을 조회 -->
</body>
</html>

 

 

 

파라메터 받기

 

FormSubmit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h2>폼값 전송하기</h2>
    <form name="frm" method="post" action="FormResult.jsp">
        이름 : <input type="text" name="name" /><br />
        성별 : <input type="radio" name="gender" value="Man" />남자
               <input type="radio" name="gender" value="Woman" />여자<br />
        학력 :
            <select name="grade">
                <option value="ele">초딩</option>
                <option value="mid">중딩</option>
                <option value="high">고딩</option>
                <option value="uni">대딩</option>
            </select><br />
        관심 사항 : 
            <input type="checkbox" name="inter" value="pol" />정치
            <input type="checkbox" name="inter" value="eco" />경제
            <input type="checkbox" name="inter" value="ent" />연예
            <input type="checkbox" name="inter" value="spo" />운동<br />
        <input type="submit" value="전송하기" />
    </form>
</body>
</html>

 

FormResult.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h3>EL로 폼값 받기</h3>
	<ul>
		<li>이름 : ${param.name }</li>
		<li>성별 : ${param.gender }</li>
		<li>학력 : ${param.grade }</li>
		<li>관심사항 : 
		${paramValues.inter[0] } 
		${paramValues.inter[1] }
		${paramValues.inter[2] } 
		${paramValues.inter[3] }
		</li>
	</ul>
</body>
</html>

 

 

EL에서 컬렉션 데이터 사용하기

 

CollectionUse.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@page import="java.util.*"%>
<%@page import="common.Person"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<h2>List 컬렉션</h2>
	<%
	List<Object> aList = new ArrayList<>();
	aList.add("청해진");
	aList.add(new Person("장보고", 22));
	pageContext.setAttribute("Ocean", aList);
	
	// aList.get(0);
	%>
	
	<ul>
	<li>0번째 요소 : ${Ocean[0] }</li> <!-- aList.get(0); -->
	<li>1번째 요소 : ${Ocean[1].name }, ${Ocean[1].age }</li> <!-- el은 값을 영역객체에서 가지고 온다 -->
	<li>2번째 요소 : ${Ocean[2] }</li> <!-- 값이 없으면 무시한다 -->
	</ul>
	

	<h2>Map 컬렉션</h2>
	<%
	Map<String, String> map = new HashMap<String, String>();
	map.put("한글", "훈민정음");
	map.put("Eng", "English");
	pageContext.setAttribute("king", map);
	
	// map.get("한글");
	%>
	
	<ul>
	 <li>영문 key : ${king["Eng"]}, ${king['Eng']}, ${king.Eng}</li> <!-- map.get("한글"); -->
     <li>한글 key : ${king["한글"]}, ${king['한글']}</li>
	</ul>

</body>
</html>

 

 

EL 연산

 

Operator1.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%
    int num1 = 3;
    pageContext.setAttribute("num2", 4);
    pageContext.setAttribute("num3", "5");
    pageContext.setAttribute("num4", "8");
    %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
변수 출력 : ${num1 } <br>
영역 변수 출력 : ${num2 } <br>
변수에 값 할당 : ${num1 = 7 } <br>

${num1 + num2}<br>
${num3 / num4}<br>
${num3 div num4}<br>

<%-- ${num2 + "이십"}<br> EL은 문자열 간 '+'연산자로 결합이 되지 않는다. 오류남! --%>

num4 > num3 : ${num4 > num3}<br>
num4 > num3 : ${num4 gt num3}<br>
num4 < num3 : ${num4 lt num3}<br>
num4 == num3 : ${num4 eq num3}<br>

</body>
</html>

 

❗️ 자바 문법에서 선언한 변수를 그대로 사용할 수 없다.

 

 

 

🍀 JSTL

 

자바라이브러리 파일 받는 곳 : https://mvnrepository.com/

HTML코드와 잘 어울리게 코딩을 하기 위해 JSTL의 EL사용

태그 라이브러리 : Core 주로 사용, l18N 가끔 사용

 

 

Core (기본)

변수 : remove, set

흐름제어 : choose(when, otherwise), forEach, forTokens, if

 

if, choose 태그

 

if.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<c:set var="number" value="77" />
	<c:set var="String" value="JSP" />

	<c:if test="${number mod 2 eq 0}" var="result">
		<!-- 조건의 결과를 변수로 받는다 -->
${number}는 짝수입니다. <br>
	</c:if>

	result : ${result }
	<br>

	<h4>choose 태그로 홀짝 판단하기</h4>

	<c:choose>
		<c:when test="${number mod 2 eq 0}">
${number}는 짝수입니다.
</c:when>

		<c:otherwise>
${number}는 홀수입니다.
</c:otherwise>

	</c:choose>

	<c:choose>
		<c:when test="${number >= 90 }">
A학점
</c:when>
		<c:when test="${number ge 80 }">
B학점
</c:when>
		<c:when test="${number >= 70 }">
C학점
</c:when>
		<c:otherwise>
F학점
</c:otherwise>
	</c:choose>
</body>
</html>

 

 

반복문

 

ForEachNomal.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page import = "java.util.*" %>
<%@ page import="common.Person"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<c:forEach begin="1" end="3" step="1" var="i">
		<!-- i가 1에서 시작, 3까지 돌고 1씩 증가 -->

		<p>반복 ${i}입니다.</p>
	</c:forEach>

	<table border="1">
	
	<c:forEach begin="3" end="5" var="i" varStatus="loop">
		<tr>
		<!-- loop는 변수명, 정해진 이름이 아니다 -->
			<td>count : ${loop.count }</td>
			<td>index : ${loop.index }</td>
			<td>current : ${loop.current }</td>
			<td>first : ${loop.first }</td>
			<td>last : ${loop.last }</td>
		</tr>
		</c:forEach>
		
	</table>
	
	<%
	String[] rgba= {"Red", "Green", "Blue", "Black"};
	%>
	
	<c:forEach items="<%=rgba %>" var="c">
	<span style="color:${c}">${c}</span>
	</c:forEach>
	
	<h4>List 컬렉션 사용하기</h4>
	<%
	LinkedList<Person> lists = new LinkedList<Person>();
	lists.add(new Person("맹사성", 34));
	lists.add(new Person("장영실", 99));
	lists.add(new Person("신숙수", 30));
	%>
	
	<c:set var="list" value="<%=lists%>"/>
	<c:forEach item="${lists }" var="list">
	이름 : ${list.name}, 나이: ${list.age }
	</c:forEach>
	
	<h4>Map 컬렉션 사용하기</h4>
	
	<%
	Map<String,Person> maps = new HashMap<String, Person>();
	maps.put("1st", new Person("멩사성", 34));
	maps.put("2st", new Person("장영실", 44));
	maps.put("3st", new Person("신숙주", 54));
	%>
	
	<c:set var="maps" value="<%=maps%>"/>
	<c:forEach items="${maps}" var="map">
	key => %{map.key}<br>
	Value => 이름: ${map.value.name}, 나이: ${map.value.age}
	</c:forEach>
	
</body>
</html>

 

 

내일은,,

파일 업로드기능과 다운로드 기능 구현

[문제 1] Tomcat10 [org.apache.jasper.JasperException: java.lang.ClassNotFoundException: org.apache.jsp.]을(를) 발생시켰습니다.

해결)

https://stackoverflow.com/questions/8021370/java-lang-noclassdeffounderror-javax-servlet-jsp-tagext-taglibraryvalidator

 

java.lang.NoClassDefFoundError: javax/servlet/jsp/tagext/TagLibraryValidator

I followed the guide in this link to install JSTL but I got the following error when I tried to launch my JSP page: java.lang.NoClassDefFoundError: javax/servlet/jsp/tagext/TagLibraryValidator ...

stackoverflow.com

톰캣 10 버전은 자카르타 라이브러리 두 개를 다운 받아야한다. 

-> 이 라이브러리가 필요하다면! 난 결과적으로 아니었다.. 라이브러리 선택 자체를 잘 못했던 거였음. 

 

 

[문제 2] common > Person 파일 작동이안됨

해결)

Build Path 에 들어가보니 전에 잘못 다운받았던 라이브러리가 연결되어있었다. 그래서 그걸 삭제하니 해결됨!

그리고 404 에러가 한 파일에서만 자꾸 났는데.. 이름을 바꾸니 해결됨. 

이름 바꾸고는 꼭 프로젝트 들어가서 클린을 해줄 것! 

 

 

 

 

 

UIUX _국비과정 0625 ~ 27 [게시판]

👉 톰캣은 다쓰고 나면 꼭 서버 종료를 잘하자인터넷도 다 종료하고 톰캣을 다시 켜야한다.프로그래밍에서 1 = 참 0 = 거짓 🎉 게시판 만들기이 코드는 통으로 그냥 외워라. 프로그램 만드는

100dumpling.tistory.com

 

ReplyBoard 폴더에 구현.

 

ReplyBoard > List.jsp

<%@page import="utils.BoardPage"%>
<%@page import="model1.board.BoardDAO"%>
<%@page import="model1.board.BoardDTO"%>
<%@page import="java.util.HashMap"%>
<%@page import="java.util.Map"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%
// DB에 연결
BoardDAO dao = new BoardDAO(application);

// form에서 액션 속성 생략 -> 자기 자신 페이지를 파라매터로 받는다. 
String searchField = request.getParameter("searchField");
String searchWord = request.getParameter("searchWord");

Map<String, Object> param = new HashMap<>();

// 검색조건으로 검색하려 할때
if (searchWord != null) {
	param.put("searchField", searchField);
	param.put("searchWord", searchWord);
}

// 전체 개수 구하기 selectCount()
// 검색 했을 때 개수 dao.selectCount(param)
// boardLists 에 DTO의 정보가 들어있다.
int totalCount = dao.selectCount(param);

int pageSize = Integer.parseInt(application.getInitParameter("POSTS_PER_PAGE"));
int blockPage = Integer.parseInt(application.getInitParameter("PAGES_PER_BLOCK"));
int totalPage = (int) Math.ceil( (double)totalCount / pageSize );

// 페이지 번호를 관리하는 변수
int pageNum = 1;

// 페이지 번호를 다른 걸로 선택하면 그 다른 페이지 번호를 받아온다
String pageTemp = request.getParameter("pageNum");

if (pageTemp != null && !pageTemp.equals("")){
	pageNum = Integer.parseInt(pageTemp);
}

// 게시물의 시작번호와 끝 번호 구하기
int start = (pageNum - 1) * pageSize + 1;
int end = pageNum * pageSize;

param.put("start", start);
param.put("end", end);

/* List<BoardDTO> boardLists = dao.selectList(param); */
List<BoardDTO> boardLists = dao.selectListPage(param);
dao.close();

%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<jsp:include page="../Common/Link.jsp" />
	<h2>목록 보기(List)</h2>

	<!-- 폼태그에 action 속성이 생략되면 자신의 현재 페이지를 요청한다. (List.jsp)-->
	<form method="get">
		<table border="1" width="90%">
			<tr>
				<td align="center">
				<select name="searchField">
						<option value="title">제목</option>
						<option value="content">내용</option>
				</select> 
				<input type="text" name="searchWord" /> 
				<input type="submit" value="검색하기" />
				</td>
			</tr>
		</table>
	</form>

	<table border="1" width="90%">
		<tr>
			<th width="10%">번호</th>
			<th width="50%">제목</th>
			<th width="15%">작성자</th>
			<th width="10%">조회수</th>
			<th width="15%">작성일</th>
		</tr>


<!-- 게시물이 없을 떄 -->
		<% if (boardLists.isEmpty()) {%>

		<tr>
			<td colspan="5" align="center">등록된 게시물이 없습니다^^*</td>
		</tr>

		<% }else{

		int virtualNum = totalCount - (pageNum - 1) * pageSize;
		for(BoardDTO dto : boardLists){ 
			// virtualNum = totalCount--;
		%>

		<!-- 게시물이 있을 때 -->
		<tr align="center">
		<!-- DTO에서 쓴 이름과 같게 -->
			<%-- <td><%= dto.getNum() %></td> --%>
			<td><%= virtualNum-- %></td>
			<td>
			<a href="View.jsp?num=<%= dto.getNum() %>"> <%= dto.getTitle() %> </a>

			</td>
			
			
			<td><%= dto.getId() %></td>
			<td><%= dto.getVisitcount() %></td>
			<td><%= dto.getPostDate() %></td>
		</tr>

		<%
		 } // for문 
		} // if else문
		%>

	</table>

	<table border="1" width="90%">
		<tr align="center">
		<td>
		<!-- [첫번째 페이지] [이전 블럭]  [1] [2] [3] [4] [5] [다음 블럭] [마지막 페이지] -->
		
		<!-- request.getRequestURI()로 주소값을 가지고 올 수 있다 -->
		<%= BoardPage.pagingStr(totalCount, pageSize, blockPage, pageNum, request.getRequestURI()) %>
		</td>
			<td align="right">
				<button type="button" onclick="location.href='write.jsp'">글쓰기</button>
			</td>
		</tr>
	</table>
</body>
</html>

 

ReplyBoard > View.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="./IsLoggedIn.jsp"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.replay.ReplyDAO"%>
<%@ page import="model1.replay.ReplyDTO"%>
<%@ page import="java.util.List"%>

<%
String num = request.getParameter("num");
BoardDAO dao = new BoardDAO(application);
ReplyDAO replyDAO = new ReplyDAO(application);

// 글에 대한 상세보기 -> 조회수 증가 처리
dao.updateVisitCount(num);

// 상세정보 보기 (원글 정보)
BoardDTO dto = dao.selectView(num);

List<ReplyDTO> replyLists = replyDAO.selectReply(num);
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>게시글 상세보기</title>

<script>
    function deletePost() {
        let confirmed = confirm("정말로 삭제하시겠습니까?");
        if (confirmed) {
            let form = document.writeFrm;
            form.method = "post";
            form.action = "DeleteProcess.jsp";
            form.submit();
        }
    }

    function validateForm(form) {
        if (form.replycontent.value == "") {
            alert("댓글 내용을 입력하세요.");
            form.replycontent.focus();
            return false;
        }
    }
</script>
</head>

<body>
    <h2>회원제 게시판 - 상세보기(View)</h2>
    <form name="writeFrm">
        <input type="hidden" name="num" value="<%=num%>">

        <table border="1" width="90%">
            <tr>
                <td>번호</td>
                <td><%=dto.getNum()%></td>
                <td>작성자</td>
                <td><%=dto.getName()%></td>
            </tr>
            <tr>
                <td>작성일</td>
                <td><%=dto.getPostDate()%></td>
                <td>조회수</td>
                <td><%=dto.getVisitcount()%></td>
            </tr>
            <tr>
                <td>제목</td>
                <td colspan="3"><%=dto.getTitle()%></td>
            </tr>
            <tr>
                <td>내용</td>
                <td colspan="3" height="100px">
                <%=dto.getContent().replace("\r\n", "<br/>")%></td>
            </tr>
            <tr>
                <td colspan="4" align="center">
                    <% if (session.getAttribute("UserId") != null && session.getAttribute("UserId").toString().equals(dto.getId())) { %>
                        <button type="button" onclick="location.href = 'Edit.jsp?num=<%=dto.getNum()%>'">수정하기</button>
                        <button type="button" onclick="deletePost()">삭제하기</button>
                    <% } %>
                    <button type="button" onclick="location.href = 'List.jsp'">목록보기</button>
                </td>
            </tr>
        </table>
    </form>

    <p>댓글</p>
    <table border="1" width="90%">
        <% if (replyLists.isEmpty()) { %>
        <tr>
            <td colspan="5" align="center">등록된 댓글이 없습니다^^*</td>
        </tr>
        <% } else { %>
        <tr>
            <th width="10%">번호</th>
            <th width="50%">댓글내용</th>
            <th width="15%">작성자</th>
            <th width="20%">날짜</th>
            <th width="5%"></th>
        </tr>
        <% for (ReplyDTO rDto : replyLists) { %>
        <tr align="center">
            <td><%= rDto.getReplyno() %></td>
            <td><%= rDto.getReplycomment() %></td>
            <td><%= rDto.getId() %></td>
            <td><%= rDto.getRegidate() %></td>
            <td>
                <% if (session.getAttribute("UserId") != null && session.getAttribute("UserId").toString().equals(rDto.getId())) { %>
                    <button type="button" onclick="location.href='ReplyEdit.jsp?replyno=<%=rDto.getReplyno()%>&num=<%=num%>'">수정</button>
                    <button type="button" onclick="location.href='ReplyDelete.jsp?replyno=<%=rDto.getReplyno()%>&num=<%=num%>'">삭제</button>
                <% } %>
            </td>
        </tr>
        <% } %>
        <% } %>
    </table>

    <h3>회원제 게시판 - 댓글(Reply)</h3>
    <form name="WriteFrm" method="post" action="ReplyProcess.jsp" onsubmit="return validateForm(this)">
        <input type="hidden" name="num" value="<%=dto.getNum() %>">
        <table border="1" width="90%">
            <tr>
                <td>댓글 내용</td>
                <td><textarea name="replycontent" style="width: 90%;"></textarea></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <button type="submit">작성완료</button>
                    <button type="reset">다시입력</button>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

 

IsLoggedIn.jsp

<%@page import="utils.JSFunction"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<!--  로그인 유무를 판단 -->
<%
if (session.getAttribute("UserId") == null){
	JSFunction.alertLocation("로그인 후 이용해주세요.", "../Session/LoginForm.jsp", out);
	return;
}
%>

 

write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
	<!-- 공통관심사항 -->
	<%@ include file ="./IsLoggedIn.jsp"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<!-- 유효성 검사 -->
<script>
function validateForm(form){
	if (form.title.value == ""){
		alert("제목을 입력하세요");
		form.title.focus();
		return false;
	}
	
	if (form.content.value == ""){
		alert("내용을 입력하세요");
		form.content.focus();
		return false;
	}
}
</script>
</head>
<body>
	<jsp:include page="../Common/Link.jsp" />
	<h2>회원제 게시판 - 글쓰기(Write)</h2>


	<form name="writeFrm" method="post" action="WriteProcess.jsp"
		onsubmit="return validateForm(this);">
		<table bordar="1" width="90%">
			<tr>
				<td>제목</td>
				<td><input type="text" name="title" style="width: 90%;" /></td>
			</tr>

			<tr>
				<td>내용</td>
				<td><textarea name="content" style="width: 90%; height: 100px;"></textarea>
				</td>
			</tr>

			<tr>
				<td colspan="2" align="center">
					<button type="submit">작성 완료</button>
					<button type="reset">다시 입력</button>
					<button type="button" onclick="location.href='List.jsp';">
						목록 보기</button>
						</td>
			</tr>

		</table>
	</form>
</body>
</html>

 

WriteProcess.jsp

<%@page import="model1.board.BoardDTO"%>
<%@page import="model1.board.BoardDAO"%>
<%@ include file ="./IsLoggedIn.jsp"%>
<%@page import="utils.JSFunction"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>

<%
// 타이틀과 컨텐츠를 파라메터로 받는다.
String title = request.getParameter("title");
String content = request.getParameter("content");

// DTO의 데이터를 묶어서 DAO로 보낸다.
// 서버 -> DTO -> DAO -> DB
// 서버 <- DTO <- DAO

BoardDTO dto = new BoardDTO();

dto.setTitle(title);
dto.setContent(content);
dto.setId((String)session.getAttribute("UserId"));

// DAO에 데이터를 삽인하는 기능 추가
// DB에 연결
BoardDAO dao = new BoardDAO(application);
int result = dao.insertWrite(dto);


// 페이징 기능을 위한 데이터 집어넣기
// 한번만 실행해야 한다. 
/* for(int i = 1; i <= 100; i++){
	dto.setTitle(title + "-" + i);
	dao.insertWrite(dto);
} */


dao.close(); 

if(result > 0){
	// 성공했을 때 페이지 이동
	response.sendRedirect("List.jsp");
}else{
	// 실패 시 이전 페이지로 
	JSFunction.alertBack("글쓰기에 실패하였습니다.", out);
}

%>

 

Edit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ include file="./IsLoggedIn.jsp"%> 
<%
   String num = request.getParameter("num");
   
   BoardDAO dao = new BoardDAO(application);
   BoardDTO dto = dao.selectView(num);
   
   String sessionId = session.getAttribute("UserId").toString();
   
   System.out.println(sessionId);
   System.out.println(dto.getId());
   System.out.println(dto.getNum());
   
   if(!sessionId.equals(dto.getId())){
      JSFunction.alertBack("작성자 본인만 수정할 수 있습니다.", out);
      return;
   }
   
   dao.close();
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>

   //validateForm()
   function validateForm(form) {
      if (form.title.value == "") {
           alert("제목을 입력하세요.");
           form.title.focus();
           return false;
       }
       if (form.content.value == "") {
           alert("내용을 입력하세요.");
           form.content.focus();
           return false;
       }
   }
</script>
</head>
<body>
<%@ include file ="./IsLoggedIn.jsp"%>
   <h2>회원제 게시판 - 수정하기(Edit)</h2>
   <form name="writeFrm" method="post" action="EditProcess.jsp" onsubmit="return validateForm(this);">
   <!-- 값을 추가적으로 지정해서 넘길 때 hidden form -->
   <!-- num, title, content 가 넘어간다. -->
   <input type="hidden" name="num" value="<%=dto.getNum() %>">
   
      <table border="1" width="90%">
         <tr>
            <td>제목</td>
            <td>
               <input type="text" name="title" value="<%= dto.getTitle() %>" />
            </td>
         </tr>
         <tr>
            <td>내용</td>
            <td>
               <textarea name="content" style="width: 90%; height: 100px;"><%=dto.getContent() %></textarea>
            </td>
         </tr>
         <tr>
            <td colspan="2" align="center">
                <button type="submit">작성완료</button>
                <button type="reset">다시입력</button>
                <button type="button" onclick="location.href='List.jsp'">목록보기</button>
            </td>
         </tr>
      </table>
   </form>
</body>
</html>

 

EditProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page import="utils.JSFunction" %>
<%@ include file="./IsLoggedIn.jsp"%> 
    
<%
String num = request.getParameter("num");
String title = request.getParameter("title");
String content = request.getParameter("content");

BoardDTO dto = new BoardDTO();
dto.setNum(num);
dto.setTitle(title);
dto.setContent(content);

BoardDAO dao = new BoardDAO(application);
int result = dao.updateEdit(dto);
dao.close();

/* 글 올리기 성공했을 때는 상세보기 화면, 실패하면 수정하기 */
if (result > 0){
	/* View 페이지에서 어떤 글을 수정해야 하는지 알기 위해  */
	response.sendRedirect("View.jsp?num=" + dto.getNum());
}else{
	JSFunction.alertBack("수정하기에 실패했습니다", out);
}

%>

 

ReplyProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="model1.replay.ReplyDAO"%>
<%@ page import="model1.replay.ReplyDTO"%>
<%@ page import="utils.JSFunction" %>
<%@ include file="./IsLoggedIn.jsp"%> 
<%
	String comment = request.getParameter("replycontent"); 
	String num = request.getParameter("num"); 
	String sessionId = (String)session.getAttribute("UserId");
	
	ReplyDTO rDto = new ReplyDTO();
	rDto.setNum(num);
	rDto.setReplycomment(comment);
	rDto.setId(sessionId);
	
	ReplyDAO dao = new ReplyDAO(application);
	int result = dao.insertReply(rDto);
	dao.close();
	
	if (result > 0){
		response.sendRedirect("View.jsp?num=" + num);
	}else {
		JSFunction.alertBack("댓글 쓰기에 실패했습니다.", out);
	}
	
%>

 

ReplyEdit.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="model1.replay.ReplyDAO"%>
<%@ page import="model1.replay.ReplyDTO"%>
<%@ include file="./IsLoggedIn.jsp"%>
<%

String replyno = request.getParameter("replyno");
String num = request.getParameter("num");

ReplyDTO rDto = new ReplyDTO();
ReplyDAO rDao = new ReplyDAO(application);

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script>

   //validateForm()
   function validateForm(form) {
        if (form.replycontent.value == "") {
            alert("댓글 내용을 입력하세요.");
            form.replycontent.focus();
            return false;
        }
    }
   
</script>
</head>
<body>
<h2>댓글 수정</h2>
    <form name="editReplyFrm" method="post" action="ReplyEditProcess.jsp" onsubmit="return validateForm(this)">
        <input type="hidden" name="replyno" value="<%=replyno%>">
        <input type="hidden" name="num" value="<%=num%>">
        <table border="1" width="90%">
            <tr>
                <td>댓글 내용</td>
                <td><textarea name="replycontent" style="width: 90%;"><%=rDto.getReplycomment()%></textarea></td>
            </tr>
            <tr>
                <td colspan="2" align="center">
                    <button type="submit">수정완료</button>
                    <button type="button" onclick="location.href='View.jsp?num=<%=num%>'">취소</button>
                </td>
            </tr>
        </table>
    </form>
</body>
</html>

 

ReplyEditProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ include file="./IsLoggedIn.jsp"%>
<%@ page import="model1.replay.ReplyDAO"%>
<%@ page import="model1.replay.ReplyDTO"%>


<%
String replyno = request.getParameter("replyno");
String num = request.getParameter("num");
String replycontent = request.getParameter("replycontent");

ReplyDTO rDto = new ReplyDTO();
rDto.setReplyno(replyno);
rDto.setReplycomment(replycontent);

ReplyDAO rDao = new ReplyDAO(application);
int updateResult = rDao.updateReply(rDto);

if (updateResult > 0) {
    response.sendRedirect("View.jsp?num=" + num);
} else {
    out.println("<script>");
    out.println("alert('댓글 수정에 실패했습니다.');");
    out.println("history.back();");
    out.println("</script>");

}
%>

 

ReplyDelete.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ page import="model1.replay.ReplyDAO"%>
<%@ page import="model1.replay.ReplyDTO"%>
<%@ include file="./IsLoggedIn.jsp"%>
<%
String replyno = request.getParameter("replyno");
String num = request.getParameter("num");

ReplyDTO rDto = new ReplyDTO();
rDto.setReplyno(replyno);

// System.out.println("replyno : " + dto.getReplyno());

ReplyDAO rDao = new ReplyDAO(application);
int result = rDao.deleteReply(rDto);

// String sessionId = session.getAttribute("UserId").toString();

// System.out.println(sessionId);
// System.out.println(dto.getId());
// System.out.println(dto.getNum());

if (result > 0) {
    JSFunction.alertLocation("댓글이 삭제되었습니다.", "View.jsp?num=" + num, out);
} else {
    JSFunction.alertBack("삭제에 실패했습니다.", out);
}

rDao.close();
%>

 

DeleteProcess.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ page import="model1.board.BoardDAO"%>
<%@ page import="model1.board.BoardDTO"%>
<%@ page import="utils.JSFunction" %>
<%@ include file="./IsLoggedIn.jsp"%> 

<%
String num = request.getParameter("num");

BoardDTO dto = new BoardDTO();
BoardDAO dao = new BoardDAO(application);
dto = dao.selectView(num);

String sessionId = session.getAttribute("UserId").toString();

// 글을 작성한 사람인지 아닌지. 글을 작성한 사람만 게시글을 삭제할 수 있다.
if (sessionId.equals(dto.getId())){
	// 본인 인증 성공, 삭제 처리
	dto.setNum(num);
	int result = dao.deletePost(dto);
	dao.close();
	
	if (result > 0) {
		// 삭제 성공
		JSFunction.alertLocation("삭제되었습니다", "List.jsp", out);
	}else{
		// 삭제 실패 -> 상세 페이지 화면
		JSFunction.alertBack("삭제에 실패했습니다.", out);
	}
	
}else{
	// 본인 인증 실패
	JSFunction.alertBack("본인만 삭제할 수 있습니다.", out);
	return;}


%>

 

ReplyDTO

package model1.replay;

import lombok.Getter;
import lombok.Setter;

@Getter
@Setter
public class ReplyDTO {
	// 컬럼명
private String replyno;
private String replycomment;
private String id;
private String regidate;
private String num;

}

 

ReplyDAO

package model1.replay;

import java.util.ArrayList;
import java.util.List;

import common.JDBConnect;
import jakarta.servlet.ServletContext;
import model1.board.BoardDTO;

public class ReplyDAO extends JDBConnect {
	
	public ReplyDAO (ServletContext application) {
		super(application);
	}
	
	public List<ReplyDTO> selectReply(String num){
		List<ReplyDTO> replybbs = new ArrayList();
		
		String query  = " select replyno, replycomment, r.id, r.regidate, r.num "
				+ " from reply r inner join board b "
				+ " on r.num = b.num "
				+ " where r.num = ? "
				+ " order by replyno asc ";
		
		try {
			psmt = con.prepareStatement(query);
			psmt.setString(1, num);
			
			rs = psmt.executeQuery();
			
			while(rs.next()) {
	            
	            ReplyDTO dto = new ReplyDTO();
	            
	            dto.setReplyno(rs.getString(1));
	            dto.setReplycomment(rs.getString(2));
	            dto.setId(rs.getString(3));
	            dto.setRegidate(rs.getString(4));
	            dto.setNum(rs.getString(5));
	            
	            replybbs.add(dto);
	         }
	         
	         
	      }catch (Exception e) {
	         e.printStackTrace();
	      }
	      
	      return replybbs;
	      
	   }
	
	public int insertReply(ReplyDTO dto) {
		
		int result = 0;
		
		String query  = " insert into reply "
				+ " (replyno, replycomment, id, num) "
				+ " values (seq_board_num.nextval,?, ?, ?)";
		
		try {
			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getReplycomment());
			psmt.setString(2, dto.getId());
			psmt.setString(3, dto.getNum());

			result = psmt.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	// 댓글 수정
	public int updateReply(ReplyDTO dto) {
		int result = 0;
		
		String query = " update reply " + " set replycomment = ? " + " where replyno = ? ";
		
		try {
			
			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getReplycomment());
			psmt.setString(2, dto.getReplyno());
			result = psmt.executeUpdate();
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		return result;
	}
	
	
	// 댓글 삭제
	public int deleteReply(ReplyDTO dto) {
		System.out.println("replyno : " + dto.getReplyno());

		int result = 0;

		String query = " delete from reply where replyno = ? ";

		try {

			psmt = con.prepareStatement(query);
			psmt.setString(1, dto.getReplyno());
			// 댓글 어떻게 판단할지
			result = psmt.executeUpdate();

		} catch (Exception e) {
			e.printStackTrace();
		}

		return result;
	}
}

댓글작성자에게만 수정, 삭제 버튼이 보이고, 댓글 작성자는 정상적으로 수정, 삭제를 할 수 있다.

 

코드를 구현하며 잘 안됐던, 어려웠던 부분에 대한 노트 추가) 

 

UIUX _국비과정 0628 [게시판_페이징] | Notion

💫 페이징이 된 모습을 보기 위해 Borad를 복사해 PagingBorad 폴더를 만들었다.

ringed-tartan-f02.notion.site

 

+ Recent posts