JSP 10강 - FileUpload2

voilà!·2022년 1월 16일
0

JSP 스프링

목록 보기
10/31

1. 파일 업로드란?

  • 웹 브라우저(크롬)에서 서버(톰캣포함)로 파일을 전송하여 서버에 저장하는 것
  • 웹 브라우저에서 서버로 파일을 전송하기 위해 JSP 페이지에 폼 태그를 사용
  • 전송된 파일을 서버에 저장하기 위해 오픈 라이브러리(common-fileupload, cos.jar)를 이용함

addProduct.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="/css/bootstrap.min.css">
<script type="text/javascript" src="/ckeditor/ckeditor.js"></script>
<script type="text/javascript" src="/js/validation.js"></script>
<title>상품 등록</title>
</head>
<body>
<!-- top 인클루드 시작 -->
	<jsp:include page="/ch03/top.jsp" />
<!-- top 인클루드 끝 -->

<!-- content 시작 -->
	<div class="jumbotron">
		<div class="container">
			<h1 class="display-3">상품 등록</h1>
		</div>
	</div>
	<div class="container">
	<!-- addProduct_process.jsp : common-fileupload -->
	<!-- addProduct_process2.jsp : cos.jar -->
		<form name="newProduct" action="addProduct_process2.jsp" 
			method="post" class="form-horizontal" enctype="multipart/form-data">
			<div class="form-group row">
				<label class="col-sm-2">상품 코드</label>
				<div class="col-sm-3">
					<input type="text" name="productId" id="productId"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">상품명</label>
				<div class="col-sm-3">
					<input type="text" name="pname" id="pname"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">가격</label>
				<div class="col-sm-3">
					<input type="text" name="uniPrice" id="uniPrice"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">상세정보</label>
				<div class="col-sm-5">
					<textarea name="description" rows="2" cols="50" class="form-control"></textarea>
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">제조사</label>
				<div class="col-sm-3">
					<input type="text" name="manufacturer"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">분류</label>
				<div class="col-sm-3">
					<input type="text" name="category"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">재고 수</label>
				<div class="col-sm-3">
					<input type="text" name="unitsInStock" id="unitsInStock"
						class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<label class="col-sm-2">상태</label>
				<div class="col-sm-5">
					<input type="radio" name="condition" id="condition1" value="new" />
						<label for="condition1">신규 제품</label>
					<input type="radio" name="condition" id="condition2" value="old" />
						<label for="condition2">중고 제품</label>
					<input type="radio" name="condition" id="condition3" value="Refurbished" />
						<label for="condition3">재생 제품</label>
				</div>
			</div>
<!-- 			<div class="form-group row">
				<label class="col-sm-2">이미지</label>
				<div class="col-sm-5">
					<input type="file" name="productImage" class="form-control" />
				</div>
			</div> -->
			<div class="form-group row">
				<label class="col-sm-2">이미지(cos.jar)</label>
				<div class="col-sm-5">
					<input type="file" name="productImage2" class="form-control" />
				</div>
			</div>
			<div class="form-group row">
				<div class="col-sm-offset-2 col-sm-10">
					<input type="button" class="btn btn-primary" value="등록" onclick="CheckAddProduct()"/>
				</div>
			
			</div>
		</form>	
	</div>
<!-- content 끝 -->
<script type="text/javascript">
CKEDITOR.replace("description");
</script>

<!-- bottom 인클루드 시작 -->
	<jsp:include page="/ch03/bottom.jsp" />
<!-- bottom 인클루드 끝 -->
</body>
</html>

2. cos.jar

  • cos.jar의 핵심 클래스는 MultipartRequest이다.
  • MultipartRequest 클래스를 통해 객체를 생성하고 해당 객체의 메소드들을 활용하여 웹 브라우저(크롬)가 전송한 multipart/form-data 유형의 요청 파라미터를 읽어오고 파일을 업로드 함

cos.jar 추가하기

http://servlets.com/cos/ 접속
하단 다운로드 - cos-20.08.zip 다운
압축풀고 cos.jar WEB-INF에 복붙
톰캣이 있는 D:\B_Util\5.ApacheTomcat\apache-tomcat-8.5.37\lib 에도 넣기

D:\B_Util\2.Java\JDK1.8\lib에도 넣기
JSPBOOK properties 에서 java buid path - add External jars - 받은 jar 파일 넣고 apply

addProduct_process2.jsp

