spring

์Šคํ”„๋ง MVC ํ•™์Šต๋ชฉ๋ก (2)

devJK93 2025. 1. 8.

๐Ÿ“ ํ•™์Šต๋ชฉ๋ก & GPT์—๊ฒŒ ๋ฌผ์–ด๋ณธ ์งˆ๋ฌธ ๋ชฉ๋ก


๐Ÿ“™ 1. ์Šคํ”„๋ง ํƒ€์ž… ์ปจ๋ฒ„ํ„ฐ

1) Converter

์ปจ๋ฒ„ํ„ฐ๋Š” org.springframework.convert.converter.Converter

public interface Conveter<S,T> {
	T convert(S source);
}

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ๋งŒ๋“ ๋‹ค.


2) ConversionService

์Šคํ”„๋ง์€ ๊ฐœ๋ฐœ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ๋ชจ์•„๋‘๊ณ  ๊ทธ๊ฒƒ์„ ๋ฌถ์–ด์„œ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ์ค€๋‹ค

๊ทธ๊ฒƒ์ด ConversionService ์ธํ„ฐํŽ˜์ด์Šค

package org.springframework.core.convert;
import java.util.List;

public interface ConversionService {

    boolean canConvert(Class<?> sourceType, Class<?> targetType);
    boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);

    <T> T convert(Object source, Class<T> targetType);
    Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);

}

๋ฉ”์„œ๋“œ๋กœ canConvert ์™€ convert๋ฅผ ์ œ๊ณตํ•œ๋‹ค.

 

๊ตฌํ˜„์ฒด๋กœ๋Š” DefaultConversionService๊ฐ€ ์žˆ๋‹ค. 

(* ConversionService์™€ ConversionRegistry๋ฅผ ๊ตฌํ˜„ํ•œ ConfigurableConversionService๋ฅผ ๊ตฌํ˜„ํ•œ GenericConversionService๋ฅผ ์ƒ์†๋ฐ›์€ ๊ตฌํ˜„์ฒด๋‹ค..)

 

// ๋“ฑ๋ก

DefaultConversionService๋Š” addConverter() ์ด์šฉํ•ด ์ปจ๋ฒ„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

 

// ์‚ฌ์šฉ

DefaultConversionService๋Š” convert() ๊ฐ€๋Šฅ

 

๋“ฑ๋ก’๊ณผ ‘์‚ฌ์šฉ’ ๋ถ„๋ฆฌ

๋“ฑ๋กํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ๋“ฑ๋กํ•  ์ปจ๋ฒ„ํ„ฐ๋“ค์„ ๋ช…ํ™•ํžˆ ์•Œ์•„์•ผ ํ•œ๋‹ค.

ํ•˜์ง€๋งŒ ์‚ฌ์šฉํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ๋ชฐ๋ผ๋„๋˜๋‹ˆ๊น ConversionService์—๋งŒ ์˜์กดํ•œ๋‹ค.

 

๐Ÿ“— ์ธํ„ฐํŽ˜์ด์Šค ๋ถ„๋ฆฌ ์›์น™ (ISP)

- ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž์‹ ์ด ์ด์šฉํ•˜์ง€ ์•Š๋Š” ๋ฉ”์„œ๋“œ์— ์˜์กดํ•˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค

 

์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๋ถ„๋ฆฌํ•˜๋ฉด ์ปจ๋ฒ„ํ„ฐ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์™€ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ์˜ ๊ด€์‹ฌ์‚ฌ๋ฅผ ๋ช…ํ™•ํžˆ ๋ถ„๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฆ‰ ์ปจ๋ฒ„ํ„ฐ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋Š” ConversionService ์ธํ„ฐํŽ˜์ด์Šค๋งŒ ์˜์กดํ•˜๋ฉด ๋˜๋‹ˆ๊น ๋‚˜๋จธ์ง€๋Š” ๊ด€์‹ฌ์—†๊ณ  ์•Œ ํ•„์š”๋„ ์—†๋‹ค.

 

์–ด์ฐŒ๋๋“  ์Šคํ”„๋ง์€ ๋‚ด๋ถ€์—์„œ ConversionService๋ฅผ ์ด์šฉํ•ด์„œ ํƒ€์ž…์„ ๋ณ€ํ™˜ํ•˜๊ณ , @RequestParam, @ModelAttribute, @PathVariable ๊ฐ™์€ ์• ๋„ˆํ…Œ์ด์…˜๋„ ConversionService๋ฅผ ์ด์šฉํ•ด์„œ ๋ณ€ํ™˜ํ•œ๋‹ค.

 

