## 57. 파일 업로드 다루기 - multipart/form-data POST 요청 파라미터 인코딩
- apache.org의 라이브러리를 이용하여 multipart/form-data 파라미터를 다루는 방법
- Servlet API를 이용하여 multipart/form-data 파라미터를 다루는 방법
- 네이버클라우드 mysql DBMS 사용하기
BoardFormServlet.java
ㄴ 해당 코드 추가
=>
ㄴ 서버 Start
=>
=>
ㄴ 게시판 > 새 글 > 내용 입력 > [파일 선택] 선택
=>
ㄴ 이미지 1개 선택
=>
=>
=>
ㄴ 등록 선택 후 개발자도구의 Payload 탭에서 filename 전달됨을 확인
Charles Proxy 로 확인하기
ㄴ Charles Proxy 실행해두기
=>
=>
ㄴ 이미지 1개 선택
=>
ㄴ [등록] 선택
=>
=>
ㄴ Chales Proxy 에서 확인 시 boundary=---- ... 추가됨을 확인
=>
=>
여러개의 파일 업로드 하기 위한 라이브러리 추가
ㄴ [See All Projects] 선택
=>
ㄴ Commons 선택
=>
ㄴ FileUpload 선택
=>
ㄴ Documentation 확인을 위해 창 띄워두기
ㄴ commons-fileupload 1.5 선택
=>
ㄴ Gradle(short) 선택
=>
ㄴ [Copy to clipboard] 선택
=>
build.gradle
ㄴ 복사한 코드 build.gradle 스크립트 파일의 dependencies 에 붙여넣기
=>
ㄴ gradle 재설정
=>
ㄴ Refresh 해주기
=>
ㄴ 라이브러리 추가된 지 확인하기
=>
BoardFormServlet.java
ㄴ multiple 옵션 추가
=>
ㄴ 서버 Restart
=>
첨부 파일 여러개 선택하여 새 글 등록 시도
=>
ㄴ 이미지 여러 개 선택
=>
ㄴ 파일 2개 선택됨
ㄴ [등록] 선택
=>
=>
ㄴ 이전에 띄워둔 Documentation 이용
ㄴ User Guide 선택
=>
ㄴ 해당 코드 복사
=>
BoardAddServlet.java
=>
=>
BoardAddServlet.java
=>
=>
BoardAddServlet.java
ㄴ 예외 처리 필요
=>
BoardAddServlet.java
ㄴ try~catch 문을 통해 예외 던지기
=>
BoardAddServlet.java
ㄴ items -> parts 로 변경
ㄴ 각각의 파트에서 값을 꺼내도록 함
=>
BoardAddServlet.java
ㄴ Board 객체 생성을 위쪽으로 이동시킴
=>
BoardAddServlet.java
ㄴ 일반 데이터일 경우와 파일 데이터일 경우를 구분하여 값 꺼내기
=>
BoardAddServlet.java
ㄴ 파일 이름 확인하기위한 출력문 추가
=>
BoardAddServlet.java
ㄴ 해당 코드 제거
=>
BoardAddServlet.java
ㄴ 작성자 설정도 위쪽으로 올려주기
=>
BoardAddServlet.java
ㄴ 해당 코드 제거
=>
BoardAddServlet.java
ㄴ category -> board.getCategory() 로 변경해주기
=>
ㄴ 서버 Restart 해주기
=>
게시판 > 새 글 추가 시 첨부파일 첨부하도록 함
=>
=>
ㄴ [등록] 선택
=>
ㄴ 글 정상 등록 됨을 확인
=>
ㄴ 콘솔 확인 시 등록한 파일 이름 확인 가능
등록한 사진이 저장되도록 하기
ㄴ webapp 폴더에 upload 라는 이름의 폴더 생성
=>
ㄴ upload 라는 폴더에 board 라는 이름의 폴더 생성
=>
ㄴ 폴더가 비어있지 않도록 README.md 파일 추가해주기
=>
README.md
=>
ㄴ wtpwebapp > report-server 폴더에 upload 폴더 생성됨을 확인
BoardAddServlet.java
ㄴ 웹 애플리케이션 환경 정보를 알고 있는 객체를 꺼내고, 웹 애플리케이션 환경정보에 /upload/board 디렉토리의 실제 경로를 계산하여 추출하도록 함
=>
ㄴ 서버 Restart
=>
게시판 > 새 글 추가 시 첨부파일 첨부하도록 함
=>
=>
ㄴ [등록] 선택
=>
=>
ㄴ 실제 경로 알아내기
=>
BoardAddServlet.java
ㄴ uploadDir 출력은 주석 설정
ㄴ part.write(...) 코드 추가
=>
ㄴ java.io.File import 하기
=>
ㄴ 서버 Restart 해주기
=>
=>
ㄴ [등록] 선택
=>
ㄴ 배포 폴더에 사진 등록됨을 확인
파일 저장 시 사용할 이름 정해주기
BoardAddServlet.java
=>
ㄴ 서버 Restart 해주기
=>
=>
ㄴ [등록] 선택
=>
ㄴ 배포 폴더에 첨부한 사진이 randomUUID 값을 이용한 이름으로 저장됨
ㄴ 이제 사용하지 않으므로 Delete 해주기
ㄴ AttachedFile 이라는 이름의 클래스 생성하기
=>
AttachedFile.java
ㄴ 필드 생성 및 Getter/Setter 생성
=>
ㄴ [Select All] 선택
ㄴ [Generate] 선택
AttachedFile.java
ㄴ Serializable 구현해주기
ㄴ serialVersionUID 추가해주기
Board.java
=>
Board.java
=>
ㄴ Getter/Setter 추가해주기
BoardAddServlet.java
ㄴ AttachedFile 클래스의 객체들을 담을 수 있는 ArrayList인 attachedFiles를 생성
=>
BoardAddServlet.java
=>
BoardAddServlet.java
=>
BoardAddServlet.java
ㄴ board 객체에 attachedFiles라는 ArrayList<AttachedFile>을 설정하도록 함
BoardDao.java
ㄴ insertFiles 인터페이스 정의 추가
=>
MySQLBoardDao.java
ㄴ insertFiles 인터페이스 구현
=>
BoardDao.xml
ㄴ (1, 'a.gif'), (1, 'b.gif'), (1, 'c.gif') 을 foreach 문으로 구현
=>
BoardDao.xml
ㄴ collection: 순회할 컬렉션을 지정 (attachedFiles 리스트를 순회함)
ㄴ item: 순회 과정에서 현재 아이템을 담을 변수명을 지정 (file 변수에 AttachedFile 객체가 순차적으로 대입됨)
ㄴ separator: 아이템 간에 구분을 지정 (,로 각 아이템을 구분)
ㄴ (#{file.filePath}, #{no}) : 각 AttachedFile 객체의 filePath와 no 값을 MyBatis의 매개변수로 전달하기 위한 표현식
ㄴ MyBatis의 동적 SQL 기능을 활용하여 attachedFiles 리스트에 있는 첨부 파일 정보를 활용하여 SQL 쿼리를 동적으로 생성하고 실행하도록 함
BoardAddServlet.java
ㄴ board.getNo() 를 출력해보도록 함
=>
ㄴ 서버 Restart 해주기
=>
로그인 후 새 글 등록 (첨부파일 첨부)
=>
=>
ㄴ [등록] 선택
=>
=>
ㄴ 0 이 출력되므로 수정 필요
=>
BoardDao.xml
=>
BoardDao.xml
=>
BoardDao.xml
=>
BoardDao.xml
ㄴ useGeneratedKeys: 이 속성을 true로 설정하여 데이터베이스에서 자동으로 생성되는 키 값을 가져오도록 함
ㄴ keyColumn: 자동 생성된 키 값을 받을 컬럼의 이름을 지정 ("board_no" 컬럼을 사용하여 자동 생성된 키 값을 받음)
ㄴ keyProperty: 키 값을 저장할 객체의 프로퍼티 이름을 지정 (no라는 프로퍼티에 자동 생성된 키 값을 저장)
=> 데이터베이스에 INSERT 작업을 수행할 때 자동으로 생성된 키 값을 가져와서 board 객체의 no 프로퍼티에 저장하도록 함
ㄴ 서버 Restart 해주기
=>
ㄴ [등록] 선택
=>
ㄴ 23 이 출력되는 것을 확인
=>
BoardAddServlet.java
ㄴ 전과 후 비교를 위한 출력문
=>
서버 Restart 해주기
=>
=>
BoardAddServlet.java
=>
ㄴ 서버 Restart 해주기
=>
ㄴ [등록] 선택
=>
ㄴ mysql 을 실행한 터미널에서 확인 시 filepath 가 정상적으로 저장됨을 확인
상세보기 화면에서 이미지 출력하기
BoardDao.xml
ㄴ left outer join 이용
=> 앞쪽에 inner join 한 것을 다시 left outer join 하는 것
ㄴ f.board_file_no, f.filepath 추가해주기
=>
ㄴ 쿼리문을 잘 작성했는지 터미널에서 확인해보기
=>
BoardDao.xml
ㄴ <collection> 태그:
=> property: 매핑 결과를 저장할 객체의 프로퍼티 이름을 지정 (attachedFiles 리스트에 매핑 결과를 저장)
=> ofType: 컬렉션 내부의 요소 타입을 지정 (attachedFile 타입의 객체가 리스트에 포함됨)
ㄴ <id> 태그:
=> column: 데이터베이스 컬럼의 이름을 지정 ("board_file_no" 컬럼을 사용하여 AttachedFile 객체의 no 프로퍼티에 매핑함)
=> property: 매핑 결과를 저장할 객체의 프로퍼티 이름을 지정 (no 프로퍼티에 매핑 결과를 저장)
ㄴ <result> 태그:
=> column: 데이터베이스 컬럼의 이름을 지정 ("filepath" 컬럼을 사용하여 AttachedFile 객체의 filePath 프로퍼티에 매핑)
=> property: 매핑 결과를 저장할 객체의 프로퍼티 이름을 지정 (filePath 프로퍼티에 매핑 결과를 저장)
=> 데이터베이스에서 조회된 결과를 attachedFiles 리스트의 각 AttachedFile 객체에 매핑하여 저장하도록 함
ㄴ MyBatis는 이러한 설정을 통해 객체와 데이터베이스 간의 매핑을 유연하게 처리할 수 있도록 해줌
BoardDetailServlet.java
=>
ㄴ 서버 Restart 해주기
=>
ㄴ [등록] 선택
=>
ㄴ 오류 발생
=>
BoardDao.xml
ㄴ b. 을 추가해주도록 함
=>
ㄴ 서버 Restart 해주기
=>
=>
=>
BoardDetailServlet.java
ㄴ 상세보기에서 이미지가 출력되도록 html 수정
=>
ㄴ 서버 Restart 해주기
=>
이미지 링크 출력
=>
ㄴ 정상적으로 출력됨을 확인
이미지 출력
BoardDetailServlet.java
=>
ㄴ 서버 Restart 해주기
=>
ㄴ 이미지 정상적으로 출력됨을 확인