๐Ÿ“Œ Spring ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ + ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ ์ด์ •๋ฆฌ

My Pale Blue Dotยท2025๋…„ 4์›” 29์ผ
0

SPRING

๋ชฉ๋ก ๋ณด๊ธฐ
25/36
post-thumbnail

๐Ÿ“… ๋‚ ์งœ

2025-04-28


๐Ÿ“ ํ•™์Šต ๋‚ด์šฉ

1๏ธโƒฃ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์ปจํŠธ๋กค๋Ÿฌ ๊ตฌํ˜„

@GetMapping(value="/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
@ResponseBody
public ResponseEntity<Resource> download(@RequestParam("path") String path) throws UnsupportedEncodingException {
    log.info("GET /file/download..." + path);

    // ํŒŒ์ผ ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ
    Resource resource = new FileSystemResource(path);

    // ํŒŒ์ผ ์กด์žฌ ์—ฌ๋ถ€ ์ฒดํฌ
    if (!resource.exists()) {
        return new ResponseEntity<>(HttpStatus.NOT_FOUND);
    }

    // ๋‹ค์šด๋กœ๋“œ ํŒŒ์ผ๋ช… ์ถ”์ถœ
    String filename = resource.getFilename();

    // HTTP ํ—ค๋” ์„ค์ •
    HttpHeaders headers = new HttpHeaders();
    headers.add(
        "Content-Disposition",
        "attachment; filename=" + new String(filename.getBytes("UTF-8"), "ISO-8859-1")
    );

    // ํŒŒ์ผ ๋ฆฌ์†Œ์Šค + ํ—ค๋” + ์„ฑ๊ณต ์ƒํƒœ์ฝ”๋“œ ํ•จ๊ป˜ ๋ฐ˜ํ™˜
    return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}

2๏ธโƒฃ ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์ฒ˜๋ฆฌ ํ•ต์‹ฌ ํฌ์ธํŠธ

ํ•ญ๋ชฉ์„ค๋ช…
@GetMapping("/download")ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์—”๋“œํฌ์ธํŠธ
produces = MediaType.APPLICATION_OCTET_STREAM_VALUE๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํŒŒ์ผ๋กœ ์ธ์‹ํ•ด์„œ ๋‹ค์šด๋กœ๋“œํ•˜๊ฒŒ ํ•จ
Resource resource = new FileSystemResource(path)์š”์ฒญ๋ฐ›์€ ๊ฒฝ๋กœ์˜ ํŒŒ์ผ์„ Resource ๊ฐ์ฒด๋กœ ์ƒ์„ฑ
resource.exists()ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด 404 Not Found ๋ฐ˜ํ™˜
Content-Disposition ํ—ค๋” ์„ค์ •ํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ๋ฐฉ์‹์œผ๋กœ ๋ณ€ํ™˜ (attachment)
ํŒŒ์ผ๋ช… ์ธ์ฝ”๋”ฉUTF-8 โž” ISO-8859-1 ๋ณ€ํ™˜ (ํ•œ๊ธ€, ํŠน์ˆ˜๋ฌธ์ž ๊นจ์ง ๋ฐฉ์ง€)
ResponseEntity<Resource> ๋ฐ˜ํ™˜๋ณธ๋ฌธ + ํ—ค๋” + HTTP ์ƒํƒœ์ฝ”๋“œ๋ฅผ ํ•จ๊ป˜ ์ „๋‹ฌ

3๏ธโƒฃ ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ JSP ํ๋ฆ„

<h1>/file/list</h1>
<div>${uploadPath}</div>

<!-- ์—…๋กœ๋“œ ํด๋” ๊ตฌ์กฐ ์ˆœํšŒ -->
<c:forEach items='${uploadPath.listFiles()}' var='subdir'>
    <hr>
    FOLDER : ${subdir.getPath()}
    <c:forEach items='${subdir.listFiles()}' var='file'>
        <br />
        - FILE :
        <a href="javascript:void(0)" class="item"
           data-dir="${subdir.getPath()}" data-filename="${file.getName()}">
           ${file.getPath()}
        </a>
    </c:forEach>
    <hr>
</c:forEach>

<script>
const projectPath = '${pageContext.request.contextPath}';
const item_els = document.querySelectorAll('.item');
item_els.forEach((item)=>{
    item.addEventListener('click', function(){
        const filepath = encodeURIComponent(item.getAttribute('data-dir') + "\\" + item.getAttribute('data-filename'));
        location.href = projectPath + "/file/download?path=" + filepath;
    })
})
</script>

4๏ธโƒฃ ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ ํ๋ฆ„ ํ•ต์‹ฌ ํฌ์ธํŠธ

ํ•ญ๋ชฉ์„ค๋ช…
uploadPath.listFiles()์ตœ์ƒ์œ„ ์—…๋กœ๋“œ ๋””๋ ‰ํ† ๋ฆฌ์˜ ์„œ๋ธŒ ํด๋”๋“ค์„ ์ˆœํšŒ
subdir.listFiles()๊ฐ ์„œ๋ธŒ ํด๋” ๋‚ด๋ถ€ ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ
<a> ๋งํฌ ํด๋ฆญ ์‹œํŒŒ์ผ ๋‹ค์šด๋กœ๋“œ ์š”์ฒญ ๋ฐœ์ƒ
encodeURIComponentํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ URL-safe ํ˜•์‹์œผ๋กœ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์„œ๋ฒ„๋กœ ์ „์†ก
์‹ค๋ฌด ์ฃผ์˜์‚ฌํ•ญ์„œ๋ฒ„์˜ ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฒฝ๋กœ๋ฅผ ์ง์ ‘ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณตํ•˜๋ฉด ์•ˆ ๋จ

๐Ÿ”ฅ ์ตœ์ข… ์ •๋ฆฌ

  • ๋‹ค์šด๋กœ๋“œ ๊ธฐ๋Šฅ์€ Resource ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ํŒŒ์ผ์„ ์ฝ๊ณ , ์ ์ ˆํ•œ ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„ํ•œ๋‹ค.
  • ํŒŒ์ผ๋ช…์— ํ•œ๊ธ€์ด๋‚˜ ํŠน์ˆ˜๋ฌธ์ž๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์„ ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ UTF-8 โž” ISO-8859-1 ์ธ์ฝ”๋”ฉ์„ ์ ์šฉํ•˜์—ฌ ๊นจ์ง์„ ๋ฐฉ์ง€ํ•ด์•ผ ํ•œ๋‹ค.
  • ํŒŒ์ผ์ด ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ 404 ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์—ฌ ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•œ๋‹ค.
  • ํŒŒ์ผ ๋ฆฌ์ŠคํŠธ ์ถœ๋ ฅ์€ JSP์—์„œ ์—…๋กœ๋“œ๋œ ํด๋”์™€ ํŒŒ์ผ๋“ค์„ ์ˆœํšŒํ•˜์—ฌ ์ถœ๋ ฅํ•˜๊ณ , ํŒŒ์ผ๋ณ„ ๋‹ค์šด๋กœ๋“œ ๋งํฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค.
  • ๋‹ค์šด๋กœ๋“œ ๋งํฌ ์š”์ฒญ ์‹œ ํŒŒ์ผ ๊ฒฝ๋กœ๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ์ธ์ฝ”๋”ฉํ•˜์—ฌ ์„œ๋ฒ„์— ์ „๋‹ฌํ•œ๋‹ค.
  • ๋ณด์•ˆ์ƒ, ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ฒฝ๋กœ๋ฅผ ์ง์ ‘ ์ œ๊ณตํ•˜๋Š” ๊ฒƒ์€ ์œ„ํ—˜ํ•˜๋ฏ€๋กœ ์‹ค๋ฌด์—์„œ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์—ฐ๋™ ๋ฐฉ์‹์œผ๋กœ ๋ณด์™„ํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

๐Ÿ”— ์ฐธ๊ณ  ์ž๋ฃŒ


profile
Here, My Pale Blue.๐ŸŒ

0๊ฐœ์˜ ๋Œ“๊ธ€