ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 스프링 타입 컨버터
    스프링/스프링 MVC 패턴 2023. 3. 7. 15:14

    반환 타입을 수정해야할 일이 있다. 스프링은 컨버터라는 변환기로 타입의 변환을 자동으로 시켜준다.

     

     

    컨버터 직접 구현

    @Getter
    @EqualsAndHashCode
    public class IpPort {
    
        private String ip;
        private int port;
    
        public IpPort(String ip, int port) {
            this.ip = ip;
            this.port = port;
        }
    }

    ipPort라는 타입을 만들어주고 stirng 타입에서 IpPort 타입으로 변경해 볼 것이다.

    @Slf4j
    public class StringToIntegerConverter implements Converter<String, Integer> {
    
        @Override
        public Integer convert(String source) {
            log.info("convert source={}", source);
            return Integer.valueOf(source);
        }
    }

    그냥 간단하게 source를 파라미터로 받고 Integer로 바꿔서 리턴해주면 된다.

     

     

     

    스프링 ConversionService

     

    public class ConversionServiceTest {
    
        @Test
        void conversionService() {
            // 등록
            DefaultConversionService conversionService = new DefaultConversionService();
            conversionService.addConverter(new StringToIntegerConverter());
            conversionService.addConverter(new IntegerToStringConverter());
            conversionService.addConverter(new StringToIpPortConverter());
            conversionService.addConverter(new IpPortToStringConverter());
    
            // 사용
            assertThat(conversionService.convert("10", Integer.class)).isEqualTo(10);
            assertThat(conversionService.convert(10, String.class)).isEqualTo("10");
    
            IpPort ipPort = conversionService.convert("127.0.0.1:8080", IpPort.class);
            assertThat(ipPort).isEqualTo(new IpPort("127.0.0.1", 8080));
    
            String ipPortString = conversionService.convert(new IpPort("127.0.0.1", 8080), String.class);
            assertThat(ipPortString).isEqualTo("127.0.0.1:8080");
        }
    }

    매번 위와 같이 컨버터를 만들어서 변환을 해주는 것은 불편할 수가 있다. 그래서 conversionService라는 기능을 제공한다. 이 conversionSerivce에 addConverter로 컨버터들을 등록을 하면 굳이 여러개의 컨버터를 찾을 필요 없이 conversionService.convert(a, b)에 a와 b값에 해당 변수를 넣으면 자동으로 타입 변환이 이루어진다.

    (addConverter로 들어간 컨버터들은 직접 클래스에서 구현했던 컨버터들)

     

    위에서는 테스트를 보기 위해서 등록, 사용을 한 클래스에 했는데 원래는 등록, 사용은 분리해놓고 의존관계 주입을 통해 사용하여 기능을 분리해야만 한다.

     

     

     

    뷰 템플릿에서의 컨버터

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
    
        @Override
        public void addFormatters(FormatterRegistry registry) {
            registry.addConverter(new StringToIpPortConverter());
            registry.addConverter(new StringToIntegerConverter());
            registry.addConverter(new IpPortToStringConverter());
            registry.addConverter(new IntegerToStringConverter());
        }
    }

    WebConfig.class에 addFormatters를 이용해서 컨버터들을 등록해준다.

     

     

    @GetMapping("/converter-view")
    public String converterView(Model model) {
        model.addAttribute("number", 10000);
        model.addAttribute("ipPort", new IpPort("127.0.0.1", 8080));
        return "converter-view";
    }

    converter-view 매핑 메소드이다.

    <!DOCTYPE html>
    <html xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <ul>
        <li>${number}: <span th:text="${number}" ></span></li>
        <li>${{number}}: <span th:text="${{number}}" ></span></li>
        <li>${ipPort}: <span th:text="${ipPort}" ></span></li>
        <li>${{ipPort}}: <span th:text="${{ipPort}}" ></span></li>
    </ul>
    
    </body>
    </html>

    converter-view.html인데, 컨버터를 적용시키려면 ${ipPort}가 아닌 ${{ipPort}} 라 해야한다. 대괄호가 두 개 있다는 뜻인 뷰 템플릿에서 자동으로 컨버터를 이용해서 타입을 변환시켜준다는 것이다.

     

     

     

    @GetMapping("/converter/edit")
    public String converterForm(Model model) {
        IpPort ipPort = new IpPort("127.0.0.1", 8080);
        Form form = new Form(ipPort);
        model.addAttribute("form", form);
        return "converter-form";
        // converter-form에서 th:field는 컨버터 자동
        // converter 안하려면 th:value를 사용
    }
    
    @PostMapping("/converter/edit")
    public String converterEdit(@ModelAttribute Form form, Model model) {
        IpPort ipPort = form.getIpPort();
        model.addAttribute("ipPort", ipPort);
        return "converter-view";
    }
    
    @Data
    static class Form {
        private IpPort ipPort;
    
        public Form(IpPort ipPort) {
            this.ipPort = ipPort;
        }
    }

    두 번째로 다른 방법도 있는데 thymeleaf를 이용한 방법이다.

    th:field는 대괄호를 2개 하지 않아도 자동으로 컨버터를 불러와서 타입 변환을 시켜준다. th:value는 컨버터가 호출이 안되기때문에 th:field는 타입 변환을 사용하고 싶을 때 사용하면 된다.

    <!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">
        th:field <input type="text" th:field="*{ipPort}"><br/>
        th:value <input type="text" th:value="*{ipPort}">(보여주기 용도)<br/>
        <input type="submit"/>
    </form>
    
    </body>
    </html>

     

     

    th:field만 변환이 된다. 웹 사이트에서 IpPort 객체가 String으로 변환되어서 보여지는 것이다.

     

    사용자에게 보여줄 때에는 객체를 문자형으로, 폼에서 문자가 넘어올 때(@PostMapping)는 문자를 객체로 변환시켜주는 것을 확인할 수 있다.

     

    문자를 객체로 변환시켜서 대괄호를 하나만 했을 때에는 객체가 출력된다.

Designed by Tistory.