ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring MVC(2) - 스프링 타입 컨버터
    Web/Spring 2023. 11. 21. 11:04

     

    1. 타입 컨버터란?

     

    - 문자를 숫자로 변환하거나, 숫자를 문자로 변환하는 일이 굉장히 많음

    - 기존 스프링을 사용하면서 @RequestParam, @ModelAttribute, @Pathvariable에서 이게 가능했음 (자동)

       추가로 @Value를 통해 정보읽기, XML에 넣은 스프링 빈 정보 변환 + 뷰 렌더링 

       (요청파라미터, @Value, 뷰렌더링)

    - 개발자가 직접 새로운 타입을 정의하고, 이에 맞는 타입 컨버터를 등록하고 싶다면 어떻게 해야할까?

     

    package org.springframework.core.convert.converter;
    public interface Converter<S, T> {
     T convert(S source);
    }

     

    - 스프링은 확장 가능한 컨버터 인터페이스를 제공함! 

    - 추가적인 타입 변환이 필요하면 위 인터페이스를 구현하고, 등록하면 된다.

     

    * (org.springframework.core.convert.converter.Converter를 import해서 사용하도록 주의하자)

     

    2. 타입 컨버터 만들어보기

     

    2.1 String,Integer

     

    
    public class StringToIntegerConverter implements Converter<String, Integer> {
    
    	public Integer convert(String source){
        	return Integer.valueOf(source);
        }
    
    }
    
    public class IntegerToStringConverter implements Converter<Integer,String>{
    
    	public String convert(Integer source){
        	return String.valueOf(source);
        }
    }

     

    - 위와 같이 converter를 만들면, converter를 생성해서 자유롭게 활용 가능하다.

     

    @Test
    
    void stringToInteger(){
    		
            StringToIntegerConverter converter = new StringToIntegerConverter();
            Integer result = converter.convert("10");
            assertThat(result).isEqualTo(10);
    
    }

     

     

    2.2 사용자 정의 타입 컨버터 

     

    - 사용자 정의 타입

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

     

    - String, IpPort Converter

     

    public class StringToIpPortConverter implements Converter<String, IpPort> {
    
    	public IpPort convert(String source){
        
    		String[] split = source.split(":");
            String ip = split[0];
        	int port = Integer.parseInt(split[1]);
        	return new IpPort(ip,port);
        }
    
    }
    
    public class IpPortToStringConverter implements Converter<IpPort, String> {
     @Override
     public String convert(IpPort source) {
     
     return source.getIp() + ":" + source.getPort();
     }
    }

     

    > 타입 컨버터 인터페이스는 아주 단순해서 어렵진 않다! 

    > 이제 타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 제공하는 걸 배워보자 

     

    출처: 스프링MVC(2) 김영한 - 인프런

     

     

    3. 컨버전 서비스 - 컨버터 묶어서 편리하게 사용하기

     

    public interface ConversionService {
    boolean canConvert(@Nullable Class<?> sourceType, Class<?> targetType);
    boolean canConvert(@Nullable TypeDescriptor sourceType, TypeDescriptor 
    targetType);
    <T> T convert(@Nullable Object source, Class<T> targetType);
    Object convert(@Nullable Object source, @Nullable TypeDescriptor sourceType,
    TypeDescriptor targetType);
    }

     

     

    3.1 컨버전 서비스에 등록과 사용

     

    @Test
     void conversionService() {
     
     	DefaultConversionService conversionService = new DefaultConversionService();
        	
            //등록
        	conversionService.addConverter(new StringToIntegerConverter());
            conversionService.addConverter(new IntegerToStringConverter());
     		conversionService.addConverter(new StringToIpPortConverter());
     		conversionService.addConverter(new IpPortToStringConverter());
     		
            //사용
            conversionService.convert("10",Integer.class);
     		
            	
     }

     

    - 등록하는 경우에는 StringToIntegerConverter와 같은 타입 컨버터를 명확하게 알아야함

    - 사용하는 경우 정확하게 몰라도 됨 (컨버전 서비스 내부에 숨어서 제공됨)

    - 따라서 등록하는 경우와 사용하는 경우 다른 인터페이스에 의존해서 등록과 사용하면됨

      (구현체만 DefaultConversionService)

     

    * DefaultConversionService : ConversionService (사용), ConverterRegistry(등록) 두개의 인터페이스 구현 (ISP)

     

     

    4. 스프링에 Converter 적용하기

     

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

     

    - 스프링 내부에서 ConversionService를 제공함 따라서 WebMvcConfigurer에 addFormatters()를 사용해서 등록하면 됨

    - 스프링 내부에서 사용하는 ConversionService에 컨버터 추가해줌 

     

    * 기본 컨버터보다, 직접 등록한 컨버터의 우선순위가 더 높다.

     

    4.1 처리과정

     

    - @RequestParam -> ArgumentResolver만남 (RequestParamMethodArgumentResolver) 

    - 얘가 Argument를 집어넣는 과정에서 ConversionService를 사용해서 타입 변환을 시도 

     

     

    5. 뷰 템플릿에 컨버터 적용하기

     

    - 뷰에 컨버터를 적용하는 방법을 알아보자

    - 타임리프는 이러한 렌더링을 편리하게 제공함

    - 이제 객체 -> 문자 컨버팅

     

     @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";
     }

    -> 이렇게 view로 객체를 넘겨보자

     

    <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>

     

    -> ${}는 그냥 객체의 값을 사용하고 ${{}}을 사용하면, 컨버전 서비스의 컨버터를 사용해서 출력한다.

     

    * String -> 객체 : 항상 컨버터를 거쳐서 특정 객체로 변환된다.

      객체 -> String : 컨버터를 사용할 수도 있고 아닐 수도 있다.

     

     

    5.1 폼에 적용하기

     

    //폼에 기본값으로 넘겨주기 위해 
    @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";
     }
     
     //폼에서 넘어온 값을 Converting
     @PostMapping("/converter/edit")
     public String converterEdit(@ModelAttribute Form form, Model model) {
     IpPort ipPort = form.getIpPort();
     model.addAttribute("ipPort", ipPort);
     return "converter-view";
     }

     

    <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>

     

    - 폼에 (input태그 등)에 값을 출력할때는 field를 사용하면 컨버팅 된 값을

      보여주고 value를 사용하면 객체 값을 보여준다.

     

    *th field는 id,name을 출력하는 등 다양한 기능 제공한다. 컨버전 서비스도 함께 적용됨

Designed by Tistory.