-
이미지업로드: inputStream,outputStream, cos.jar-MultipartRequestJAVA 2021. 7. 25. 14:43
이미지 업로드
form 에 enctype="multipart/form-data" 속성과 값을 지정해야 한다. ( 이번에 쓸 API 와 관련된 환경타입 ) 파일을 request.getParameter 하면 파일의 이름, 정보등이 텍스트형식으로 얻어진다.
파일 이름만 있으면 그 파일을 다운받거나 요청할 수 있기 때문이다.파일은 1. 파일저장 2. DB저장 의 두가지 방법이 있다. 파일 업로드를 위한 API 는 cos.jar 라고 검색해서 mavenpository 홈페이지에서 다운 또는 maven dependency 태그로 넣자
https://mvnrepository.com/artifact/servlets.com/cos/05Nov2002Servlet 책에서 library 에 tomcat안의 servlet API 를 경로 지정했던 이유는 eclipse 내에서 tomcat이 실행전이라 이 API 가 보이지 않자 미리부터 없다고 오류가 자꾸난다. ( 사실 실행될때 API 가 실행되기 때문에 문제는 없는데도 불구하고..)
그래서 수업시간에는 책처럼 경로를 지정하지 않고 그냥 maven 의 pom.xml 에 dependency 로 library를 다운받았다.
상대 form 에서 넘어온 파일을 저장할 폴더를 만든다. (upload 라는 이름으로 만들었다.) 그 폴더의 실제 경로를 찾아낸다(절대 경로로는 운영체제에 따라 C:// 가 없을 수도 있기 때문에 C://upload 라 하면 문제가 될 수 있다.)
request.getRealPath("폴더명")tomcat 에서는 tomcat 의 webapps 폴더안에 프로젝트를 복사해서 놓는데 upload폴더에 저장하는 로직을 구현해도
내가 만든 프로젝트 경로에 들어가면 없다.
왜냐하면 이는 tomcat이 가상 복제본으로 취급하여 사용하는 곳이고, 실제 경로에 저장했으니 실제 경로로 들어가보면 잘 되어 있다.
실제 경로란 eclipse 가 내가 만든 위치가 아닌 자기가 따로 정보폴더에 저장해놓은 곳이다.
>> input.html
<body> <form action="receive.jsp" method="post" enctype="multipart/form-data"> <h1>회원등록</h1> <!--기초내용 --> 성명 <input type = "text" name = "name" id="name"><br> 프로필<img src="images/sample.jpg" id="myimg"/><br> <input type="file" name="profile" id="myfile"/><br> 아이디 <input type="text" name="id" id="id" readonly="readonly"> <input type="button" onclick="아이디중복검사창을띄우다()" value="조회"><br> 패스워드 <input type="password" name="password" id="password1"/><br> <input type="submit" value="등록" /> </form> </body> <script> function 그림파일읽어출력하기(event){ var 그림파일 = event.target.files[0]; if(!그림파일.type.match('image.*')){ alert("그림파일을 선택해주세요."); return; } var 파일리더 = new FileReader(); 파일리더.onload = function(event2){ var myimg = document.querySelector("#myimg"); myimg.src = event2.currentTarget.result; } 파일리더.readAsDataURL(그림파일); } document.querySelector("#myfile").addEventListener("change",그림파일읽어출력하기,false); </script>
업로드한 파일 저장하기
다운받은 파일업로드관련 API 를 이용해보자 (cos.jar)1. 해당 API 의 클래스인 MultipartRequest 를 사용해야 한다. (form 의 환경타입이 multipart/form-data 인것 처럼 이름이 비슷) 2. MultipartRequest 를 생성할 때 생성자의 매개값에
1) 파일을 받아오는 request
2) 파일저장경로
3) 파일최대용량
4) 인코딩 방식
5) 중복된 이름의 파일이 존재시 처리 정책 ( DefaultFileRenamePolicy 클래스 이용 )3-1. 프로젝트에 폴더를 만들어 거기에 집어넣을 경우 실제경로를 알아내 거기에 넣는다. request.getRealPath() 로 얻어내기.
3-2. 폴더를 File 클래스의 mkdir() 메서드로 직접 만들 수 있으며 이 경로에 MultipartRequest 로 저장경로를 설정하여 저장할 수 있다.>> receive.jsp
<% String uploadPath = request.getRealPath("upload"); System.out.println(uploadPath); String folderPath = "D:\\dojihye\\testFolder"; File fileFolder = new File(folderPath); if (!fileFolder.exists()) { try{ fileFolder.mkdir(); //폴더 생성합니다. make directory System.out.println("폴더가 생성되었습니다."); } catch(Exception e){ e.getStackTrace(); } }else { System.out.println("이미 폴더가 생성되어 있습니다."); } try{ MultipartRequest 다중부분요청 = new MultipartRequest(request, folderPath, // 파일저장 경로 1024*1204*5,// 최대용량 "utf-8", // 업로드한 파일이 한글일 경우를 위해 인코딩 new DefaultFileRenamePolicy()); }catch(Exception e){ e.printStackTrace(); } %>
업로드한 파일 가져오기 1. 해당 API 의 클래스인 MultipartRequest 를 사용해야 한다. 2. 위처럼 파일을 폴더에 저장하기 위해 정보를 저장한 경우 getFile("input의name속성값"); 으로 얻어내기
// input 태그의 name 속성이 매개값이니 업로드 되는 당시의 파일을 가져오는 것.3. 마찬가지로 request를 얻은 상태이니 MultipartRequest 도 getParameter("태그name속성값") 로 파일외의 다른 요소를 가져올 수 있다. try{ MultipartRequest 다중부분요청 = new MultipartRequest(request, folderPath, // 파일저장 경로 1024*1204*5,// 최대용량 "utf-8", // 업로드한 파일이 한글일 경우를 위해 인코딩 new DefaultFileRenamePolicy()); File file = 다중부분요청.getFile("profile");//MultipartRequest 가 request 에게 파일의 정보를 가져와있으니 얘한테 파일을 얻어내는것. String name = 다중부분요청.getParameter("name");//파일이 아닌 텍스트부분도 request 를 가졌으니 가져올 수 있다. System.out.println(name); }catch(Exception e){ e.printStackTrace(); }
업로드한 파일 폴더에서 지우기 1. file 로 가져온 다음, File 클래스의 delete() 메서드를 사용하면 그 가져온 파일을 지운다.
(이번에 input 에 올린 파일이니 결국 upload 되지 않고 파일은 더이상 생기지 않는다.)try{ MultipartRequest 다중부분요청 = new MultipartRequest(request, folderPath, // 파일저장 경로 1024*1204*5,// 최대용량 "utf-8", // 업로드한 파일이 한글일 경우를 위해 인코딩 new DefaultFileRenamePolicy()); File file = 다중부분요청.getFile("profile");//MultipartRequest 가 request 에게 파일의 정보를 가져와있으니 얘한테 파일을 얻어내는것. file.delete(); }catch(Exception e){ e.printStackTrace(); }
업로드한 파일과 함께 회원table 에 넣어보기 1. 다른건 그대로 동일. 파일은 자바에서 Blob(java.sql) 또는 byte[] 형 둘다 가능하다.
Blob 는 byte의 모임이기 때문이다.2. PreparedStatement 에서 ? 에 인자를 넣을때도 setBlob() 또는 setBytes() 를 이용해 넣으면 된다. 3. VO 에 값을 넣어줘야 이 메서드로 찾기 가능한데, File 객체였으니 byte배열로 바꾸는 작업이 필요하다.
- 일단 file 크기만큼의 byte 배열을 만든다.
- 파일입력스트림으로 파일을 읽도록 생성자 매개변수에 넣는다. ( byte 기준 )
- 만들어놓은 file 크기의 byte 배열을 매개변수로 생성자에 넣었던 file 을 읽는다.
(읽은 파일은 매개값인 byte 배열에 들어간다.)4. 다 끝나면 입력스트림도 close() 하고 file 도 지워준다. 5. UploadDAO 의 메서드로 DB에 연결하여 작업을 수행한다. 유의사항. 아랫단에서 MultipartRequest 를 만들었다고 윗단에서 request.getParameter() 사용 불가하다.(정보가 get이 안된다.)
DAO의 메서드가 잘못됐을수도 있다.
<form method=post> 가 되어야한다. file은 get방식으로 출력불가하다.(파일의 글자수는 많을거같다)
<form enctype="multipart/form-data"> 여야 한다.>> UploadDAO.java
public void save(Upload upload) { try { Class.forName("com.mysql.cj.jdbc.Driver"); Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/uploaddb1?useUnicode=true","root","1234"); PreparedStatement st = c.prepareStatement("insert into tblupload(name,profile,id,password) values(?,?,?,?)"); st.setString(1, upload.getName()); st.setBytes(2, upload.getProfile()); st.setString(3, upload.getId()); st.setString(4, upload.getPassword()); st.executeUpdate(); st.close(); c.close(); } catch (Exception e) { e.printStackTrace(); } } // public Upload findByNo(int no) { Upload upload = null; try { Class.forName("com.mysql.cj.jdbc.Driver"); Connection c = DriverManager.getConnection("jdbc:mysql://localhost:3306/tblupload?useUnicode=true","root","1234"); PreparedStatement st = c.prepareStatement("select * from tblupload where no = ?"); st.setInt(1, no); ResultSet set = st.executeQuery(); if(set.next()) { upload = new Upload(); upload.setName(set.getString("name")); upload.setProfile(set.getBytes("profile")); upload.setId(set.getString("id")); upload.setPassword(set.getString("password")); } st.close(); c.close(); } catch (Exception e) { e.printStackTrace(); } return upload; }
>> receive.jsp
String folderPath = "D:\\dojihye\\testFolder"; if (!fileFolder.exists()) { try{ fileFolder.mkdir(); //폴더 생성합니다. make directory System.out.println("폴더가 생성되었습니다."); } catch(Exception e){ e.getStackTrace(); } }else { System.out.println("이미 폴더가 생성되어 있습니다."); } File fileFolder = new File(folderPath); try{ MultipartRequest 다중부분요청 = new MultipartRequest(request, folderPath, // 파일저장 경로 1024*1204*5,// 최대용량 "utf-8", // 업로드한 파일이 한글일 경우를 위해 인코딩 new DefaultFileRenamePolicy()); File file = 다중부분요청.getFile("profile");//MultipartRequest 가 request 에게 파일의 정보를 가져와있으니 얘한테 파일을 얻어내는것. String name = 다중부분요청.getParameter("name"); String id = 다중부분요청.getParameter("id"); String password = 다중부분요청.getParameter("password"); Upload upload = new Upload(); upload.setName(name); upload.setId(id); upload.setPassword(password); //file 에서 byte 배열로 byte[] profile = new byte[(int)file.length()]; //일단 file 크기만큼의 byte 배열을 만든다. FileInputStream 입력스트림 = new FileInputStream(file); 입력스트림.read(profile); 입력스트림.close(); file.delete(); upload.setProfile(profile); UploadDAO dao = new UploadDAO(); dao.save(upload); }catch(Exception e){ e.printStackTrace(); }
업로드한 파일과 함께 회원정보 출력하기 1. 회원을 DAO를 통해 찾고(회원번호매개로 찾는메서드) 그 회원의 profile 을 get한다. 2. 응답객체의 contentType 을 image/jpeg 형식으로 지정한다. 3. 지정한 형식으로 출력하기 위해 OutputStream 을 얻는다. (ServletOutputStream) 4. 전달받은 OutputStream 이 형식에 맞춰 작성(write) 한다. 결과값은 잘 나오나 계속 console창에 getOutputStream() 이 이미 호출되었다는 오류문구가 뜰 시
<%@ page trimDirectiveWhitespaces="true" %>
profile.jsp 윗단에 입력해주자. jsp 에서 나는 이상한 오류로 whitespace 로 인해 오류가 난 것이다. 이를 없애라는 명령어다.>> profile.jsp
<% // 바이너리로 응답 (html 응답) 모든 파일은 다 바이너리(byte)규격 이다. int no = Integer.valueOf(request.getParameter("no")); UploadDAO dao = new UploadDAO(); Upload upload = dao.findByNo(no); byte[] profile = upload.getProfile(); response.setContentType("image/jpeg"); ServletOutputStream os = response.getOutputStream(); os.write(profile); %>
>> detail.jsp
<body> <img src="profile.jsp?no=1" alt="" width="500px" height="500px"/> </body>
웹브라우저는 contentType="text/html; 가 default 값으로 지정되어 있다.
그래서 주소를 치면 기본적으로 html 을 먼저 찾는 것이다.
그렇기 때문에 순수하게 파일이나 이미지를 출력할 경우 contentType 을 바꾸어 출력하면 된다.
위의 profile.jsp 는 이제 contentType 이 image 이므로 detail.jsp 에서 해당주소로 image 의 src 지정이 가능하게 된 것이다.'JAVA' 카테고리의 다른 글
redirect, forward,spring 서두 (0) 2021.07.26 JSP: FrontController 직접 구현해보기 (0) 2021.07.26 ModelAndView (0) 2021.07.25 MVC 3 Tier,인터페이스정의서,AJAX-JSON사용,BLOB(image) (0) 2021.07.25 Servlet, 과도기 MVC (0) 2021.07.25