# ์„œ๋ธ”๋ฆฟ์„ ์ด์šฉํ•œ HTML Form ํŒŒ์ผ ์—…๋กœ๋“œ
Study Repository

์„œ๋ธ”๋ฆฟ์„ ์ด์šฉํ•œ HTML Form ํŒŒ์ผ ์—…๋กœ๋“œ

by rlaehddnd0422

HTML Form์„ ์ด์šฉํ•œ ํŒŒ์ผ ์ „์†ก

ํŒŒ์ผ์„ ์„œ๋ฒ„์— ์ „์†กํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ˆœ์ˆ˜ ์„œ๋ธ”๋ฆฟ์„ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ์Šคํ”„๋ง์ด ์ง€์›ํ•˜๋Š” MultipartFile๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋Š”๋ฐ ์ด ํฌ์ŠคํŒ…์—์„œ ํ•œ๋ฒˆ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

 

์šฐ์„  ์•Œ์•„๋‘์–ด์•ผ ํ•  ์ ์€ HTML Form์„ ํ†ตํ•ด ํŒŒ์ผ์„ ์—…๋กœ๋“œ ํ•˜๊ณ ์ž ํ•  ๋•Œ๋Š” ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉํ–ˆ๋˜ www-form-urlencoded Content Type์ด ์•„๋‹Œ ๋‹ค๋ฅธ ํ˜•์‹(multipart/form-data)์„ ์‚ฌ์šฉํ•œ๋‹ค๋Š” ์ ์ž…๋‹ˆ๋‹ค!

 

Content-Type : application/x-www-form-urlencoded

  • ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•
  • HTTP Body์— ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ ํ˜•์‹์œผ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.
  • ๋ฌธ์ž ์ „์†ก์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

Content-Type : multipart/form-data 

  • ๋ฌธ์ž ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ์ผ ์ „์†ก๋„ ์ง€์›
  • ํŒŒ์ผ์€ ๋ฐ”์ด๋„ˆ๋ฆฌ๋กœ ์ „์†ก๋ฉ๋‹ˆ๋‹ค.
  • ์ด ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ ค๋ฉด Form ํƒœ๊ทธ์— ๋ณ„๋„๋กœ enctype="multipart/form-data"๋ฅผ ์ง€์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
<form th:action method="post" enctype="multipart/form-data">
    <ul>
        <li>์ƒํ’ˆ๋ช…<input type="text" name="itemName"></li>
        <li>ํŒŒ์ผ<input type="file" name="file" ></li> </ul>
    <input type="submit"/>
</form>
  • ์ด Content-Type์„ ์‚ฌ์šฉํ•˜๋ฉด Form์—์„œ ๊ฐ ๋ฐ์ดํ„ฐ๋“ค์€ ๊ฐ๊ฐ์˜ Part๋กœ ๋‚˜๋ˆ„์–ด์ ธ POST ์ „์†ก ๋ฉ๋‹ˆ๋‹ค. ์„œ๋ธ”๋ฆฟ์—์„œ๋Š” part๋ณ„๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ›์•„๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • ์ปจํŠธ๋กค๋Ÿฌ์—์„œ request.getParts()๋ฅผ ํ†ตํ•ด multpiart/form-data ์ „์†ก ๋ฐฉ์‹์—์„œ ๊ฐ๊ฐ ๋‚˜๋ˆ„์–ด์ง„ Part๋ฅผ ๋ฐ›์•„์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ (์ฒซ๋ฒˆ์งธ ์ธ์ž๋Š” itemName์— ๋Œ€ํ•œ part, ๋‘ ๋ฒˆ์งธ ์ธ์ž๋Š” File์— ๋Œ€ํ•œ part)

+ Tip : application.properties์— ์ถ”๊ฐ€ํ•˜๋ฉด HTTP ์š”์ฒญ ๋ฉ”์‹œ์ง€ ๋กœ๊ทธ๋ฅผ ํ†ตํ•ด ํ™•์ธ ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. ์ถ”๊ฐ€์ ์œผ๋กœ ํผ์—์„œ ์ „์†ก๋œ ๋ฉ€ํ‹ฐํŒŒํŠธ์˜ ๊ฐ ํŒŒํŠธ์˜ ์ •๋ณด๋ฅผ ๋ณผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

