일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 스프링 쇼핑몰
- 이미지 출력
- spring 쇼핑몰
- BCrypt 적용
- 스프링 프로젝트 설정
- 로그인 기능
- 스프링 업로드
- 스프링 게시판
- Bcrypt
- 정규표현식
- 스프링 파일 삭제
- 쇼핑몰 포트폴리오
- 스프링 쇼핑몰 프로젝트
- 스프링 메일 전송
- 회원가입 기능
- 로그아웃 기능 구현
- 스프링 HikariCP
- 인증번호 전송
- 삭제 구현
- ResponseEntity
- oracle 설치방법
- 쇼핑몰 프로젝트
- 파일 업로드
- 스프링 게시판 구현
- 스프링 이미지
- spring 프로젝트
- 스프링 포트폴리오
- 스프링 프로젝트 기본 설정
- 스프링 프로젝트
- arraylist
- Today
- Total
Kim VamPa
[Spring][쇼핑몰 프로젝트][25] 업로드 이미지 출력 -1 본문
프로젝트 Github : https://github.com/sjinjin7/Blog_Project
프로젝트 포스팅 색인(index) : https://kimvampa.tistory.com/188
목표
업로드 이미지 출력 구현
이번 포스팅부터는 비동기 방식으로 url을 호출하면 이미지를 반환해주는 url 매핑 메서드를 구현할 것입니다. 이 메서드는 저번 포스팅에 이어서 구현해야 할 상품 등록 페이지에서의 미리 보기 이미지뿐만 아니라 앞으로 사용자가 검색을 하였을 때 볼 수 있는 이미지들을 출력하는데도 사용될 것입니다.
순서
1. 전체적 방향
2. url 매핑 메서드 작성 및 File 객체 생성
3. 'Content Type' 명시 & 데이터 파일 반환
4. 테스트
1. 전체적 방향
이번에 구현할 url 메서드의 경우 '파일 경로(유동 경로)' + '파일 이름" 데이터를 파라미터로 전달받고, 해당 데이터에 맞는 이미지 파일을 찾아서 뷰에 이미지 데이터를 전송 하도록 할 것입니다.
가장 먼저 생각 해볼 사항은 이미지는 어떠한 데이터 타입으로 주고받을 수 있는가입니다. 먼저 결론부터 말하자면 이미지 파일을 주고받기 위한 데이터 타입은 byte 배열(byte [])입니다.
이미지 파일은 바이너리(binary) 파일 범주에 들어갑니다. 바이너리 파일이란 쉽게 말해 이진 데이터 인데 0과 1로만 구성된 데이터인데, 테스트(text) 파일을 제외 한 모든 파일을 지칭합니다. 이러한 바이너리 파일(데이터를) 주고받을 때 바이트(혹은 옥텟(octet)) 단위로 데이터를 주고받습니다. 그렇기 때문에 이미지 파일을 주고받기 위해서는 byte 배열 타입을 사용해야 합니다.
※ 1byte = 8bit
그 다음 고려할 사항은 url 메핑 메서드의 반환 타입입니다. 현재 구현할 메서드의 경우 화면의 이동 없이 특정 데이터를 반환하는 것을 목표로 하기 때문에 비동기 방식의 url 메핑 메서드를 구현해야 합니다. 따라서 @ResponseBody 어노테이션과 Responseentity 객체 두 가지 선택 사항이 있습니다.
이전 포스팅에서도 설명을 했지만 다시 한번 간략히 설명을 하면 두 가지 모두 경우 http response 메시지의 body에 데이터를 첨부한다는 점은 동일하지만, ResponseEntity의 경우 http response 메시지의 header와 status(상태 코드)를 조작할 수 있다는 차이점이 있습니다.
저는 ResponseEntity를 사용하고자 합니다. 그 이유는 response 메시지의 body에 이미지 데이터(byte 배열)을 전송할 것인데, 해당 데이터의 타입(header의 'content-type')이 이미지 파일임을 명확히 명시해주기 위해서입니다.
이미지 출력 메서드를 어떠한 방식으로 구현할지를 정리하면 파라미터로 전달받은 '파일 경로'와 '파일 이름'을 활용하여 대상 이미지 파일을 File 객체로 생성을 합니다. 해당 File 객체를 활용하여 MIME TYPE에 대한 정보를 알아냅니다. ResponseEntity에 대상 이미지 데이터를 복사하여 body에 추가해주고, header의 'Content Type'에 앞서 얻어낸 MIME TYPE으로 수정 해준 후 ResponseEntity 객체를 호출한 뷰(view)로 전송해줍니다.
2. URL 매핑 메서드 작성 및 File 객체 생성
이미지 데이터를 전달해주는 매핑 메서드 선언부를 추가해주겠습니다. 지금 현재 관리자 관련 기능들을 구현을 하고 있어서 AdminController에 추가해주어야 한다고 생각을 할 수 있습니다. 하지만 AdminController에 접근하기 위해선 관리자 계정이 아닐 시 접근을 하지 못하도록 설정을 한 Interceptor 필터를 거쳐야 하기 때문에 접근을 하는데 제한이 있습니다. 이미지는 로그인을 하든 안 하든 모든 곳에서 접근이 가능해야 하기 때문에 BookController.java 에 작성을 하겠습니다.
BookController.java 에 아래와 같이 url 매핑 메서드를 작성합니다.
@GetMapping("/display")
public ResponseEntity<byte[]> getImage(String fileName){
}
반환 타입은 앞서 말했듯이 ResponseEntity 객체를 통해 body에 byte [] 데이터를 보내야 하기 대문에 ResponseEntity<byte[]>를 반환 타입으로 작성하였습니다.
파라미터의 경우 '파일 경로' + '파일 이름'을 전달받아야 하기 때문에 String 타입의 fileName 변수를 파라미터로 부여하였습니다.
url의 경로를 통해 변수와 변수 값을 부여할 수 있도록 GetMapping 어노테이션을 사용하였습니다.
기본 경로 문자열 데이터와 전달받은 '유동 경로' + '파일 이름'을 활용하여 File 객체를 생성해주고 File 타입의 참조 변수에 대입합니다.
File file = new File("c:\\upload\\" + fileName);
"c:\upload\"가 아닌 "c:\\upload\\"을 작성한 이유는 특수 문자'\'을 인식할 수 있도록 이스케이프 문자를 사용한 것입니다.
3. 'Content Type' 명시 & 데이터 파일 반환
ResponseEntity에 Response의 header에 대한 설정을 추가해주기 위해 아래의 생성자를 사용할 것입니다.
ResponseEntity(T body, MultiValueMap<String,String> headers, HttpStatus status)
첫 번째 파라미터는 body에 첨부할 데이터를 추가합니다. 두 번째 파라미터의 경우 header의 설정이 부여된 객체를 추가합니다. MultiValueMap 클래스 타입이어야 한다고 명시되어 있는데 MultiValueMap 클래스를 상속한 HttpHeader 클래스를 사용할 것입니다. 세 번째 클래스의 경우 전송하고자 하는 상태 코드와 관련된 코드를 추가해 줄 것입니다.
뷰로 반환할 ResponseEntity 객체의 주소를 저장할 참조 변수를 선언하고 null로 초기화합니다.
ResponseEntity<byte[]> result = null;
대상 이미지 파일의 MIME TYPE을 얻기 위해 이전 포스팅에서 사용한 Files 클래스의 proveContentType() 메서드를 사용할 것입니다. 해당 메서드의 경우 IOException을 일으킬 가능성이 큰 메서드이기 때문에 try catch문을 작성해주어야 합니다. 따라서 try catch문을 추가해줍니다.
ResponseEntity<byte[]> result = null;
try {
}catch (IOException e) {
e.printStackTrace();
}
ResponseEntity에 Response의 header와 관련된 설정의 객체를 추가해주기 위해서 HttpHeaders를 인스턴스화 한 후 참조 변수를 선언하여 대입합니다.
ResponseEntity<byte[]> result = null;
try {
HttpHeaders header = new HttpHeaders();
}catch (IOException e) {
e.printStackTrace();
}
header의 'Content Type' 속성 값에 이미지 파일 MIME TYPE을 추가해주기 위해서 HttpHeader 클래스에 있는 add() 메서드를 사용해 줄 것입니다.
add() 메서드의 첫 번째 파라미터에는 Response header의 '속성명'을, 두 번째 파라미터에는 해당 '속성명'에 부여할 값(value)을 삽입하면 됩니다.
header의 'Content Type'에 대상 파일의 MIME TYPE을 부여해주는 코드를 추가해줍니다.
ResponseEntity<byte[]> result = null;
try {
HttpHeaders header = new HttpHeaders();
header.add("Content-type", Files.probeContentType(file.toPath()));
}catch (IOException e) {
e.printStackTrace();
}
대상 이미지 파일, header 객체, 상태 코드를 인자 값으로 부여한 생성자를 통해 ResponseEntity 객체를 생성하여 앞서 선언한 ResponseEntity 참조 변수에 대입합니다.
ResponseEntity<byte[]> result = null;
try {
HttpHeaders header = new HttpHeaders();
header.add("Content-type", Files.probeContentType(file.toPath()));
result = new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), header, HttpStatus.OK);
}catch (IOException e) {
e.printStackTrace();
}
첫 번째 파라미터는 출력시킬 대상 이미지 데이터 파일이라고 말을 하였는데 FilesCopyUtils.copyToByteArray(file) 코드를 작성하였습니다.
FileCopyUtils 클래스는 파일과 stream 복사에 사용할 수 있는 메서드를 제공하는 클래스입니다. 해당 클래스 중 copyToByteArray() 메서드는 파라미터로 부여하는 File 객체 즉, 대상 파일을 복사하여 Byte 배열로 반환해주는 클래스입니다.
두 번째 파라미터는 'Content-Type' 속성을 지정 해준 HttpHeader 객체(변수 header)를 인자로 부여하였습니다.
세 번째 파라미터는 성공 상태(status) 코드 200이 전송되도록 인자 값을 작성하였습니다.
url 매핑 메서드의 return에 생성한 ResponseEntity 객체(변수 result)를 작성해줍니다.
ResponseEntity<byte[]> result = null;
try {
HttpHeaders header = new HttpHeaders();
header.add("Content-type", Files.probeContentType(file.toPath()));
result = new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), header, HttpStatus.OK);
}catch (IOException e) {
e.printStackTrace();
}
return result;
4. 테스트
실제로 이미지가 잘 출력되는지 서버를 구동시켜서 확인을 해보겠습니다.
테스트를 위해 아래의 사진을 "c:\upload\" 경로에 추가 해준 후 해당 파일을 웹브라우저에 출력시켜보겠습니다.
웹 브라우저에 display 메서드를 호출해보겠습니다. url의 쿼리 스트링에 변수 fileName과 그 값을 부여합니다. 지금 테스트를 위해 추가한 파일은 '고정 경로'에 바로 추가한 것이기 때문에 '유동 경로' 값 없이 '파일 이름' 값만 부여해주면 됩니다.
이번에는 유동 경로에 파일을 추가하여 출력시켜보겠습니다. "2021/05/21"에 "test.png" 파일을 추가해줍니다.
이번엔 url 쿼리 스트링에 이동경로를 포함한 값을 작성하여 요청합니다. 쿼리 스트링의 유동 경로에는 "\"이 아닌 "/"을 사용해야 합니다.
REFERENCE
- 코드로배우는 스프링 웹 프로젝트(남가람북스)
- https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%A7%84_%ED%8C%8C%EC%9D%BC
- https://stackoverflow.com/questions/19764448/why-we-use-byte-to-read-binary-data
- https://stackoverflow.com/questions/4579777/why-images-are-represented-by-byte-array
- https://towardsdatascience.com/understanding-binary-data-fc4c78c9e677
- https://ko.wikipedia.org/wiki/%EC%98%A5%ED%85%9F_(%EC%BB%B4%ED%93%A8%ED%8C%85)
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/ResponseEntity.html#ResponseEntity-T-org.springframework.util.MultiValueMap-org.springframework.http.HttpStatus-
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/HttpHeaders.html#add-java.lang.String-java.lang.String-
- https://docs.oracle.com/javase/7/docs/api/java/nio/file/Files.html#probeContentType(java.nio.file.Path)
- https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/FileCopyUtils.html#copyToByteArray-java.io.InputStream-
DATE
- 2020.05.21
'스프링 프레임워크 > 쇼핑몰 프로젝트' 카테고리의 다른 글
[Spring][쇼핑몰 프로젝트][26] 업로드 이미지 삭제 - 1 (2) | 2021.05.31 |
---|---|
[Spring][쇼핑몰 프로젝트][25] 업로드 이미지 출력 -2 (1) | 2021.05.25 |
[Spring][쇼핑몰 프로젝트][24] 상품 이미지 업로드(서버 단계 이미지 파일 체크) - 7 (0) | 2021.05.19 |
[Spring][쇼핑몰 프로젝트][24] 상품 이미지 업로드(이미지 정보 뷰 반환 - 2) - 6 (12) | 2021.05.18 |
[Spring][쇼핑몰 프로젝트][24] 상품 이미지 업로드(이미지 정보 뷰 반환 - 1) - 6 (5) | 2021.05.17 |