@RequestParam์€ @RequestParam์„ ์ฒ˜๋ฆฌํ•˜๋Š” ArgumentResolver์ธ RequestParamMethodArgumentResolver์—์„œ ConversionService๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํƒ€์ž…์„ ๋ณ€ํ™˜ํ•œ๋‹ค. 


3) WebMvcConfigurer ์˜ addFormatters ๊ตฌํ˜„

์Šคํ”„๋ง ์›นMVC์— ๋ญ”๊ฐ€ ๋“ฑ๋กํ• ๋•Œ๋Š” WebMvcConfigurer๊ตฌํ˜„ํ•œ ํด๋ž˜์Šค @Configuration์œผ๋กœ ๋“ฑ๋กํ–ˆ๋‹ค

@Configuration

public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToIpPortConverter());
        …
    }
}

 

์Šคํ”„๋ง์€ ๋‚ด๋ถ€์—์„œ ConversionService๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์šฐ๋ฆฌ๋Š” addFormatters๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ converter๋ฅผ ๋“ฑ๋กํ•˜๋ฉด๋œ๋‹ค.

 

๊ทธ๋Ÿฌ๋ฉด ์Šคํ”„๋ง์€ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•˜๋Š” ConversionService์— converter๋ฅผ ๋“ฑ๋กํ•ด์ค€๋‹ค.

1) ๋ฌธ์ž์—ด → ํƒ€์ž… OK

2) View์—์„œ ํƒ€์ž… → ๋ฌธ์ž์—ด์€?

 

ํƒ€์ž„๋ฆฌํ”„์—์„œ ${{...}} ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด ConversionService(ํƒ€์ž… → ๋ฌธ์ž์—ด) ์ ์šฉ๊ฐ€๋Šฅ

* th:field๋Š” ${...}๋งŒ ํ•ด๋„ ConversionService ์ ์šฉ๋œ๋‹ค.

* th:value๋Š” ${{...}}ํ•ด์•ผ ํ•จ.


4) Converter vs Formatter

Converter๋Š” ๋ฒ”์šฉ : ๊ฐ์ฒด -> ๊ฐ์ฒด

Formatter๋Š” ๋ฌธ์ž์— ํŠนํ™” : ๋ฌธ์ž -> ๊ฐ์ฒด, ๊ฐ์ฒด -> ๋ฌธ์ž + Locale(ํ˜„์ง€ํ™”) (Converter์˜ ํŠน๋ณ„ ๋ฒ„์ „)

 

Printer ์ธํ„ฐํŽ˜์ด์Šค์™€ Parser์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด Formatter ์ธํ„ฐํŽ˜์ด์Šค

import org.springframework.format.Formatter;
import org.springframework.stereotype.Component;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

@Component
public class LocalDateFormatter implements Formatter<LocalDate> {

    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

    @Override
    public LocalDate parse(String text, Locale locale) {
        try {
            return LocalDate.parse(text, formatter);
        } catch (Exception e) {
            throw new IllegalArgumentException("Invalid date format. Please use yyyy-MM-dd");
        }
    }

    @Override
    public String print(LocalDate object, Locale locale) {
        return object.format(formatter);
    }
}

 

 

1000 <-> 1,000 ์ž๋ฐ”๊ฐ€ ๊ธฐ๋ณธ์ ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” NumberFormat์„ ์ด์šฉํ•ด์„œ ๋งŒ๋“ค์ž locale์ •๋ณด์—๋”ฐ๋ผ ๋‹ค๋ฅด๊ฒŒ ๋งŒ๋“ค์–ด์คŒ.

package hello.typeconverter.formatter;

import lombok.extern.slf4j.Slf4j;
import org.springframework.format.Formatter;
import java.text.NumberFormat;
import java.text.ParseException;
import java.util.Locale;

@Slf4j
public class MyNumberFormatter implements Formatter<Number> {

    @Override
    public Number parse(String text, Locale locale) throws ParseException {
        log.info("text={}, locale={}", text, locale);
        NumberFormat format = NumberFormat.getInstance(locale);
        return format.parse(text);
    }
    
    @Override
    public String print(Number object, Locale locale) {
        log.info("object={}, locale={}", object, locale);
        return NumberFormat.getInstance(locale).format(object);
    }
}