logging.level.org.apache.coyote.http11=debug

+ application.properties์—์„œ multipart์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ ์˜ต์…˜์„ ๋„๋ฉด ์„œ๋ธ”๋ฆฟ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ multipart ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋””ํดํŠธ๋Š” true๋กœ ์„ค์ •๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

spring.servlet.multipart.enabled=false

+ ์„œ๋ธ”๋ฆฟ์—์„œ multipart์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” RequestFacade๊ฐ€ ์•„๋‹Œ StandardMultipartHttpServletRequest๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. 

์„œ๋ธ”๋ฆฟ์„ ์ด์šฉํ•œ HTML Form ํŒŒ์ผ ์—…๋กœ๋“œ

์„œ๋ธ”๋ฆฟ์„ ํ†ตํ•ด ๊ฐ„๋‹จํ•˜๊ฒŒ ํŒŒ์ผ์„ ์„œ๋ฒ„์— ์—…๋กœ๋“œ ํ•ด๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

@Slf4j
@Controller
@RequestMapping("/servlet/v2")
public class ServletUploadControllerV2 {

    @Value("${file.dir}")
    private String fileDir;

    @GetMapping("/upload")
    public String newFile()
    {
        return "upload-form";
    }
  • file.dir์€ ์—…๋กœ๋“œํ•  ๊ฒฝ๋กœ๋กœ application.properties์— ๋“ฑ๋กํ•ด์„œ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
file.dir=/Users/kdo6301/Desktop/Files/
  • upload-form์—๋Š” form์— enctype="multipart/form-data"๋ฅผ ์ง€์ •ํ•ด์ฃผ๊ณ  ์ƒํ’ˆ๊ณผ ํŒŒ์ผ์„ ์ž…๋ ฅํ•  ์ˆ˜ ์žˆ๋Š” ํผ์„ ์ž‘์„ฑํ–ˆ์Šต๋‹ˆ๋‹ค.
    @PostMapping("/upload")
    public String saveFileV2(HttpServletRequest request) throws ServletException, IOException
    {
        log.info("request = {}",request);

        String itemName = request.getParameter("itemName");
        log.info("itemName = {}",itemName);

        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));
            }

            // content-disposition ; filename
            log.info("submittedFileName={}",part.getSubmittedFileName());
            log.info("size={}",part.getSize());

            // ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ
            InputStream inputStream = part.getInputStream();
            String body = StreamUtils.copyToString(inputStream, StandardCharsets.UTF_8);
//            log.info("body={}",body);

            // part๋ฅผ ํ†ตํ•ด ์ „์†ก๋œ ๋ฐ์ดํ„ฐ ์ €์žฅ
            if(StringUtils.hasText(part.getSubmittedFileName()))
            {
                String fullPath = fileDir + part.getSubmittedFileName();
                log.info("ํŒŒ์ผ ์ €์žฅ fullPath = {}", fullPath);
                part.write(fullPath);
            }
        }

        return "upload-form";
    }

 

  • request.getParts()๋ฅผ ํ†ตํ•ด multpiart/form-data ์ „์†ก ๋ฐฉ์‹์—์„œ ๊ฐ๊ฐ ๋‚˜๋ˆ„์–ด์ง„ Part๋ฅผ ๋ฐ›์•„์„œ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํผ์œผ๋กœ๋ถ€ํ„ฐ ์ „์†ก๋œ ๊ฐ ํŒŒํŠธ๋ฅผ iterator๋กœ ๊ฐ ํŒŒํŠธ์— ๋Œ€ํ•œ ์ •๋ณด(ํ—ค๋”)๋ฅผ ์ถœ๋ ฅํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํŒŒ์ผ ํ˜•์‹์ธ ๊ฒฝ์šฐ (part.getSubmittedFileName() Not Null ) ํ•ด๋‹น ํŒŒํŠธ๋ฅผ fullPath์— writeํ•ด์„œ ์ €์žฅ 
    • part.write() : ํŒŒ์ผ ์ €์žฅ 
    • part.getSubmittedFileName() : ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ „๋‹ฌํ•œ ํŒŒ์ผ๋ช…
    • part.getInputStream() : Part์˜ ์ „์†ก ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋กœ๊ทธ

