티스토리 뷰

728x90

21.12.31 download 부분 수정

21.10.12 수정

22.04.25 체크..

22.11.02 이미지 보기, 다운로드 관련 수정~

 

우선 코드는 잘 되지만 설명은 잘 안된다는 점......


 

Spring boot를 사용하는 이유는 여러 사이트에서 공통적으로 하는 '초반 설정 단계를 매우 간략하게 함' 이라는 것 같다.

 

아직까지 DB 쪽은 건들지 않아서 나는 체감되지 않지만 예전에 spring에서 pom.xml 만지는 것이 정말 귀찮았다고는 생각했기 때문에 이해가 됐다.

 

 

boot를 일반 spring에서 좀 더 간소화 된 버전이겠지~ 하면 또 안되는게, 

boot와 일반 spring의 차이는 옛날 책으로 되어 있던 전화번호부에서 전화번호를 찾아 전화하는 방법과

AI에게 전화번호 찾아서 전화 걸어줘~ 하는 수준의 차이가 난다고 나는 체감한다(아마 spring 옛날 버전을 배워서 그런듯,,?)

 

 

 

각설하고요~ 마치 유치원생(나)에게 말하듯 차근차근 적습니다.

 

 

오늘 할 일은 이미지를 업로드, html에 띄워보기

 

아래는 form 태그와 스프링 부트 시스템을 사용하여 파일 업/다운로드 미리보기를 다룹니다. 

 

그냥 <img src="image.jpg" /> 라고 작성하면 static에 있는 image.jpg를 찾아온다.

그러면 이미지 업로드 시 경로를 static으로 쓰거나, 아니면 src 를 다르게 적거나인데 어떻게 이미지를 찾아왔는지 코드와 같이 보자. 정리하면 쉽지... 근데 나는 왜 또 헤맸을까

 

추가적인 설명을 적어보면 직관적으로 생각해서 `나는 static 폴더에 이미지를 저장하구 거기서 가져와야지~` 는 불가능하다. 보안상의 이유라고 알고 있었는데 정확하게는 잘 모르겠다. 하여 아래 코드는 로컬에 파일을 저장하고 가져오기를 다룬다. 

 

<form method="post" action="/upload" enctype="multipart/form-data">
	<input type="file" name="uploadfile" multiple="multiple"/> 
	<input type="submit" value="결과 확인"/>
</form>

 

 

대충 html에 이런 코드를 넣습니다. 어렵지 않죠.

그럼 controller에서 /upload를 찾습니다.

 

