티스토리 뷰

study/springboot

011. Controller @InitBinder

까오기 2022. 5. 14. 12:43

Date, DateTime, Boolean, enum, Number 타입 등 요청 값을 적절하게 포맷팅하고 컨버팅할 필요가 있습니다. 

이런 처리는 크게 세가지 방법으로 처리 가능합니다.   

1. 요청레벨 : 요청시 파라미터에서 설정으로 통해 처리하는 방법. 

2. 클래스레벨 : @InitBinder를 통해 해당 컨트롤러 전체에 동일 적용하는 방법. 

3. 프로젝트레벨 : WebMvcConfigurationSupport 설정을 통해 프로젝트 전체에 적용하는 방법 

 

요청레벨에 따른 처리 방법은 이전 글에 정리를 했고 이번에는 @InitBinder 부분입니다. 

실무에서는 주로 환경 설정을 통해 전체 적용하는 방법을 많이 쓰기 때문에 간단한 예제만 만들어 봤습니다. 

 

예제 

@Slf4j
@RestController
@RequestMapping("/controller/request/initbinder")
public class RequestParam02APIController {

    /**
     * class level convert : class 전체 적용 
     * @param webDataBinder
     * @param request
     */
    @InitBinder
    private void initBinder(WebDataBinder webDataBinder, WebRequest request) {
        // datetime format 설정 
        DateFormat datetimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        datetimeFormat.setLenient(false);
        webDataBinder.registerCustomEditor(Timestamp.class, new CustomDateEditor(datetimeFormat, true));
        // date format 설정 
        DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        webDataBinder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, true));
        // trim 설정 
        webDataBinder.registerCustomEditor(String.class, new StringTrimmerEditor(true));
        // number 관련 설정 
        NumberStyleFormatter numberFormatter = new NumberStyleFormatter();
        numberFormatter.setPattern("#,###,###,###.##");
        webDataBinder.addCustomFormatter(numberFormatter);
    }

    /**
     * date 타입 받기 yyyy-MM-dd 
     * @return
     */
    @PostMapping("/date")
    public ResponseEntity<String> dateMapping(@RequestParam final Date param) {
        String strDate = DateUtil.formatDate(param, "yyyy/MM/dd");
        log(strDate);
        return ResponseEntity.ok(strDate);
    }

    /**
     * 12,000.12 형태로 전달 받으면 12000.12로 변환 
     * @param pDouble
     * @return
     */
    @PostMapping("/double")
    public ResponseEntity<Double> doubleMapping(@RequestParam final Double param) {
        log(param.toString());
        return ResponseEntity.ok(param);
    }

    /**
     * 12,000.12 형태로 전달 받으면 12000로 변환 
     * @param pLong
     * @return
     */
    @PostMapping("/long")
    public ResponseEntity<Long> longMapping(@RequestParam final Long param) {
        log(param.toString());
        return ResponseEntity.ok(param);
    }

    /**
     * trim 처리 
     * @param pString
     * @return
     */
    @PostMapping("/trim")
    public ResponseEntity<String> trimMapping(@RequestParam final String param) {
        log(param);
        return ResponseEntity.ok(param);
    }

    @PostMapping("/params")
    public ResponseEntity<RequestParams02> requestParamObject(final RequestParams02 params) {
        log(params.toString());
        return ResponseEntity.ok(params);
    }
    
    /**
     * request parameters를 객체에서 받고 date 타입은 formate 지정을 한다.   
     * request level에서 convert 처리 
     * @return
     */
    @PostMapping("/body")
    public ResponseEntity<RequestParams02> requestParamBody(@RequestBody final RequestParams02 params) {
        return requestParamObject(params);
    }
    
    private void log(String message) {
        log.debug("parameters : "+message);
    }

    @Getter
    @Setter
    @ToString
    @Builder
    public static class RequestParams02 {
        private String id;
        private String name;
        private Boolean test;
        private Date created;
    }
}

이전 코드와 비교해 봤을 때 코그다 좀 더 간략하게 변한걸 확인 할 수 있습니다. 

 

테스트  

@WebMvcTest(controllers = RequestParam02APIController.class)
class RequestParam02APIControllerTest {

    @Autowired 
    private MockMvc mockMvc;
 
    private RequestParams02 getRequestParams02() {
        return new RequestParams02("test", "테스트", true, DateUtil.parseDate("2022-05-12"));
    }

    @ParameterizedTest
    @CsvSource(value = {
        "/controller/request/initbinder/date#2022-05-12#2022/05/12"
        ,"/controller/request/initbinder/double#12,000.12#12000.12"
        ,"/controller/request/initbinder/long#12,000.12#12000"
        ,"/controller/request/initbinder/trim# 12,000.12 #12,000.12"
        }, delimiterString="#")
    void dateMapping(String uri, String param, String expected) throws Exception {
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post(uri)
                .param("param", param)
                .contentType(MediaType.APPLICATION_JSON))
//                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
        assertThat(result.getResponse().getContentAsString()).isEqualTo(expected);
    }

    /**
     * 객체 매핑 테스트   
     * @throws Exception
     */
    @Test
    void objectMapping() throws Exception {
        RequestParams02 params = getRequestParams02();
        mockMvc.perform(MockMvcRequestBuilders.post("/controller/request/initbinder/params")
                .param("id", params.getId())
                .param("name", params.getName())
                .param("created", DateUtil.formatDate(params.getCreated()))
                .param("test", (params.getTest())? "yes":"no")
                .contentType(MediaType.APPLICATION_JSON))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name").value(params.getName().trim()))
                .andExpect(jsonPath("$.id").value(params.getId()));
    }
    
    /**
     * @RequestBody 테스트    
     * @throws Exception
     */
    @Test
    void bodyMapping() throws Exception {
        RequestParams02 params = getRequestParams02();
        ObjectMapper objectMapper = new ObjectMapper();
        String body = objectMapper.writeValueAsString(params);
        mockMvc.perform(MockMvcRequestBuilders.post("/controller/request/initbinder/body")
                .contentType(MediaType.APPLICATION_JSON)
                .content(body))
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.name").value(params.getName()))
                .andExpect(jsonPath("$.id").value(params.getId()));
    }
}

 코드를 작성해 보고 실행해 보면 @InitBinder가 어떤 역할을 하고 어떻게 작동하는지 확인이 될 겁니다. 

 

github소스

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함