์„œ๋ธ”๋ฆฟ์ด ์ œ๊ณตํ•˜๋Š” Part๋ฅผ ์ด์šฉํ•ด์„œ ํŒŒ์ผ์„ ์„œ๋ฒ„์— ์ „์†กํ•ด๋ณด์•˜์Šต๋‹ˆ๋‹ค. ํŽธํ•˜๊ธด ํ•˜์ง€๋งŒ ์„œ๋ธ”๋ฆฟ ๊ฐ์ฒด๋ฅผ ์จ์•ผ ํ•˜๊ณ , ์ถ”๊ฐ€๋กœ ํŒŒ์ผ ๋ถ€๋ถ„๋งŒ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด์ด ์ข€ ๊นŒ๋‹ค๋กญ์Šต๋‹ˆ๋‹ค. ์Šคํ”„๋ง์ด ์ด ๋ถ€๋ถ„์„ ์–ผ๋งˆ๋‚˜ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ œ๊ณตํ•ด์ฃผ๋Š”์ง€ ์•Œ์•„๋ณด๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.


์Šคํ”„๋ง์„ ์ด์šฉํ•œ HTML Form ํŒŒ์ผ ์—…๋กœ๋“œ

์Šคํ”„๋ง์€ MultiPartFile ์ด๋ผ๋Š” ์ธํ„ฐํŽ˜์ด์Šค๋กœ ๋ฉ€ํ‹ฐํŒŒํŠธ ํŒŒ์ผ์„ ๋งค์šฐ ํŽธ๋ฆฌํ•˜๊ฒŒ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

@PostMapping("/upload")
public String saveFile(@RequestParam String itemName,
                       /* @ModelAttribute๋„ ๊ฐ€๋Šฅ*/
                       @RequestParam MultipartFile file, HttpServletRequest request)
        throws IOException
{
    log.info("request = {}",request);
    log.info("itemName = {}",itemName);
    log.info("file = {}",file);

    if(!file.isEmpty())
    {
        String fullPath = fileDir + file.getOriginalFilename();
        log.info("ํŒŒ์ผ ์ €์žฅ fullPath = {}",fullPath);
        file.transferTo(new File(fullPath));
    }

    return "upload-form";
}

POST ๋กœ HTML ํผ ์ „์†ก ์‹œ ํŒŒ์ผ์— ๋Œ€ํ•œ ํƒ€์ž…์„ MultiPart๋กœ ์ง€์ •ํ•˜๋ฉด @RequestParam์ด๋‚˜ @ModelAttribute๋กœ ๋ฐ›์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์„œ๋ธ”๋ฆฟ๊ณผ ๋น„๊ตํ•˜๋ฉด ์ฐธ ์‰ฝ๊ณ  ๊ฐ„๋‹จํ•˜์ฃ ?

 

MultiPartFile์˜ ์ฃผ์š” ๋ฉ”์†Œ๋“œ

  • getOriginalFilename() : ์—…๋กœ๋“œ ํŒŒ์ผ ๋ช… 
  • transferTo(File) : ํŒŒ์ผ ์ €์žฅ 

 

<์ฐธ๊ณ ์ž๋ฃŒ>

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2/dashboard

 

์Šคํ”„๋ง MVC 2ํŽธ - ๋ฐฑ์—”๋“œ ์›น ๊ฐœ๋ฐœ ํ™œ์šฉ ๊ธฐ์ˆ  - ์ธํ”„๋Ÿฐ | ๊ฐ•์˜

์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ์›น ๊ธฐ์ˆ ์„ ๊ธฐ์ดˆ๋ถ€ํ„ฐ ์ดํ•ดํ•˜๊ณ , ์™„์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. MVC 2ํŽธ์—์„œ๋Š” MVC 1ํŽธ์˜ ํ•ต์‹ฌ ์›๋ฆฌ์™€ ๊ตฌ์กฐ ์œ„์— ์‹ค๋ฌด ์›น ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ๋ชจ๋“  ํ™œ์šฉ ๊ธฐ์ˆ ๋“ค์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ

www.inflearn.com

 

๋ธ”๋กœ๊ทธ์˜ ์ •๋ณด

Study Repository

rlaehddnd0422

ํ™œ๋™ํ•˜๊ธฐ