5) Formatter๋ฅผ ์ง€์›ํ•˜๋Š” ConversionService

ConversionService๋Š” Converter๋งŒ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. 

๊ทธ๋Ÿฌ๋‚˜ ์ž˜ ์ƒ๊ฐํ•ด๋ณด๋ฉด Formatter๋Š” ๋ฌธ์ž ↔ ๊ฐ์ฒด ๋ฅผ ํ•ด์ฃผ๋Š” ํŠน์ˆ˜ํ•œ Converter์ผ ๋ฟ์ด๋‹ค.

 

Formatter๋ฅผ ์ง€์›ํžˆ๋Š” ConversionService๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ConversionService์— Formatter๋ฅผ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค.

๋‚ด๋ถ€์—์„œ Adapter Pattern์„ ์‚ฌ์šฉํ•ด์„œ Formatter๊ฐ€ Converter์ฒ˜๋Ÿผ ๋™์ž‘ํ•˜๋„๋ก ์ง€์›ํ•œ๋‹ค.

 

FormattingConversionService ๋Š” Formatter๋ฅผ ์ง€์›ํ•˜๋Š” ConversionService
DefaultFormattingConversionService ๋Š” FormattingConversionService ์— ๊ธฐ๋ณธ์ ์ธ ํ†ตํ™”, ์ˆซ์ž
๊ด€๋ จ ๋ช‡๊ฐ€์ง€ ๊ธฐ๋ณธ Formatter๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์ œ๊ณตํ•œ๋‹ค.

public class FormattingConversionServiceTest {

    @Test
    void formattingConversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();

        //์ปจ๋ฒ„ํ„ฐ ๋“ฑ๋ก
        conversionService.addConverter(new StringToIpPortConverter());
        conversionService.addConverter(new IpPortToStringConverter());

        //ํฌ๋งทํ„ฐ ๋“ฑ๋ก
        conversionService.addFormatter(new MyNumberFormatter());

        //์ปจ๋ฒ„ํ„ฐ ์‚ฌ์šฉ
        IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
        assertThat(ipPort).isEqualTo(new IpPort("127.0.0.1", 8080));

        //ํฌ๋งทํ„ฐ ์‚ฌ์šฉ
        assertThat(conversionService.convert(1000,String.class)).isEqualTo("1,000");
        assertThat(conversionService.convert("1,000", Long.class)).isEqualTo(1000L);
    }
}

 

๐Ÿ“ DefaultFormattingConversionService ์ƒ์† ๊ด€๊ณ„


FormattingConversionService ๋Š” ConversionService ๊ด€๋ จ ๊ธฐ๋Šฅ์„ ์ƒ์†๋ฐ›๊ธฐ ๋•Œ๋ฌธ์— Converter๋„ Formatter๋„ ๋ชจ๋‘ ๋“ฑ๋กํ•  ์ˆ˜ ์žˆ๋‹ค. ์‚ฌ์šฉํ•  ๋•Œ๋Š” ConversionService ๊ฐ€ ์ œ๊ณตํ•˜๋Š” convert๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋จ.

 

์Šคํ”„๋ง ๋ถ€ํŠธ๋Š” DefaultFormattingConversionService ๋ฅผ ์ƒ์† ๋ฐ›์€ WebConversionService๋ฅผ ๋‚ด๋ถ€์—์„œ ์‚ฌ์šฉํ•จ.

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
    
        //์ฃผ์„์ฒ˜๋ฆฌ ์šฐ์„ ์ˆœ์œ„
        // * MyNumberFormatter ๋„ ์ˆซ์ž ๋ฌธ์ž, ๋ฌธ์ž ์ˆซ์ž๋กœ ๋ณ€๊ฒฝํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‘˜์˜ ๊ธฐ๋Šฅ์ด ๊ฒน์นจ. 
        // * ์šฐ์„ ์ˆœ์œ„๋Š” ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ์šฐ์„ ํ•˜๋ฏ€๋กœ ํฌ๋งทํ„ฐ๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๊ณ , ์ปจ๋ฒ„ํ„ฐ๊ฐ€ ์ ์šฉ๋จ.
        //registry.addConverter(new StringToIntegerConverter());
        //registry.addConverter(new IntegerToStringConverter());

        registry.addConverter(new StringToIpPortConverter());
        registry.addConverter(new IpPortToStringConverter());
        
        //์ถ”๊ฐ€
        registry.addFormatter(new MyNumberFormatter());
    }
}

