on
데이터 바인딩 추상화: PropertyEditor
데이터 바인딩 추상화: PropertyEditor
org.springframework.valiation.DataBinder
기술적인 관점: 프로퍼티 값을 타켓 객체에 설정하는 기능.
사용자 관점: 사용자 입력값을 애플리케이션 도메인 모델에 동적으로 변환해 넣어주는 기능.
해석하자면: 입력값은 대부분 “문자열”인데, 그 값을 객체가 가지고 있는 int, long, Boolean, date 등 심지어 Event, Book 같은 도메인 타입으로도 변환해서 넣어주는 기술.
PropertyEditor
스프링 3.0 이전까지 DataBinder가 변환 작업 사용하던 인터페이스.
쓰레드-세이프 하지 않음 (상태 정보 저장 하고 있음. 따라서 싱글톤 빈으로 등록해서 쓰다가는..)
Object 와 String 간의 변환만 할 수 있어, 사용 범위가 제한적 임. (그래도 그런 경우가 대부분이기 때문에 잘 사용했음. 조심해서.. )
고전적인 방식의 데이터 바인딩
public class Event { private Integer id; private String title; public Event(Integer id) { this.id = id; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } @Override public String toString() { return "Event{" + "id=" + id + ", title='" + title + '\'' + '}'; } }
@RestController public class EventController { @GetMapping("/event/{event}") // 도메인으로 {event} 받고(숫자) Event 타입으로 바꿔서 public String getEvent(@PathVariable Event event){ // 도메인타입으로 코딩 System.out.println(event); return event.getId().toString(); } }
@RunWith(SpringRunner.class) @WebMvcTest public class EventControllerTest { @Autowired MockMvc mockMvc; @Test public void getTest() throws Exception{ mockMvc.perform(get("/event/1")) .andExpect(status().isOk()) .andExpect(content().string("1")); } }
test 코드 흐름
get “/event/1” 로 요청을 보냅니다. status 가 ok 인지 확인 요청을 받은 controller 가 {event} 를 Event 타입으로 바꾸고 요청받은 {1} 로 아이디를 반환하길 원함.
결과
2021-12-30 21:24:46.623 WARN 21920 --- [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'me.jsh.demospring51.Event'; nested exception is java.lang.IllegalArgumentException: 1]
요청받은 {1} 을 Event 타입으로 변환할 수 없기 때문에.
PropertyEditor를 만들기.
// 목적: 텍스트를 Event 타입으로 바꾸는 것. public class EventEditor extends PropertyEditorSupport { //필요한 메소드만 오버라이드 해서 구현해 주면됨. @Override public String getAsText() { Event event = (Event) getValue(); return event.getId().toString(); } @Override public void setAsText(String text) throws IllegalArgumentException { setValue(new Event(Integer.parseInt(text))); } }
빈으로 등록하면 안됨. 쓰레드 세이프하지않기 떄문. 여기서 getValue , setValue 의 value 는 propertyEditor 가 가지고 있는 값. 이 값이 서로다른 쓰레드에서 공유가 됨. 스테이트풀함.
구현자체도 편리하지 않음.
그럼 어떻게 사용하는가
@RestController public class EventController { @InitBinder public void init(WebDataBinder webDataBinder){ webDataBinder.registerCustomEditor(Event.class, new EventEditor()); } @GetMapping("/event/{event}") public String getEvent(@PathVariable Event event){ System.out.println(event); return event.getId().toString(); } }
@InitBinder 를 사용하여 binder를 등록해서 사용.
확인.
위의 문제들때문에, Spring3 부터는 데이터바인딩과 관련된 기능들과 인터페이스들이 추가되었습니다.
from http://in-intuition.tistory.com/48 by ccl(A) rewrite - 2021-12-30 23:01:44