study/springboot
012. Request Parameter에 converter 및 formatter 전체 적용
까오기
2022. 5. 14. 12:45
환경 설정을 통한 일괄 적용
@Configuration
public class WebMvcConfiguration extends WebMvcConfigurationSupport {
...
@Autowired(required = false)
private Converter<?, ?>[] converters;
@Override
public void addFormatters(FormatterRegistry registry) {
if(converters != null) {
for(final Converter<?, ?> converter : converters) {
registry.addConverter(converter);
}
}
NumberStyleFormatter numberFormatter = new NumberStyleFormatter();
numberFormatter.setPattern("#,###,###,###.##");
registry.addFormatter(numberFormatter);
}
}
WebMvcConfiguration에서 addFormatters에 사용자 Converter를 설정하면 전체 요청에 대해 일괄 적용이 가능합니다.
@Component
public class StringToDateConverter implements Converter<String, Date> {
private final static String DATE_FORMAT = "yyyyy-MM-dd";
@Override
public Date convert(String source) {
SimpleDateFormat format = new SimpleDateFormat(DATE_FORMAT);
try {
return format.parse(source);
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
@Component
public class StringToDateTimeConverter implements Converter<String, Timestamp> {
private final static String DATETIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Override
public Timestamp convert(String source) {
SimpleDateFormat format = new SimpleDateFormat(DATETIME_FORMAT);
try {
Date parsedDate = format.parse(source);
return new java.sql.Timestamp(parsedDate.getTime());
} catch (ParseException e) {
e.printStackTrace();
return null;
}
}
}
@Component
public class StringTrimConverter implements Converter<String, String> {
@Override
public String convert(String source) {
if(source == null) return source;
return source.trim();
}
}
위에 예제 소스를 보면 정말 간단하게 만들어졌다는 걸 알 수 있습니다.
개발자가 요청을 받아서 처리하는 반복적인 작업들이 있다면 Converter로 만들어 두면 정말 편리합니다.
Converter는 @Component로 만들어서 @Configuration에서 자동 injection이 되게 합니다.
@Autowired(required = false)
private Converter<?, ?>[] converters;
이렇게 설정을 하면 number format, date 관련 설정 등을 완료 한 것입니다.
예제 코드
@Slf4j
@RestController
@RequestMapping("/controller/request/config")
public class RequestParam03APIController {
/**
* date 타입 받기 yyyy-MM-dd
* @return
*/
@PostMapping("/date")
public ResponseEntity<String> dateMapping(@RequestParam final Date param) {
return ResponseEntity.ok(DateUtil.formatDate(param, "yyyy/MM/dd"));
}
/**
* 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<RequestParams03> requestParamObject(final RequestParams03 params) {
log(params.toString());
return ResponseEntity.ok(params);
}
private void log(String message) {
log.debug("parameters : " + message);
}
@Getter
@Setter
@ToString
public static class RequestParams03 {
private String id;
private String name;
private Boolean test;
private Date created;
private Double dbl;
private Long lng;
public RequestParams03() {
super();
}
public RequestParams03(String id, String name, Date created) {
super();
this.id = id;
this.name = name;
this.created = created;
}
}
}
위에 코드를 보면 이전에 보이던 format, convert, @InitBinder 관련 설정이 모두 제거 된것을 확인 할 수 있습니다.
그래도 정상 작동하는지 테스트해 봅니다.
@SpringBootTest
@AutoConfigureMockMvc
class RequestParam03APIControllerTest {
@Autowired
private MockMvc mockMvc;
private RequestParams03 getRequestParams03() {
return new RequestParams03("test", " 테스트 ", DateUtil.parseDate("2022-05-12"));
}
@Test
void dateMapping() throws Exception {
RequestParams03 param = getRequestParams03();
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/controller/request/config/date")
.param("param", DateUtil.formatDate(param.getCreated()))
.accept(MediaType.TEXT_PLAIN)
)
.andExpect(status().isOk())
.andReturn();
assertThat(result.getResponse().getContentAsString()).isEqualTo(DateUtil.formatDate(param.getCreated(), "yyyy/MM/dd"));
}
@Test
void doubleMapping() throws Exception {
String param = "12,000.12";
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/controller/request/config/double")
.param("param", param)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON))
// .andDo(print())
.andExpect(status().isOk())
.andReturn();
assertThat(result.getResponse().getContentAsString()).isEqualTo("12000.12");
}
@Test
void objectMapping() throws Exception {
RequestParams03 params = getRequestParams03();
mockMvc.perform(MockMvcRequestBuilders.post("/controller/request/config/params")
.param("id", params.getId())
.param("name", params.getName())
.param("test", "yes")
.param("created", DateUtil.formatDate(params.getCreated()))
.param("dbl", "12,000.12")
.param("lng", "12,000.12")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON))
.andDo(print())
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(params.getName().trim()))
.andExpect(jsonPath("$.id").value(params.getId()))
.andExpect(jsonPath("$.dbl").value(12000.12))
.andExpect(jsonPath("$.lng").value(12000))
;
}
}
github : https://github.com/kkaok/study-springboot/tree/main/src/main/java/eblo/study/springboot/controller