Validation(2) 에서는 Library Application 의 /library/books [post] 요청에 대한 validation을 순차적으로 진행합니다.
@PostMapping("/library/books")
public String bookAdd(@ModelAttribute(name="bookInsertRequest") BookInsertRequestDto bookInsertRequestDto, Model model) {
int requestDtoNameLength = bookInsertRequestDto.getName().trim().length();
int requestDtoAuthorLength = bookInsertRequestDto.getAuthor().trim().length();
int requestDtoExpense = bookInsertRequestDto.getExpense();
if(requestDtoNameLength < 1 || requestDtoNameLength > 30) {
model.addAttribute("isError",true);
model.addAttribute("message","책 이름은 1자 이상 30자 이하로 입력해주세요.");
return "library/insert";
}
if (requestDtoAuthorLength < 1 || requestDtoAuthorLength > 30) {
model.addAttribute("isError",true);
model.addAttribute("message","저자 이름은 1자 이상 30자 이하로 입력해주세요");
return "library/insert";
}
if (requestDtoExpense < 0) {
model.addAttribute("isError",true);
model.addAttribute("message","비용은 0원 이상으로 입력해주세요.");
return "library/insert";
}
//추가적인 validation...
bookService.createBook(bookInsertRequestDto);
return "redirect:/library/books";
}
현재 Validation 하는 부분은 몇가지 문제가 있어 보입니다.
thymeleaf 의 logical address를 반환하는 부분이나, isError 를 model에 싣는 부분이 중복되어 보입니다.
지금은 만약 3개의 부분에서 전부 유효하지 않은 값이 오더라도, 가장 상위에 있는 에러 메시지만 사용자에게 전달됩니다. 이를 해결한 사용자는 다시 요청을 보내지만 이제는 그 다음 에러를 마주하게 될 겁니다. 여러 에러를 한번에 사용자에게 전달할 수 있는 방법이 필요해 보입니다.
A post shared by 유머페이지 "모아" (@moa_humor)
이건 validation에서 핵심적인 문제는 아닙니다. 하지만 expense의 input에 0이 들어있는것은 너무 열받습니다. 이것은 자바의 원시타입(primitive type)은 null을 가질 수 없어 0으로 초기화되고 그 값이 출력되기 때문입니다. 아주아주 열받으니 Wrapper 타입인 Integer로 변경시켜보도록 하겠습니다.
먼저 가장 간단한 수정인 DTO의 input을 Integer 타입으로 변환해주겠습니다.
public class BookInsertRequestDto {
private String name;
private String author;
**private Integer expense;**
public Book toEntity() {
return Book.builder()
.name(name)
.author(author)
.registerDate(LocalDateTime.now().toString())
.lent(0)
.expense(expense)
.build();
}
}
이렇게만 바꿔주어도 큰 문제 없습니다. 대신 이제 expense 가 null이 될 수 있으므로, validation에서는 null check를 추가로 진행해줘야할 것입니다.
@PostMapping("/library/books")
public String bookAdd(@ModelAttribute(name="bookInsertRequest") BookInsertRequestDto bookInsertRequestDto, Model model) {
int requestDtoNameLength = bookInsertRequestDto.getName().trim().length();
int requestDtoAuthorLength = bookInsertRequestDto.getAuthor().trim().length();
Integer requestDtoExpense = bookInsertRequestDto.getExpense();
Map<String,String> errors = new HashMap<>();
if(requestDtoNameLength < 1 || requestDtoNameLength > 30) {
errors.put("name","책 이름은 1자 이상 30자 이하로 입력해주세요.");
}
if (requestDtoAuthorLength < 1 || requestDtoAuthorLength > 30) {
errors.put("author","저자 이름은 1자 이상 30자 이하로 입력해주세요.");
}
if (requestDtoExpense == null || requestDtoExpense < 0) {
errors.put("expense","비용 입력은 필수이며, 0 이상이어야 합니다.");
}
if(!errors.isEmpty()) {
model.addAttribute("errors",errors);
return "library/insert";
}
//추가적인 validation...
bookService.createBook(bookInsertRequestDto);
return "redirect:/library/books";
}
Validation error를 저장할 Map 자료형을 가진 errors 라는 변수를 만들었습니다. 이 변수는 validation 간에 발생한 모든 에러를 저장한 뒤, model에 담겨서 view에 전송될 것입니다. 이때에 key는 어떤 input에서 발생한 에러인지를 저장하게 되고, value는 에러 메시지를 저장하게 됩니다.