본문 바로가기
국비학원

[국비지원] KH 정보교육원 82-83일차

by 도전하는 개발자 2022. 7. 26.

kh day 083

이번주 공지사항
 가. Servlet/JSP : 오늘 Servlet 종료, 곧바로 JSP 기본/고급 완료예정 (수요일까지)
 나. 스프링의 선행요소 기술 학습:
  -DB처리를 위한 MyBatis SQL Mapper Framework 완료예정
  - 배치처리를 위한 Quartz Job Scheduler Framework 완료예정
 다. 스프링 MVC 프레임워크 시작 : 
  - spring-core, spring-context, spring-webmvc, spring-jdbc, spring-tx, spring-websocket

동시에 Final Project에 박차를 가해주시기 자랍니다.
 가. UX/UI 스토리보드 작성
 나. 관계형 데이터 모델링 => 3NF까지 완료된 테이블 생성 => Dummy 데이터 생성

---

*파일 업로드

 

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <title>FileUpload 실습</title>
</head>

<body>
    <h1>/resources/uploadForm.html</h1>
    <hr>
    
    <!-- 파일업로드 태그가 포함된 Form은, 반드시 enctype 속성의 값으로 아래와 같이 지정해야함 (표준) -->
    <form action="/Upload" method="post" enctype="multipart/form-data">

        1. 작성자 : <input type="text" name="writer"><br><br>
        2. 업로드 파일 : <input type="file" name="uploadFile" multiple>
        <br><br>

        <input type="submit" value="업로드">
    </form>
</body>

</html>

uploadForm.html

 

@Log4j2
@NoArgsConstructor
@MultipartConfig(
		location="C:/temp/upload", 
		maxFileSize=1 * 1024 * 1024 * 2,       // 최대 파일 크기 : 2MB
		maxRequestSize=1 * 1024 * 1024 * 2)    // 한 요청당 최대크기 : 2MB
@WebServlet("/Upload")
public class UploadServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
	
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException {
		log.trace("service(req, res) invoked.");	

		// 응답 메시지 생성 및 전송
		req.setCharacterEncoding("utf8");
		res.setContentType("text/html; charset=utf8");
		@Cleanup
		PrintWriter out = res.getWriter();
		
		// multiple 속성이 있는 <input type=file multiple> 태그로 업로드 된 복수의 파일을 저장하는 로직
		Collection<Part> parts = req.getParts();		
//		parts.forEach( p -> log.info(p) );
		parts.forEach( p -> log.info( p.getName() ) );
		
		// 멀티파트를 구성하는 각 Part의 이름이란? => 각 파트를 구성하는 전송 파라미터의 이름
//		Part uploadFilePart = req.getPart("uploadFile");
//		log.info("uploadFile : {}", uploadFilePart);
		
		// 각 파트의 구성 헤더 정보에 접근해보자
		Iterator<Part> iter = parts.iterator();
		while(iter.hasNext()) {               // 그 다음 요소가 있느냐?
			Part part = iter.next();          // 있다면 그 다음 요소를 달라!
			
			// 이 Part에 포함된 
			log.info("========================================");
			log.info("\t+ 1. part.getName : {}", part.getName());               // 전송 파라미터 이름 (=파트이름)  
			log.info("\t+ 2. part.getContentType : {}", part.getContentType()); // Content-Type 헤더의 값  
			log.info("\t+ 3. part.getSize : {}", part.getSize());               // Body의 Content Length  
			log.info("\t+ 4. part.getSubmittedFileName : {}", part.getSubmittedFileName()); // 파일의 원본 파일명  
			log.info("\t+ 5. part.getHeaderNames : {}", part.getHeaderNames()); // 헤더명의 목록
			
			// 첨부파일만 포함하고 있는 Part를 필터링해서 첨부파일 저장
			if( part.getSubmittedFileName() != null ) { 
				// part.write(part.getSubmittedFileName()); // 원본파일명으로 지정된 폴더에 저장
				// 근데 실제 서비스에선 이렇게 하면 원본파일명이 겹치는 사용자가 있기 때문에 문제가 생김
				
				try {
					String uuid = UUIDGenerator.generateUniqueKeysWithUUIDAndMessageDigest();
					part.write(uuid); // 파일명 임시파일처럼 저장
					part.delete(); // 다운로드시 사용된 임시파일 삭제
					
					// 응답으로 각 파일의 다운로드 링크 생성
					String encodedFilename = URLEncoder.encode(part.getSubmittedFileName(), "utf8");
					String link = String.format("<a href='/FileDown?file_name=%s&uuid=%s'> 파일 다운로드 </a><br>", encodedFilename, uuid);
					out.println(link);
				} catch (Exception e) {;;}				
			} // if  
		} //while
		out.flush();
	}// service

} // end class

