caffeine-library / pro-spring-5

🌱 전문가를 위한 스프링5를 읽는 스터디
5 stars 0 forks source link

[keyword] 10장 타입 변환과 포매팅을 사용해 유효성 검증하기 키워드 정리 #74

Closed wooyounggggg closed 3 years ago

wooyounggggg commented 3 years ago

주제

10장 타입 변환과 포매팅을 사용해 유효성 검증하기를 읽고 중요✨ 하다고 생각하는 키워드와 선택한 이유에 대해서 코멘트로 달아주세요.

연관챕터

73

JasonYoo1995 commented 3 years ago

스프링에서 유효성 검증

1. 스프링 Validator 인터페이스 사용

  1. 자바 구성 클래스에 LocalValidatorFactoryBean 선언

  2. SingerValidationService 클래스 생성

binchoo commented 3 years ago

프로퍼티 에디터 복습

요구사항

Singer 엔터티의 birthDate 필드의 타입은 org.joda.time.DateTime입니다.

그런데 XML 구성이나 프로퍼티 파일에 "yyyy-mm-dd" 형식을 지키는 String을 사용할 겁니다.

따라서 문자열을 bithDate 필드에 요다 타임 타입으로 바인딩 해줄 도구가 필요합니다.

(PropertyEditor는 문자열을 특정 타입으로 변환하는 데 적합)

CustomEditorConfigurer 구성 모습

image

관련 메소드 시그니쳐

PropertyEditorRegistrar

메서드 인자로 프로퍼티 저장소 객체를 전달받습니다. 아마 CustomEditorConfigurer 쪽에서 넣어주는 것 같죠? 해당 저장소에 커스텀 프로퍼티 에티터들을 등록하도록 설계되어있습니다.

public interface PropertyEditorRegistrar {
    void registerCustomEditors(PropertyEditorRegistry registry);
}

PropertyEditor

프로퍼티 에디터 구현체 PropertyEditorSupport 입니다.

public class PropertyEditorSupport implements PropertyEditor {
    public void setAsText(String text) throws java.lang.IllegalArgumentException {
        if (value instanceof String) {
            setValue(text);
            return;
        }
        throw new java.lang.IllegalArgumentException(text);
    }

    public void setValue(Object value) {
        this.value = value;
        firePropertyChange();
    }

    public void getValue(Object value) {
        return this.value;
    }

구현

책에서 "문자열->요다 타임" 변환이 setAsText(text: String) 에서 구현됩니다.

public class DateTimeEditorRegistrar implements PropertyEditorRegistrar {
    private DateTimeFormatter dateTimeFormatter;

    public DateTimeEditorRegistrar(String dateFormatPattern) {
        dateTimeFormatter = DateTimeFormat.forPattern(dateFormatPattern);
    }

    // 커스텀 프로퍼티 에디터를 저장소에 등록
    @Override
    public void registerCustomEditors(PropertyEditorRegistry registry) {
        registry.registerCustomEditor(DateTime.class, new DateTimeEditor(dateTimeFormatter));
    }

    // 문자열 -> 요다 타입 매핑을 구현하는 커스텀 프로퍼티 에디터
    private static class DateTimeEditor extends PropertyEditorSupport {
        private DateTimeFormatter dateTimeFormatter;

        public DateTimeEditor(DateTimeFormatter dateTimeFormatter) {
            this.dateTimeFormatter = dateTimeFormatter;
        }

        // 문자열 -> 요다 타입 매핑 로직을 구현
        @Override
        public void setAsText(String text) throws IllegalArgumentException {
            setValue(DateTime.parse(text, dateTimeFormatter));
        }
    }
}
emiling commented 3 years ago

스프링 데이터 바인딩

image

Converter

컨버터 정의

public class EventConverter {
    public static class StringToEventConverter implements Converter<String, Event> {
        @Override
        public Event convert(String s) {
            return new Event(Integer.parseInt(s));
        }
    }
    public static class EventToStringConvert implements Converter<Event, String> {
        @Override
        public String convert(Event event) {
            return event.getId().toString();
        }
    }
}

ConversionService

@Configuration
public class AppConfig {
    @Bean
    public ConversionServiceFactoryBean conversionService() {
        ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
        Set<Converter> convs = new HashSet<>();
        convs.add(StringToEventConverter());
        convs.add(EventToStringConvert());
        conversionServiceFactoryBean.setConverters(convs);
        conversionServiceFactoryBean.afterPropertiesSet();
        return conversionServiceFactoryBean;
    }

    @Bean
    StringToDateTimeConverter converter() {
        return new StringToDateTimeConverter();
    }
//
    @Bean
    SingerToAnotherSingerConverter singerConverter() {
        return new SingerToAnotherSingerConverter();
    }

}

Formatter

포매터 정의

public class DateTimeFormatter implements Formatter<DateTime> {

    private static final String DEFAULT_DATE_PATTERN = "yyyy-MM-dd";
    private String datePattern = DEFAULT_DATE_PATTERN;
    private DateTimeFormatter dateFormat;

    @PostConstruct
    public void init() {
        dateFormat = DateTimeFormat.forPattern(datePattern);
    }

    @Override
    public DateTime parse(String dateTimeString, Locale locale) throws ParseException {
        return dateFormat.parseDateTime(dateTimeString);
    }

    @Override
    public String print(DateTime dateTime, Locale locale) {
        return dateFormat.print(dateTime);
    }
}

ConversionService

@Configuration
public class AppConfig {
    @Bean
    public FormattingConversionServiceFactoryBean conversionService() {
        FormattingConversionServiceFactoryBean formattingConversionServiceFactoryBean
                = new FormattingConversionServiceFactoryBean();
        Set<Formatter> formatters = new HashSet<>();
        formatters.add(dateTimeFormatter());
        formattingConversionServiceFactoryBean.setFormatters(formatters);
        formattingConversionServiceFactoryBean.afterPropertiesSet();
        return formattingConversionServiceFactoryBean;
    }

}

또 다른 방법

기타 사용법

Spring MVC

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addConverter(new StringToEventConverter());
        registry.addFormatter(new EventFormatter());
    }
}

Springboot

public class EventConverter {

    @Component
    public static class StringToEventConverter implements Converter<String, Event> {
        @Override
        public Event convert(String s) {
            return new Event(Integer.parseInt(s));
        }
    }

    @Component
    public static class EventToStringConvert implements Converter<Event, String> {
        @Override
        public String convert(Event event) {
            return event.getId().toString();
        }
    }
}