<%@page import="dto.Product"%>
<%@page import="ch04.com.dao.ProductRepository"%>
<%@page import="java.util.Enumeration"%>
<%@page import="com.oreilly.servlet.multipart.DefaultFileRenamePolicy"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ page import="com.oreilly.servlet.MultipartRequest"%>
<!DOCTYPE html>
<html>
<head>
<title>cos.jar를 통한 파일 업로드</title>
</head>
<body>

<%
	request.setCharacterEncoding("UTF-8");
	//웹 어플리케이션상의 절대 경로
	String realFolder = "D:\\A_TeachingMaterial\\6.JspSpring\\workspace\\JSPBook\\WebContent\\upload";
	
	String filename="";

	//최대 업로드될 파일의 크기 5MB
	int maxSize = 5*1024*1024;
	
	//인코딩 유형
	String encType = "UTF-8";
	
	//cos.jar 라이브러리의 핵심 클래스
	MultipartRequest multi = new MultipartRequest(
			request, realFolder, maxSize, encType, new DefaultFileRenamePolicy()
			);
	
	//폼 데이터 처리
	String productId = multi.getParameter("productId");
	String pname = multi.getParameter("pname");
	String uniPrice = multi.getParameter("uniPrice");
	String description = multi.getParameter("description");
	String manufacturer = multi.getParameter("manufacturer");
	String category = multi.getParameter("category");
	String unitsInStock = multi.getParameter("unitsInStock");
	String condition = multi.getParameter("condition");
	
	Integer price;
	if(uniPrice.isEmpty()){
		price = 0;
	}else{
		//uniPrice 형변환
		price = Integer.valueOf(uniPrice);
	}
	
	long stock;
	if(unitsInStock.isEmpty()){
		stock = 0;
	}else{
		//unitsInStock 형변환
		stock = Long.valueOf(unitsInStock);
	}
	
	//파일객체 처리
	//multi객체 안에는 request 객체가 들어있고, request객체 안에는 파일 객체가 있음
	Enumeration files = multi.getFileNames();
	//productImage2
	String fname = (String)files.nextElement();
	//폼 페이지에서 전송되어 서버에 업로드된 파일을 가져옴
	String fileName = multi.getFilesystemName(fname);
	
	out.print("fname : " + fname + ", fileName : " + fileName);
	
	//싱글톤패턴
	ProductRepository dao =  ProductRepository.getInstance();
	
	Product newProduct = new Product();
	newProduct.setProductId(productId);
	newProduct.setPname(pname);
	newProduct.setUniPrice(price);
	newProduct.setDescription(description);
	newProduct.setManufacturer(manufacturer);
	newProduct.setUnitsInStock(stock);
	newProduct.setCondition(condition);
	
	//파일 객체의 파일명(fileName : P1237.jpg)
	newProduct.setFilename(fileName);
	//dao : data access object(여기서는 메모리 DB라고 생각)
	dao.addProduct(newProduct);
	//상품 목록으로 리다이렉트
	response.sendRedirect("products.jsp");
%>


</body>
</html>

3. Commons-FileUpload

  • 먼저 Commons-FileUpload 패키지에 포함되어 있는 DiskFileUpload 클래스를 통해 객체를 생성
  • 생성된 객체의 메소드들을 사용하여 웹 브라우저가 전송한 multipart/form-data 유형의 요청 파라미터를 가져옴
  • FileItem 클래스의 메소드를 사용하여 요청 파라미터가 일반 데이터인지 파일인지 분석 및 처리하여 파일을 업로드 함

addProduct_process.jsp

<%@page import="java.io.File"%>
<%@page import="org.apache.commons.fileupload.FileItem"%>
<%@page import="java.util.Iterator"%>
<%@page import="java.util.List"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 
<%@ page import="org.apache.commons.fileupload.DiskFileUpload"%>
<%@ page import="dto.Product"%>
<%@ page import="ch04.com.dao.ProductRepository"%>
<%
//1. request 객체의 인코딩을 UTF-8로 설정
	request.setCharacterEncoding("UTF-8");

