데이터 바인딩 추상화 PropertyEditor ,
데이터바인딩은 도메인 모델의 프로퍼티에 값을 할당해주는 기능을 말한다.
사용자의 입력값은 대부분 문자열이지만 이를 int long Boolean Date , 커스텀 도메인 등으로 변환해주는 기능을 가지는 강력한 녀석이다.
PropertyEditor를 사용하는 DataBinder는 스프링 Mvc에 많이 사용하는데 xml설정파일의 문자열을 빈의 타입으로 변환할때, springEL 에서도 사용되는 녀석이다.
일단 rest방식의 컨트롤러를 놓고 @PathVariable 어노테이션으로 경로변수 값을 할당받아 자동으로 Event객체로 맵핑되는지 확인해본다.
@RestController
public class EventController {
@GetMapping("/event/{event}")
public String getEvent(@PathVariable Event event){
System.out.println(event);
return event.getId().toString();
}
}
public class Event {
private Integer id;
private String title;
public Event(Integer id) {
this.id = id;
}
public Integer getId() {
return id;
}
@Override
public String toString() {
return "Event{" +
"id=" + id +
", title='" + title + '\'' +
'}';
}
}
org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
org.springframework.test.web.servlet.result.MockMvcResultMatchers.content
org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
스테틱 메소드 호출 명단.
@RunWith(SpringRunner.class)
@WebMvcTest
class EventControllerTest {
@Autowired
MockMvc mockMvc;
@Test
public void getTest() throws Exception {
mockMvc.perform(get("/event/1"))
.andExpect(status().isOk())
.andExpect(content().string("1"));
}
}
해당테스트 는 실패한다. 응답은 500 이며, String 을 Event 타입으로 변환하지 못하였다는 메시지가뜬다.
이에 해당하는 PropertyEditor나 ConversionService 가 필요하다는 의미이다.
ConversionService는 WebDataBinder가 프로퍼티에대한 변환이나 값에대한 프로퍼티 변환 둘다를 위임하는 객체라는 것을 기억하고 있다.
여기서는 PropertyEditor를 사용할 것이므로, 구현객체를 만듦이 필요하다.
-
ProperyEditor를 구현하는 것도 가능하나 재정의할 메서드가 굉장히많다.
-
그러므로 PropertyEditorSupport 클래스를 상속받아 사용함이 이롭다.
-
자주 쓰이는 것은 getAsText() , setAsText() 메서드.
-
프로퍼티 에디터가 가진 값이나 객체를 받아오는 것이 getAsText()
-
들어온 텍스트를 원하는 타입이나 값으로 변환시켜 저장시키는 것이 setAsText()
-
수동 구현이며, getValue()로 값을 꺼내오고 Object 리턴타입.
-
setValue()로 값을 저장한다.
import java.beans.PropertyEditorSupport;
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)));// setValue 라는 메서드에 변환할 클래스를 생성하여 변환시킴, 매개변수인 text는 들어오는 값이다.
}
}
-
주의할 점은 PropertyEditorSupport 상속 "객체가 가지고 있는 값" 이므로 Thread-Safe 하지 않다!
-
그러므로 여러개의 쓰레드가 공유하면 값이 뒤섞여바뀌어 버릴 수있다.
-
이는 즉, static pool을 공유하는 SpringBean 으로 만들어사용하면 매우매우 위험하다는 것이다.
-
절대로 빈으로 사용하지 않음이 안전하며, DataBinder 구현객체에 등록시켜 사용하는 것이 이롭다.
컨트롤러 범위 Validation을 할때 사용했었던 @InitBinder 인데, 매개변수가 WebDataBinder 즉 DataBinder의 구현객체이다.
-
WebDataBinder 의 .registerCustomEditor( Type.class , PropertyEditor ) 메서드를 사용하여 컨트롤러 범위 데이터 바인더를 등록해주는 방법이있다.
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
@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{id=1, title='null'}
쓰레드에 안전하지 않고,
불편한 점이 많으므로, 스프링 3버전 이상부터 Formatter 와 Converter가 추가되었다.
'springframework' 카테고리의 다른 글
o.s.w IoC 핵심기술. SpEL (스프링 Expression Language) (0) | 2020.09.17 |
---|---|
o.s.w IoC 핵심기술. 데이터 바인딩 추상화: Converter와 Formatter (0) | 2020.09.16 |
파일업로드의 고민점, (지속적으로 추가 예정..) (0) | 2020.09.07 |
MultipartFile 의 메서드 (0) | 2020.09.06 |
파일 업로드의 기본 설정 (0) | 2020.09.06 |