6) ์Šคํ”„๋ง์ด ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋ณธ Formatter

์Šคํ”„๋ง์€ ์ž๋ฐ”์—์„œ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ํƒ€์ž…๋“ค์— ๋Œ€ํ•ด ์ˆ˜ ๋งŽ์€ Formatter๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต.


IDE์—์„œ Formatter ์ธํ„ฐํŽ˜์ด์Šค์˜ ๊ตฌํ˜„ ํด๋ž˜์Šค๋ฅผ ์ฐพ์•„๋ณด๋ฉด ์ˆ˜ ๋งŽ์€ ๋‚ ์งœ๋‚˜ ์‹œ๊ฐ„ ๊ด€๋ จ ํฌ๋งทํ„ฐ๊ฐ€ ์ œ๊ณต๋˜๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅ
๊ทธ๋Ÿฐ๋ฐ Formatter๋Š” ๊ธฐ๋ณธ ํ˜•์‹์ด ์ง€์ •๋˜์–ด ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๊ฐ์ฒด์˜ ๊ฐ ํ•„๋“œ๋งˆ๋‹ค ๋‹ค๋ฅธ ํ˜•์‹์œผ๋กœ ํฌ๋งท์„ ์ง€์ •ํ•˜๊ธฐ๋Š” ์–ด๋ ต๋‹ค.


์ด๋Ÿฐ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์• ๋…ธํ…Œ์ด์…˜ ๊ธฐ๋ฐ˜์œผ๋กœ ์›ํ•˜๋Š” ํ˜•์‹์„ ์ง€์ •ํ•ด์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋งค์šฐ ์œ ์šฉํ•œ Formatter 2๊ฐ€์ง€๋ฅผ ๊ธฐ๋ณธ์œผ๋กœ ์ œ๊ณต.
@NumberFormat : ์ˆซ์ž ๊ด€๋ จ ํ˜•์‹ ์ง€์ • Formatter ์‚ฌ์šฉ
@DateTimeFormat : ๋‚ ์งœ ๊ด€๋ จ ํ˜•์‹ ์ง€์ • Formatter ์‚ฌ์šฉ

@Controller
public class FormatterController {

    @GetMapping("/formatter/edit")
    public String formatterForm(Model model) {
    
        Form form = new Form();
        form.setNumber(10000);
        form.setLocalDateTime(LocalDateTime.now());
        
        model.addAttribute("form", form);
        return "formatter-form";
    }
    
    @PostMapping("/formatter/edit")
    public String formatterEdit(@ModelAttribute Form form) {
        return "formatter-view";
    }
    
    @Data
    static class Form {
    
        @NumberFormat(pattern = "###,###")
        private Integer number;
        
        @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
        private LocalDateTime localDateTime;
    }
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form th:object="${form}" th:method="post">
        number <input type="text" th:field="*{number}"><br/>
        localDateTime <input type="text" th:field="*{localDateTime}"><br/>
        <input type="submit"/>
    </form>
</body>
</html>
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
	<title>Title</title>
</head>
<body>
    <ul>
        <li>${form.number}: <span th:text="${form.number}" ></span></li>
        <li>${{form.number}}: <span th:text="${{form.number}}" ></span></li>
        <li>${form.localDateTime}: <span th:text="${form.localDateTime}" ></span></li>
        <li>${{form.localDateTime}}: <span th:text="${{form.localDateTime}}" ></span></li>
    </ul>
</body>
</html>

7) ConversionService์™€ HttpMessageConverter

๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ(HttpMessageConverter)์—๋Š” ConversionService๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.


๊ฐ์ฒด ↔ JSON ์œผ๋กœ ๋ณ€ํ™˜ํ•  ๋•Œ HttpMessageConverter๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด์„œ ์ด ๋ถ€๋ถ„์„ ๋งŽ์ด ์ฐฉ๊ฐํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค. HttpMessageConverter ์˜ ์—ญํ• ์€ HTTP ๋ฉ”์‹œ์ง€ body์˜ ๋‚ด์šฉ์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๊ฑฐ๋‚˜ ๊ฐ์ฒด๋ฅผ HTTP ๋ฉ”์‹œ์ง€ ๋ฐ”๋””์— ์ž…๋ ฅํ•˜๋Š” ๊ฒƒ์ด๋‹ค. 