//0. 파일 업로드 처리(productImage)
	//파일 저장 임시 경로 & 실제로 저장될 위치 => /upload/...jpg
	String path = "D:\\A_TeachingMaterial\\6.JspSpring\\workspace\\JSPBook\\WebContent\\upload";
	
	//DiskFileUpload 클래스(commons.fileupload 라이브러리에서 제공해줌)
	DiskFileUpload upload = new DiskFileUpload();
	//5M까지 업로드 가능
	upload.setSizeMax(5000000);
	//버퍼 메모리 4Kbytes
	upload.setSizeThreshold(4096);
	//임시 저장  경로
	upload.setRepositoryPath(path);
	//upload객체가 jsp 기본 객체인 request 객체에 담긴 파라미터 데이터들을 파싱(구문 + 의미 분석)
	//목록화
	List items = upload.parseRequest(request);
	//List를 Iterator로 바꿔줌(왜? 약속)
	Iterator params = items.iterator();
	
	//상품 객체(신규 상품을 등록하기 위해 빈그릇을 준비. 자바빈 클래스)
	Product newProduct = new Product();
	//enctype="multipart/form-data"를 쓰는 순간 request.getParameter는 사용 불가
	//그래서 변수 선언만 해놓음
	String productId = "";
	String pname = "";
	String uniPrice = "";
	String description = "";
	String manufacturer = "";
	String category = "";
	String unitsInStock = "";
	String condition = "";
	
	//전송된 요청 파라미터가 없을 때까지 반복. Iterator 객체 타입의 hasNext() 메소드 사용.
	while(params.hasNext()){
		//전송된 요청 파라미터의 이름을 가져옴
		FileItem item = (FileItem)params.next();
		
		if(item.isFormField()){//파라미터가 파일이 아니라면..
			//input type="text" name="productId" ==> productId
			String name = item.getFieldName();		
					
			if(name.equals("productId")){		
				productId = item.getString("UTF-8");
			}else if(name.equals("pname")){
				pname = item.getString("UTF-8");
			}else if(name.equals("uniPrice")){
				uniPrice = item.getString("UTF-8");
			}else if(name.equals("description")){
				description = item.getString("UTF-8");
			}else if(name.equals("manufacturer")){
				manufacturer = item.getString("UTF-8");
			}else if(name.equals("category")){
				category = item.getString("UTF-8");
			}else if(name.equals("unitsInStock")){
				unitsInStock = item.getString("UTF-8");
			}else if(name.equals("condition")){
				condition = item.getString("UTF-8");
			}
		}else{//파라미터가 파일이라면..
			//<input type="file" name="productImage" -> productImage
			String fileFieldName = item.getFieldName();
			//실제 파일명 ex) P1237.jpg
			String fileName = item.getName();
			//파일의 MIME 타입 ex) ../jpeg
			String contentType = item.getContentType();
			//물리 경로(P1237.jpg) -> 파일명(P1237.jpg)만 남김
			//IE(C:\Users\PC-12\Downloads\P1237.jpg) -> P1237.jpg
			fileName.substring(fileName.lastIndexOf("\\") +1);
			//파일 저장을 위한 설계(파일객체)
			//"D:\\A_TeachingMaterial\\6.JspSpring\\workspace\\JSPBook\\WebContent\\upload"
			// /P1237.jpg
			File file = new File(path + "/" + fileName);
			//파일 저장
			item.write(file);
			//결과 출력
			out.print("저장 파일 이름 : " + fileName + "<br>");
			//상품 객체의 filename 멤버변수에 파일명을 세팅
			newProduct.setFilename(fileName);
		}
		
	}

//2. 파라미터 목록을 받자
	//uniPrice : "10000"
	Integer price;
	if(uniPrice.isEmpty()){
		price = 0;
	}else{
		//uniPrice 형변환 "10000" -> 10000
		price = Integer.valueOf(uniPrice);
	}
	
	long stock;
	if(unitsInStock.isEmpty()){
		stock = 0;
	}else{
		//unitsInStock 형변환
		stock = Long.valueOf(unitsInStock);
	}
	
//3. ProductRepository 클래스의 인스턴스 생성(싱글톤 패턴 -> 단 한번 생성 -> 하나의 객체를 서로 공유)
	//new 로 객체 생성 시 메모리 과부하 --> ProductRepository클래스에서 싱글톤 만들기	
	//ProductRepository dao = new ProductRepository();
	
	//상품 객체의 모든 멤버변수에 세팅
	ProductRepository dao = ProductRepository.getInstance();
	
	newProduct.setProductId(productId);
	newProduct.setPname(pname);
	//위에서 만든 price 변수 넣기
	newProduct.setUniPrice(price);
	newProduct.setDescription(description);
	newProduct.setManufacturer(manufacturer);
	newProduct.setCategory(category);
	//위에서 만든 stock 변수 넣기
	newProduct.setUnitsInStock(stock);
	newProduct.setCondition(condition);
	
	out.print("newProduct : " + newProduct.toString());

//4. 상품을 추가하자
	dao.addProduct(newProduct);
	
//5. 상품목록(products.jsp)으로 돌아가자.
	response.sendRedirect("products.jsp");

%>

0개의 댓글