<!-- 파일 업로드 처리 --> <% //1. 파일 저장 위치 (가상경로) 만들기 // D:\workspace_jsp7\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\fileUpload/upload //System.out.println("가상경로 : "+request.getRealPath("/upload")); String uploadPath = request.getRealPath("/upload");
//2. 저장 크기 지정 (10MB) int maxSize = 10 * 1024 * 1024;
//3. 정보를 저장하는 변수 만들기 String name =""; String subject =""; String filename = ""; //서버에 올라갈 파일명 String OFilename = ""; //오리지널 파일명
//6. 예외처리 try{ //4. MultipartRequest 객체생성 //4-1. cos 라이브러리 추가 //4-2. 객체 생성 //request정보를 직접가져올 수 없고 multi를 통해서 가져올 수 있다. MultipartRequest multi = new MultipartRequest(request, uploadPath, maxSize, "UTF-8", new DefaultFileRenamePolicy());
//5. 파일업로드완료 //5-1. 전달되는 이름, 제목 저장 name = multi.getParameter("name"); subject = multi.getParameter("subject"); //5-2. 전달된 파일의 이름 확인 Enumeration files = multi.getFileNames(); //업캐스팅 String file1 = (String) files.nextElement(); //위의 업캐스팅한 걸 다운캐스팅 //5-3. 서버에 저장되는 파일 이름 filename = multi.getFilesystemName(file1); System.out.println("filename : "+filename); //5-4. 원래 파일이름 OFilename = multi.getOriginalFileName(file1); System.out.println("OFilename : "+OFilename); //여기까지 업로드 기능 구현 완료! => 6. 파일업로드는 예외가 많이때문에 예외처리를 해야한다 }catch(Exception e){ e.printStackTrace(); } %>
<!-- 데이터를 전달하기 enctype안적어도 될까? 업로드 유무로 판단! 업로드할꺼면 필요, 업로드하지않을거면 필요하지않다 아래처럼 input type을 text로 그냥 가져가면 중요한 정보들이 유출될 수있다. 보안을 위해 2가지 방법이 있다. 1안은 submit버튼사용 2안은 a태그사용한 방법이다. 편한 걸로하면되지만 보통 2안으로 많이한다 -->
MIME타입 : 클라이언트에게 전송되는 데이터(문서)를 다양하게 처리 가능하도록 하는 메커니즘 웹에서 파일의 확장자는 큰 의미가 없음(스트림형태로 데이터가 전달) -> 스트림형태일때는 데이터 구분못함. 따라서 각 데이터(문서)에서 올바른 형태의 데이터를 전달하도록 MIME 타입을 지정 브라우저들이 응답정보(리소스)를 받았을때 어떤 형태로 처리해야하는지 판단하는 기준 마임타입을 가져오는 방법은 getServletContext().getMimeType()으로 가능
브라우저에 따른 데이터 처리(대응)
왜 인터넷익스플로러를 기준으로 나눌까?
인터넷익스폴러는 다운로드시 한글파일이 깨짐 -> 따라서 파일을 인코딩해서 다운로드함
이때 공백문자가 플러스(+)기호로 나옴 -> 이걸 %20으로 변경
인터넷익스플로러인지 아닌지는 어떻게 구분할까?
접속한 사용자정보(User-Agent)를 불러와서 indexOf사용하여 MSIE이나 Trident이 들어가 있으면 익스플로러이다.
<%@pageimport="java.net.URLEncoder"%> <%@pageimport="javax.activation.MimeType"%> <%@pageimport="java.io.FileInputStream"%> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> <% //1. 전달받은 데이터 저장 String filename = request.getParameter("file_name"); System.out.println(" 전달된 파일 명 : "+filename);
//2. 파일 다운로드할 위치(= 파일 업로드 위치) =>가상경로 //savepath는 저장되는 폴더명 String savepath = "upload";
//3. 내 프로젝트 정보(ServletContext)안에서 가상경로를 실제경로로 계산해줘야한다. //3-1. 서버안에 있는 물리적 위치 확인 ServletContext context = getServletContext(); String DownloadPath = context.getRealPath(savepath); System.out.println("DownloadPath : "+DownloadPath); //3-2. 다운로드할 파일의 전체 경로 //역슬러시 두개는 이스케이프문자로서 역슬러시 1개만 표현됨 String FilePath = DownloadPath+"\\"+filename; //여기까지다운로드기능완료
//4. 데이터 응답처리를 다운로드 형태로 구현 //4-1. 파일을 한번에 처리하기위한 배열 byte[] b = newbyte[4069];
//4-2. 파일입출력을 처리하는 파일 입력 스트림 객체생성(즉, 파일을 읽어오는 통로만들기) FileInputStream fis = new FileInputStream(FilePath);
//4-3. 다운로드할 파일의 마임타입 확인(mime) //=> 클라이언트에게 전송되는 데이터(문서)를 다양하게 처리 가능하도록 하는 메커니즘 String MimeType = getServletContext().getMimeType(FilePath); System.out.println("Mime type: "+MimeType);
if(MimeType == null){ //기본값 지정 - 이진파일을 처리하기위한 기본타입 //-> 잘 알려지지 않은 파일을 의미하기때문에 //-> 브라우저는 보통 자동실행을 안하고 대화상자를 이용하여 사용자에게 실행할지 질문함 MimeType = "application/octet-stream"; }
//4-4내 응답정보를 마임타입으로 지정 response.setContentType(MimeType);
//5. 브라우저에 따른 데이터 처리(대응) //왜 인터넷익스플로러를 기준으로 나눌까? //인터넷익스폴러는 다운로드시 한글파일이 깨짐 -> 따라서 파일을 인코딩해서 다운로드함 //이때 공백문자가 플러스(+)기호로 나옴 -> 이걸 %20(공백)으로 변경
//6. 데이터다운로드 처리 //브라우저가 응답정보를 읽어서(해석) 처리시 //"Content-Disposition" 설정값이 "attachment;" 모든 데이터 다운로드 처리 response.setHeader("Content-Disposition", "attachment; filename="+filename);
//7. 데이터출력(다운로드) ServletOutputStream out2 = response.getOutputStream(); //7-1. 데이터출력 통로 생성 int data = 0; while((data = fis.read(b,0,b.length)) != -1){ //데이터출력시 파일이 있을동안 계속 진행 out2.write(b,0,data); //배열에다가 data를 담아서 출력 out2.flush(); } //8. 자원해제
out2.close(); fis.close();
//9. java.lang.IllegalStateException: //이 응답을 위해 getOutputStream()이 이미 호출되었습니다. // => JSP->Servlet 변환시 out 객체가 자동생성, 추가로 OutputStream 객체 생성시 // 오류 메세지 출력( 다운로드 문제 X, 서버에 에러 메세지 로그 쌓임)
out.clear(); out = pageContext.pushBody(); %>
5-1. java.lang.IllegalStateException에러
java.lang.IllegalStateException: 이 응답을 위해 getOutputStream()이 이미 호출되었습니다.
jsp가 실행될때 java파일로 변환되어 실행되고 그 바뀌는 걸 servlet이라고 한다. 이 변환시에 out이라는 객체가 자동 생성된다. 만약 추가로 OutputStream 객체생성시 IllegalStateException에러가 발생한다.
다운로드기능에는 문제가 없으나 에러가 실행될때마다 서버에 에러 메세지 로그 쌓이기때문에 처리해야한다.
<% //1. 전달되는 데이터 인코딩 request.setCharacterEncoding("euc-kr");
//2. 업로드 폴더 지정(절대경로 = 파일을 직접적으로 접근하는 방식) String savePath = "d:\\upfile";
//3. 업로드 파일 크기 => 10MB int maxSize = 10 * 1024 * 1024;
//4. 파일 이름 저장하는 변수 생성 String fileName=""; String originalFileName="";
//5. 예외처리 포함한 파일업로드 try{ MultipartRequest multi = new MultipartRequest(request, savePath, maxSize, "euc-kr", new DefaultFileRenamePolicy()); //여기까지 파일업로드완료 //6. 파일업로드 결과를 화면에 출력 //6-1. 폼의 이름 반환 Enumeration formNames = multi.getFileNames(); //업캐스팅 //6-2. 전달된 파일의 정보를 저장 String formname = (String) formNames.nextElement(); //위의 업캐스팅한 걸 다운캐스팅 //7. 서버에 저장된 파일의 이름저장 fileName = multi.getFilesystemName(formname); //8. 원래 파일의 이름 저장 originalFileName = multi.getOriginalFileName(formname); //9.파일업로드 성공시 해당 정보 출력 if(fileName == null){ out.println("파일업로드 실패!"); }else{ out.print("업로드한 사람 : "+multi.getParameter("name") +"<br>업로드 파일이름(서버저장) : "+fileName+"<br>업로드 파일이름(원본): "+originalFileName +"<br>file태그정보 : "+formname); } }catch(Exception e){ out.println("파일업로드 중 예외상황발생"); e.printStackTrace(); } %> <fieldset> <form method="post" name="myform"> <input type="text" name="filename" value="<%=fileName%>"> //onclick에 function을 넣어도 되고 location.href넣어도 동일한 결과 출력 <input type="button" value="파일삭제" onclick="delfile()"> <input type="button" value="파일삭제" onclick="location.href='./delup.jsp'"> <input type="button" value="파일다운로드"> </form> </fieldset>
4. delup.jsp 생성
한글파일빼고는 삭제가 잘 진행된다. 인코딩방식의 문제이므로 나중에 처리하기로한다
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<% //1. 전달된 파일 이름 저장 String filename = request.getParameter("filename");
//2. 파일 객체 생성 -> 삭제 //File f = new File("해당파일의 위치+파일명"); //객체를 만든 순간 = 해당 폴더로 이동해서 파일을 선택한 상황임. File f = new File("D:\\upfile/"+filename);
//3. 파일삭제 f.delete(); out.println("파일삭제완료");
//3-1. 한글파일빼고는 삭제가 잘 진행된다. out.println(filename); %>
<%@pageimport="java.io.FileNotFoundException"%> <%@pageimport="java.io.FileInputStream"%> <%@pageimport="java.io.File"%> <%@pageimport="java.io.OutputStream"%> <%@pageimport="java.io.InputStream"%> <%@ page language="java" contentType="text/html; charset=euc-kr" pageEncoding="euc-kr"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=euc-kr"> <title>Insert title here</title> </head> <body> <h2>다운로드페이지</h2> <% //1. 인코딩 //string은 그냥 담아도 (=String filename=request.getParameter("filename"))되고 객체에 담아도된다 //String filename= new String(request.getParameter("filename")); //파라미터 데이터를 가져와서 8859_1 인코딩방식으로 바꾼 뒤 EUC-KR로 한번 더 바꾸는 것 String filename = new String((request.getParameter("filename")).getBytes("8859_1"),"euc-kr");
//2. 파일저장경로(절대경로) String filePath = "D:/upfile";
//3. 입출력시 필요한 객체 생성 InputStream in = null; OutputStream os = null; File file = null; File viewFile = null;
// 4. 예외처리 try{ //5. 변수생성 : 인코딩시 변경되는 string 따로 저장하려고 3개 변수 만듬 String fname1 = ""; String fname2 = ""; String fname = ""; fname = filename; fname1 = new String(fname.getBytes("8859_1"), "euc-kr"); //9. try catch구문으로 묶기 try{ //6. 전달된 파일 경로,이름 사용해서 파일 객체 생성 file = new File(filePath, fname); viewFile = new File(filePath,fname1); //확인차 페이지에 출력 out.print("file : "+file+"<br>"); out.print("viewfile : "+viewFile); //8. 파일을 읽어오기 위해서 입력 통로를 생성 // 객체를 만든 순간 = 해당 폴더로 이동해서 파일을 선택한 상황임. // InputStream in = null; in = new FileInputStream(file); //업캐스팅 }catch(FileNotFoundException e){ skip = true; } //10. String변수만들어주기 fname2 = new String(fname1.getBytes("euc-kr"), "8859_1"); //11. 응답객체초기화 for 다운로드 팝업창 생성된 것처럼 보이게끔하여 다운로드 진행중임을 표시 response.reset();
//6. 파일의 정보 + 글 정보를 디비에 저장 //6-1. 글정보저장하는 객체생성 BoardBean bb = new BoardBean(); //6-2. 전달되는 정보 저장 // bb.setName(request.getParameter("name")); enctype과 함께 쓸 수없다 bb.setName(multi.getParameter("name")); bb.setPw(multi.getParameter("pw")); bb.setSubject(multi.getParameter("subject")); bb.setContent(multi.getParameter("content"));
// bb.setFile(multi.getParameter("file")); //DB에 파일저장 불가->아래코드로 진행 bb.setFile(multi.getFilesystemName("file")); System.out.println("upfile에 저장된 파일명 : "+multi.getFilesystemName("file")); System.out.println("사용자가 올린 원본 파일명 : "+multi.getOriginalFileName("file"));
//6-3. 따로 저장한 정보 저장 bb.setIp(request.getRemoteAddr());
//7. boardDAO객체생성 BoardDAO bdao = new BoardDAO();
//8. 글쓰기 메서드 호출 bdao.insertBoard(bb);
//9. 목록페이지로 이동 response.sendRedirect("boardList.jsp");
DB에도 잘 들어가는 걸 확인할 수 있다. 동일한 페이지 두번 작성하면 upfile에 저장된 파일명은 자동적으로 뒤에 숫자가 붙어 고유한 파일명으로 업로드가능하다.