-
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(); } }
> 타입 컨버터 인터페이스는 아주 단순해서 어렵진 않다!
> 이제 타입 컨버터를 등록하고 관리하면서 편리하게 변환 기능을 제공하는 걸 배워보자
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을 출력하는 등 다양한 기능 제공한다. 컨버전 서비스도 함께 적용됨
'Web > Spring' 카테고리의 다른 글
Spring MVC (2) - 예외 처리와 오류 페이지 (0) 2023.11.21 Spring MVC (2) - 스프링 포맷터 (0) 2023.11.21 SpringMVC 2 - 서블릿 필터와 인터셉터 (0) 2023.11.15 Spring MVC 2 - 검증 (2) BeanValidation (0) 2023.10.25 SpringMVC 2 - 검증 (0) 2023.10.24