본문 바로가기

개발/Spring

데이터 바인딩 추상화: PropertyEditor

반응형

org.springframework.validation.DataBinder

데이터 바인딩이란?
 - 프로퍼티 값을 타겟 객체에 설정하는 기능
 - 사용자가 입력한 값을 application domain 객체에 동적으로 할당하는 기능
    사용자가 입력한 값은 보통 문자열   
    객체가 가지고있는 값의 타입은 다양한 스트링, int, 객체 자체 등등 각각에 맞게 변환하여 바인딩 해주는 것.

PropertyEditor
 - 스프링 3.0 이전까지 DataBinder 가 변환 작업 사용하던 인터페이스 
 - ApplicationContext를 xml 파일로 설정할때, xml 파일에 입력한 문자열을 빈이 가지고 있는 적절한 타입으로 변환하여 넣어줄때 사용되었음.
 - 쓰레드 세이프 하지 않다. (상태 정보 저장 하고 있다. 따라서 싱글톤 빈으로 등록해서 쓰다가는 .. 안됀다)
 - Obejct 와 String 간의 변환만 할 수 있어, 사용 범위가 제한적이다. 하지만 잘써왔다.

 

- String 을 객체로 만들기
 1) controller 

package com.bpkim.demospring51;

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();
    }
}

2) 사용할 클래스파일 Event

package com.bpkim.demospring51;

public class Event {
    Integer id ;

    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 + '\'' +
                '}';
    }
}

3) Test

package com.bpkim.demospring51;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@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 실행 결과 
 에러! 받은 string 값을 바로 객체로 바인딩 하지 못해 에러가 발생! >> BindEditor 생성

4) BinderEditor 생성
 - PropertyEditor 를 상속하면 인터페이스이므로 구현해야할 함수가 많아 PropertyEditorSupport 를 상속하여 필요한 두 함수만 구현
  setAsText > Text 값을 객체로 변환 
  getAsText > 객체 값을 Text 로 변환

package com.bpkim.demospring51;

import java.beans.PropertyEditorSupport;

public class EventEditor extends PropertyEditorSupport {

    @Override
    public String getAsText() {
        // getValue() 객체를 가져온다.
        // Event 타입으로 변환
        Event event = (Event)getValue();

        // Event 의 id 를 리턴
        return event.getId().toString();
    }

    // Text 를 Event 로 변환
    @Override
    public void setAsText(String text) throws IllegalArgumentException {

        // text 를 이용해 그대로 객체 생성하여 setValue
        setValue(new Event(Integer.parseInt(text)));

    }

    /*
        setValue 한 값은 상태 정보를 저장하고있다.
        Theread safe 하지 않다.
        propertyEditor의 구현체는 여러 스레드에 공유해서 쓰면 안된다. >> Bean 으로 등록하여 사용해선 안된다.
        theread scope 로 등록해서 사용하면 되지만...  전혀 빈으로 등록하지 않는 것을 추천한다.

        @InnitBinder 로 컨트롤러에서 등록하여 사용하자
     */
}

 - PropertyEditor 특징
setValue 한 값은 상태 정보를 저장하고있다.
Theread safe 하지 않다.
propertyEditor의 구현체는 여러 스레드에 공유해서 쓰면 안된다. >> Bean 으로 등록하여 사용해선 안된다.
theread scope 로 등록해서 사용하면 되지만... 전혀 빈으로 등록하지 않는 것을 추천한다.

@InnitBinder 로 컨트롤러에서 등록하여 사용하자

5) 컨트롤러 수정

package com.bpkim.demospring51;

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);
        // event 에 들어온 값을 Event 객체로 변환 시켜줘야한다.
        // 그래서 변환 할 PropertyEditor을 만들어줘야 한다.

        return event.getId().toString();
    }
}


- 실행 결과 
 : 성공!
  event 객체를 출력한 모습도 확인 가능하다.

반응형

'개발 > Spring' 카테고리의 다른 글

SpEL(스프링 Expression Language)  (0) 2021.04.23
데이터 바인딩 추상화 Converter와 Formatter  (0) 2021.04.23
Validation 추상화  (0) 2021.04.22
Resource 추상화  (0) 2021.04.22
Ioc 컨테이너 - ResourceLoader  (0) 2021.04.22