@PostMapping("/upload")
public String upload(@RequestParam("uploadfile") 
		MultipartFile[] uploadfile, Model model) {

	List<FileDto> list = new ArrayList<>();

	for (MultipartFile file : uploadfile) {			
		FileDto dto = new FileDto( file.getOriginalFilename(), file.getContentType() );	
		list.add(dto);
		File newFileName = new File(dto.getFileName());
        
		try {
			file.transferTo(newFileName);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	model.addAttribute("files", list);
	return "results";
}

 

uploadfile에서 하나씩 가져다가 저장합니다.

저장 경로는 application.yaml에 있는데요

 

 servlet:
    multipart:
      location: c:\\Temp\\upload
      maxFileSize: 200MB
      maxRequestSize: 100MB

 

이렇게 되어 있는 상태입니다. (자바 코드에 경로를 지정해서 넣어 주어도 된다)

 

그러면 아래처럼 이미지가 저장됩니다.

 

코드를 보니까 results.html로 가네요 봅시다.

 

<ul th:each="file: ${files}">
	<li>
		<span th:text="${file.fileName}"></span>
		<a th:href="'/download?fileName='+${file.fileName}"> [download] </a> <br />
		<a th:href="'/display?filename='+${file.fileName}"> 
		<img th:src="'/display?filename='+${file.fileName}" alt="이미지 확인하기" width="300px" />
		</a><br />
	</li>
</ul>

 

 

내가 넣은 파일들의 이름과 다운로드 할 수 있는 a 링크가 보입니다. 

 

다운로드

@Value("${spring.servlet.multipart.location}")
String filePath;

@GetMapping("/download")
public ResponseEntity<Resource> download(@ModelAttribute FileDto dto) throws IOException {

	Path path = Paths.get(filePath + "/" + dto.getFileName());
	String contentType = Files.probeContentType(path);

	HttpHeaders headers = new HttpHeaders();
	headers.setContentDisposition(
	ContentDisposition.builder("attachment")
		.filename(dto.getFileName(), StandardCharsets.UTF_8)
		.build());
	headers.add(HttpHeaders.CONTENT_TYPE, contentType);

	Resource resource = new InputStreamResource(Files.newInputStream(path));

	return new ResponseEntity<>(resource, headers, HttpStatus.OK);

}

 

 

아래는 딱히 정리된건 아닌 짜투리 정보들..

 

Resource? java.net.URL을 추상화 한 객체

  • FileSystemResource  절대경로나 파일시스템에서 리소스 찾기
  • UrlResource  URL을 통해서 리소스 찾기
  • ClassPathResource  class loader를 통해 리소스 찾기
  • InputStreamResource   inputStream을 넣어주고 사용: 파일 읽어들일 때 사용
  • ByteArrayResource  byteArray를 넣어주고 사용: 파일을 사용할 때 씀..

리소스를 이용하거나 stream(inputstream, outputstream)을 사용하기도 한다.... 

 

ResponseEntity? Http request 또는 response에 해당하는 HttpHeader와 HttpBody를 포함하는 클래스.

body, headers, status code 정보를 전송

  • body: request나 response가 전송하는 데이터
  • headers: request나 response의 부가정보
  • status code: 클라이언트의 요청 처리 여부

 

HttpHeader를 HttpHeaders에서 설정한다.

Content disposition 헤더: 컨텐츠가 브라우저에 inline되어야하는 웹페이지 자체 혹은 일부(inline)인지, attachment로써 다운로드되거나 로컬에 저장될 용도로 쓰이는 지를 알려주는 역할.

Content Disposition에 관해서.... 🔗

더보기

좀 더 자세히..

 

//파일 보기

headers.setContentDisposition(ContentDisposition.builder("inline").filename(filename, StandardCharsets.UTF_8).build());

//파일 다운로드

headers.setContentDisposition(ContentDisposition.builder("attachment").filename(filename, StandardCharsets.UTF-8).build());

headers.add("Content-Disosition", "attachment; filename=" + filename, "ISO-8859-1"));

 

ContentDisposition을 따로 지정하지 않으면 inline으로 설정되는 듯 보임...

 

 

path의 파일을 inputstream으로 받아와

filename이 dto.getFileName()이며 attachment라고 알려주는 헤더에

contentType 추가하고 

ResponseEntity를 통해 모든 정보를 반환..(?) 인 것 같습니다.

 

 

다운로드 아래 a 링크를 보니까 /display가 있네요 보러갑니다.. 

@GetMapping("/display")
public ResponseEntity<Resource> display(@RequestParam("filename") String filename) {
	String path = "C:\\Temp\\upload\\";
	String folder = "";
	Resource resource = new FileSystemResource(path + folder + filename);
	if(!resource.exists()) 
		return new ResponseEntity<Resource>(HttpStatus.NOT_FOUND);
	HttpHeaders header = new HttpHeaders();
	Path filePath = null;
	try{
		filePath = Paths.get(path + folder + filename);
		header.add("Content-type", Files.probeContentType(filePath));
	}catch(IOException e) {
		e.printStackTrace();
	}
	return new ResponseEntity<Resource>(resource, header, HttpStatus.OK);
}

 

저는 이미지를 뭐 이렇게 어렵게 띄우나,,, 했지 뭐예요

아 controller에 들어갔다 와야 띄워지는구나..

 

그리고 probeContentType 을 찾다가 알게된 MIME 타입 https://server-talk.tistory.com/183

그리고 probeContentType 설명: 마임타입이 확인되지 않으면 null 반환 https://2ham-s.tistory.com/283

 

 

아직 spring boot랑 거리두기 중..

 

 

 

 

728x90
댓글
250x250
250x250
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
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 31
글 보관함