(HttpMessage body ↔ ๊ฐ์ฒด)

 

JSON์„ ๊ฐ์ฒด๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๋ฉ”์‹œ์ง€ ์ปจ๋ฒ„ํ„ฐ๋Š” ๋‚ด๋ถ€์—์„œ Jackson ๊ฐ™์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.

๊ฐ์ฒด๋ฅผ JSON์œผ๋กœ ๋ณ€ํ™˜ํ•œ๋‹ค๋ฉด ๊ทธ ๊ฒฐ๊ณผ๋Š” ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋‹ฌ๋ฆฐ ๊ฒƒ.

๋”ฐ๋ผ์„œ JSON ๊ฒฐ๊ณผ๋กœ ๋งŒ๋“ค์–ด์ง€๋Š” ์ˆซ์ž๋‚˜ ๋‚ ์งœ ํฌ๋งท์„ ๋ณ€๊ฒฝํ•˜๊ณ  ์‹ถ์œผ๋ฉด ํ•ด๋‹น ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ์„ค์ •์„ ํ†ตํ•ด์„œ ํฌ๋งท์„ ์ง€์ •ํ•ด์•ผ ํ•œ๋‹ค. 

 

๊ฒฐ๊ณผ์ ์œผ๋กœ ์ด๊ฒƒ์€ ์ปจ๋ฒ„์ „ ์„œ๋น„์Šค์™€ ์ „ํ˜€ ๊ด€๊ณ„๊ฐ€ ์—†๋‹ค.
์ปจ๋ฒ„์ „ ์„œ๋น„์Šค๋Š” @RequestParam , @ModelAttribute , @PathVariable , ๋ทฐ ํ…œํ”Œ๋ฆฟ ๋“ฑ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.


๐Ÿ“™ 2. ํŒŒ์ผ ์—…๋กœ๋“œ

1) HTML Form ์ „์†ก๋ฐฉ์‹ 2๊ฐ€์ง€

1. application/x-www-form-urlencoded → form ํƒœ๊ทธ์— ๋ณ„๋„ enctype ์˜ต์…˜์—†์ด ์ „์†ก

  • ์›น ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ HTTP ๋ฉ”์‹œ์ง€์˜ ํ—ค๋”์— ๋‹ค์Œ๋‚ด์šฉ์„ ์ถ”๊ฐ€ํ•œ๋‹ค. Content-Type: application/x-www-form-urlencoded
  • ํผ์— ์ž…๋ ฅํ•œ ์ „์†กํ•  ํ•ญ๋ชฉ์„ HTTP Body์— ๋ฌธ์ž๋กœ username=kim&age=20 ์™€ ๊ฐ™์ด & ๋กœ ๊ตฌ๋ถ„ํ•ด์„œ ์ „์†ก

2. multipart/form-data → form ํƒœ๊ทธ์— ๋ณ„๋„ enctype ์˜ต์…˜์ถ”๊ฐ€,  multipart/form-data ๋ผ๋Š” ์ „์†ก ๋ฐฉ์‹ ์‚ฌ์šฉ

  • multipart/form-data ๋ฐฉ์‹์€ ๋‹ค๋ฅธ ์ข…๋ฅ˜์˜ ์—ฌ๋Ÿฌ ํŒŒ์ผ๊ณผ ํผ์˜ ๋‚ด์šฉ ํ•จ๊ป˜ ์ „์†ก ๊ฐ€๋Šฅ.
POST /save HTTP/1.1
Host: localhost:8080
Content-Type: multipart/form-data; boundary=------XXX
Content-Length: 34521

------XXX
Content-Disposition: form-data; name="username"

kim
------XXX
Content-Disposition: form-data; name="age"

20
------XXX
Content-Disposition: form-data; name="file1"; filename="img32.png"
Content-Type: image/png

12dfkli1k1k23kj3kkj4
------XXX--

2) ์„œ๋ฒ„์—์„œ multipart/form-data ๋ฉ”์„ธ์ง€ ์‚ฌ์šฉ

 

 

 


๐Ÿ“š Reference

์œ„ ํ•™์Šต ์š”์•ฝ์€ ๊น€์˜ํ•œ๋‹˜์˜ '์Šคํ”„๋ง MVC ๊ฐ•์˜ 2ํŽธ' ์„ ๊ธฐ์ดˆ๋กœ ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

๋Œ“๊ธ€