๐ŸŒ Backend/๐Ÿƒ Spring

ํŒŒ์ผ ์—…๋กœ๋“œ ํ•˜๋Š” ๋ฐฉ๋ฒ•(Form, Spring)

DevPoong 2022. 9. 12. 22:00

์ด๋ฒˆ์— ์ง„ํ–‰ํ•˜๊ณ  ์žˆ๋Š” ํ”„๋กœ์ ํŠธ์—์„œ ํŒŒ์ผ์„ ์—…๋กœ๋“œํ•˜๋Š” ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•ด์„œ ๊ณต๋ถ€ํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค.

1. ๋‘ ๊ฐ€์ง€ ์ „์†ก ๋ฐฉ์‹

HTML Form์˜ ๋ฐ์ดํ„ฐ ์ „์†ก ๋ฐฉ์‹์€ ํฌ๊ฒŒ

1. x-www-form-urlencoded

Http Body์— bookname=jpabook&quantity=31 ์™€ ๊ฐ™์ด key-valueํ˜•์‹์„ &๋กœ ์—ฐ๊ฒฐ์ง€์–ด ๋ฌธ์ž๋ฅผ ์ „์†กํ•œ๋‹ค.

2. multipart/form-data

๋ฐ”์ด๋„ˆ๋ฆฌ ๋ฐ์ดํ„ฐ์™€ ๋ฌธ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ „์†กํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

multipart/form-data์— ๋Œ€ํ•ด์„œ ๋” ์•Œ์•„๋ณด์ž.

 

2. multipart/form-data

<form action="/save" method="post" enctype="multipart/form-data">
    <input type="text" name="bookname"/>
    <input type="file" name="imgfile1" />
</form>

ํผ ๋ฐ์ดํ„ฐ๊ฐ€ ์„œ๋ฒ„๋กœ submit ๋  ๋•Œ ์ธ์ฝ”๋”ฉ ๋˜๋Š” ๋ฐฉ์‹์„ ์ง€์ •ํ•˜๋Š” enctype(encryptiontype)์„ ํ•ด๋‹น ๋ฐฉ์‹์œผ๋กœ ์„ค์ •ํ•œ๋‹ค.

๊ทธ๋ ‡๊ฒŒ ์•„๋ž˜์™€ ๊ฐ™์€ ํ˜•์‹์œผ๋กœ Http ๋ฉ”์‹œ์ง€๊ฐ€ ๋ณด๋‚ด์ง„๋‹ค. 

POST /save HTTP/1.1
Host: ~
Content-Type: multipart/form-data; boundary=(random๊ฐ’ x)

x
Content-Disposition: form-data; name="bookname"
jpa
x
Content-Disposition: form-data; name="imgfile1"; filename="jpa.png"
Content-Type: image/png
4121312asdasd12345f12dfas123...............(binary ๋ฐ์ดํ„ฐ๊ฐ€ ๋„˜์–ด๊ฐ)
x

 

3-1. ์Šคํ”„๋ง์—์„œ multipart ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ• 1

Form์—์„œ text input๊ณผ file input 2๊ฐ€์ง€ ๋ฐ์ดํ„ฐ๋ฅผ ๋™์‹œ์— ์ „์†กํ•ด๋ณด์•˜๋‹ค.

HttpServletRequest์—๋Š” ์ด๋ฆ„์—์„œ๋ถ€ํ„ฐ ์•Œ ์ˆ˜ ์žˆ๋“ฏ์ด ๋ณต์žกํ•œ multipart ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ StandardMultipartHttpServletRequest๊ฐ€ ํ• ๋‹น๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

spring.servlet.multipart.enabled=true

์œ„์˜ ์˜ต์…˜์ด spring์˜ ๊ธฐ๋ณธ ์„ค์ •์ธ true์ผ ๋•Œ๋งŒ

Spring Boot์˜ DispatcherServlet์—์„œ MultipartResolver๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

๊ทธ๋ฆฌ๊ณ  http multipart ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด MultipartResolver๊ฐ€ ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ์ „๋‹ฌํ•˜๋Š” ์ผ๋ฐ˜์ ์ธ HttpServletRequest๋ฅผ MultipartHttpServletRequest๋กœ ๋ณ€ํ™˜ํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์ปจํŠธ๋กค๋Ÿฌ์—์„œ๋Š” HttpServletRequest ๋Œ€์‹ ์— MultipartHttpServletReques๋ฅผ ์ฃผ์ž…๋ฐ›์•„ ๋” ๋งŽ์€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด์ œ HttpServletRequest์—์„œ Part๋ฅผ ์–ป์–ด์˜ค๊ณ  Part์˜ ๊ธฐ๋Šฅ์„ ์ด์šฉํ•˜์—ฌ ํŒŒ์ผ ๊ด€๋ จ ํŽธ์˜ ๊ธฐ๋Šฅ, ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ, ํŒŒ์ผ ์ €์žฅํ•˜๊ธฐ๋ฅผ ํ•ด๋ณด์ž!

์šฐ์„  ํŒŒ์ผ์„ ์ €์žฅํ•  ๊ฒฝ๋กœ๋ฅผ ์„ค์ •ํ•œ๋‹ค.

#application.properties

file.dir = /Users/khs/Documents/Development/workspace/FileUpload/file/

 

@PostMapping("/upload")
public String saveFileV1(HttpServletRequest request) throws ServletException, IOException {
    Collection<Part> parts = request.getParts();
    log.info("parts={}", parts);

    for (Part part : parts) {
        log.info("===== PART =======");
        log.info("name={}", part.getName());
        Collection<String> headerNames = part.getHeaderNames();
        for (String headerName : headerNames) {
            log.info("header {}: {}", headerName, part.getHeader(headerName));
        }

        //ํŽธ์˜ ๊ธฐ๋Šฅ ๋ฉ”์„œ๋“œ
        log.info("submittedFileName={}", part.getSubmittedFileName());
        log.info("size={}", part.getSize());

        //๋ฐ์ดํ„ฐ Read
        InputStream inputStream = part.getInputStream();
        String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
        log.info("body={}", body);
        
        //ํŒŒ์ผ์— ์ €์žฅํ•˜๊ธฐ
        if (StringUtils.hasText(part.getSubmittedFileName())) {
            String fullPath = fileDir + part.getSubmittedFileName();
            log.info("ํŒŒ์ผ ์ €์žฅ fullPath={}", fullPath);
            part.write(fullPath);
        }
        
        
    }
}

์œ„์™€ ๊ฐ™์ด ์ด๋ฏธ์ง€ ํŒŒ์ผ์ด ์ž˜ ์ €์žฅ๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

 

3-2. ์Šคํ”„๋ง์—์„œ multipart ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ• 2( ์ถ”์ฒœ! โญ๏ธโญ๏ธโญ๏ธ)

@PostMapping("/upload")
public String saveFile(@RequestParam("itemName") String itemName,
                       @RequestParam("file") MultipartFile file, HttpServletRequest request) throws IOException {
    log.info("request={}", request);
    log.info("itemName={}", itemName);
    log.info("multipartFile={}", file);
    if (!file.isEmpty()) {
        String fullPath = fileDir + file.getOriginalFilename();
        log.info("ํŒŒ์ผ ์ €์žฅ fullPath={}", fullPath);
        file.transferTo(new File(fullPath)); //ํŒŒ์ผ์ €์žฅ
    }
    return "upload-form";
}

Spring์—์„œ ์ œ๊ณตํ•ด์ฃผ๋Š” Multipart class๋ฅผ ์ด์šฉํ•˜์—ฌ ๊ฐ„ํŽธํ•˜๊ฒŒ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜๋‹ค.