UploadServlet.java

---

*파일 다운로드 

 

@Log4j2
@NoArgsConstructor

@WebServlet("/FileDown")
public class FileDownServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;
    
	@Override
	protected void service(HttpServletRequest req, HttpServletResponse res) 
			throws ServletException, IOException {
		log.trace("service(req, res) invoked.");
		
		req.setCharacterEncoding("utf8");
		
		// step1. 다운로드에 필요한 전송 파라미터 획득
		String file_name = req.getParameter("file_name");
		String uuid = req.getParameter("uuid");
		log.info("\t+ 1. file_name : {}", file_name); // 원본파일명
		log.info("\t+ 2. uuid : {}", uuid);           // 저장파일명
		
		// step2. 저장파일명을 이용해서, 파일데이터를 응답메시지의 Body에 Write.		
		String path = "C:/temp/upload/" + uuid; // 저장파일에 대한 절대경로
		
		@Cleanup
		FileInputStream fis = new FileInputStream(path);
		
		// step3. 다운로드할 대상 파일의 Mime Type 획득		
		ServletContext sc = req.getServletContext();
		String mimeType = sc.getMimeType(file_name);
		if (mimeType == null) {
			mimeType = "application/octet-stream";
		} // if
		
		// step4. 응답문서의 Content Type 헤더의 값을 Mime Type으로 지정 (***)
		res.setContentType(mimeType);
		
		// step5. 응답문서의 헤더영역에 아래의 새로운 헤더 추가 (***)
		// Content-Disposition : attachment; filename=원본파일명
		// 주의할 점 : 원본파일명은 ASCII (ISO-8859-1) 문자집합으로 인코딩해서 넣어야 함.
		String encodedFN = new String(file_name.getBytes("utf8"), "ISO-8859-1");
		res.setHeader("Content-Disposition", "attachment; filename=" + encodedFN );
		
		// step6. 저장파일명(uuid)을 이용하여, 파일데이터를 읽어 응답메시지 body에 write & send
		byte [] bagagi = new byte[100]; // 바가지 준비
		int readBytes = 0;              // 실제 한번 바가지로 읽어낸 바이트 수를 저장
		
		// 응답메시지의 body에 바이트 기반 출력스트림을 획득
		@Cleanup		
		ServletOutputStream sos = res.getOutputStream();
		
		while ((readBytes = fis.read(bagagi)) != -1) {        // -1 : EOF (End Of File)
			sos.write(bagagi, 0, readBytes);
		} // while
		
		sos.flush();
	}// service

} // end class


FileDownServlet.java

---

 

이제 JSP 들어갑니다

*
Servlet : Buisness Logic 수행 및 데이터 생산
JSP : 응답화면 만드는 것 (HTML 문서 생산)

<JSP 기본>
1. JSP == Servlet (JSP가 Servlet으로 변환됨)
2. JSP 기본태그 (JSP Scripting Tags)
   (HTML 문서의 원하는 위치에 Model 데이터를 injection하기 위해서)
3. JSP 내장객체
4. JSP 액션태그

<JSP 고급>
5. EL (Expression Language)
6. JSTL (JSP Standard Tag Libraries)

---

JSP 개요


JSP은 서블릿과 마찬가지로 동적인 웹 어플리케이션을 개발할 때 사용 가능한 웹 컴포넌트이다. 다음은 JSP 웹 컴포넌트의 특징을 정리한 것이다.

- 태그(tag)기반의 웹 컴포넌트로서 jsp 확장자를 갖는다. 
- 클라이언트의 요청에 의해서 동적으로 실행된다. 따라서 다양한 클라이언트 요구사항을 처리할 수 있다. 
- 클라이언트는 브라우저를 이용한 URL 지정을 통해서 JSP에 요청이 가능하다. 요청방법은 HTML 파일 요청방식과 동일하다.
- JSP의 응답결과는 HTML 형식으로 서비스된다. JSP의 대부분의 구성요소가 HTML과 같은 태그로 되어있기 때문에 서블릿과 비교해서 손쉽게 HTML 화면을 구성할 수 있다. 
- JSP는 자동으로 서블릿으로 변환되어 실행된다. 따라서 JSP가 서블릿이라고 해도 틀린 말이 아니다. 
- MVC 패턴의 View 역할로서 JSP가 사용된다. 

상위에 언급된 JSP의 특징을 반드시 숙지하고 간단한 JSP을 직접 작성하여 실행함으로써 JSP 생성 방법 및 동작 아키텍쳐를 이해해보기로 한다.