[Spring] 스프링 데이터 바인딩 추상화 : PropertyEditor (Spring Editor Binding Abstraction : PropertyEditor)
| 스프링 데이터 바인딩( Spring Data Binding )
스프링에서는 사용자가 입력한 값을 타겟 객체에 설정하는 데이터 바인딩 기능을 지원한다. org.springframework.validation.DataBinder 인터페이스를 통해서 데이터 바인딩 기능을 지원하며 사용자가 입력한 값을 도메인 모델에 동적으로 변환해서 넣어준다.
이 기능이 필요한 이유는 다음과 같은 이유에서다. 사용자의 입력값은 대부분 문자열이지만 자바의 객체가 가지고 있는 데이터 타입은 int, long, Data, Double 혹은 사용자가 작성한 클래스로 만들어진 객체 Event, Book 같은 것이다. 따라서 사용자의 이런 문자열 입력값을 자바의 데이터 타입으로 변환해서 넣어줘야하는 데, 이때 적절하게 데이터를 넣어주는 데이터 바인딩이 필요한 것이다.
| PropertyEditor 인터페이스
스프링 3.0 이전까지 DataBinder가 변환 작업을 사용하던 인터페이스는 PropertyEditor였다. 이 PropertyEditor를 구현한 PropertyEditorSupport 클래스를 상속받아 데이터 바인딩용 클래스를 만든 코드는 다음과 같다.
public class Event {
Integer id;
String title;
public Event(Integer id) {
this.id = id;
}
public Event(Integer id, String title) {
this.id = id;
this.title = title;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Override
public String toString() {
return "Event{" +
"id=" + id +
", title='" + title + '\'' +
'}';
}
}
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)));
}
}
setAsText는 사용자가 입력한 데이터를 Event 객체로 변환해 주는 역할을 한다. 만일 /event/1 이라는 요청이 올 시 1이라는 데이터를 Event로 변환할 때 위 setAsText의 메서드가 호출되어 사용자 데이터를 변환한다.
getAsText는 프로퍼티가 받은 객체를 getValue 메서드를 통해 가져오고 이 Event 객체를 문자열 정보로 변환해서 반환하는 역할을 한다.
조심해야할 것은 EventEditor의 getValue와 setValue 메서드는 thread-safe하지 않다. 따라서 절대 스프링 빈으로 등록해서 쓰면 안된다.
위의 EventEditor는 빈으로 사용하지 않고 @InitBinder 어노테이션을 통해 컨트롤러에 데이터 바인더로서 등록할 수 있다. 참고로 @PathVariable은 URL경로에 변수를 넣어주는 기능을 한다.
@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();
}
}
아래의 테스트 케이스는 스프링 어플리케이션에 /event/1 요청을 하고 요청을 통해서 받은 데이터가 1인지 체크하는 테스트를 작성한 것이다. 만일 위 코드를 제대로 작성했다면 테스트 케이스가 무리없이 통과될 것이다.
@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"));
}
}
참고자료 : https://www.inflearn.com/course/spring-framework_core/