특정 컨트롤러에서 바인딩 또는 검증 설정을 변경하고 싶을 때 사용
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder) {
webDataBinder.setDisallowedFields("id");
}
바인딩 설정
포매터 설정
Validator 설정
특정 모델 객체에만 바인딩 또는 Validator 설정을 적용하고 싶은 경우
@Controller
@SessionAttributes("event")
public class EventController {
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
webDataBinder.setDisallowedFields("id");라고 쓰면 받고 싶지 않은 필드 값을 걸러낼 수 있다. id는 이벤트를 저장할 때 생성하고 싶기 때문에 쿼리 파라미터나 패스, 폼 등으로 받아오고 싶지 않을 때 이렇게 사용하면 id가 입력되었을 때 걸러낼 수 있다.
public class Event {
private Integer id;
@NotBlank
private String name;
@Min(0)
private Integer limit;
@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)
// @DateTimeFormat(pattern = "yyyy-MM-dd")
private LocalDate startDate;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public LocalDate getStartDate() {
return startDate;
}
public void setStartDate(LocalDate startDate) {
this.startDate = startDate;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getLimit() {
return limit;
}
public void setLimit(Integer limit) {
this.limit = limit;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="#" th:action="@{/events/form/name}" method="post" th:object="${event}">
<p th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Incorrect date</p>
startDate: <input type="text" title="startDate" th:field="*{startDate}"/>
Name : <input type="text" title="name" th:field="*{name}"/>
<input type="submit" value="Create"/>
</form>
</body>
</html>
Formatter가 기본으로 등록되어 있어서 String이 LocalDate로 자동으로 바인딩된다.
또한 특정한 값을 이름으로 받고 싶지 않다면 Validator를 등록해주면 된다.
public class EventValidator implements Validator {
@Override
public boolean supports(Class<?> clazz) {
return Event.class.isAssignableFrom(clazz);
}
@Override
public void validate(Object target, Errors errors) {
Event event = (Event) target;
if (event.getName().equalsIgnoreCase("aaa")){
errors.rejectValue("name", "wrongValue", "the value is not allowed");
}
}
}
Validator를 @InitBinder에 등록해준다.
@Controller
@SessionAttributes("event")
public class EventController {
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
webDataBinder.addValidators(new EventValidator());
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "/events/form-name";
}
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
아니면 Validator를 @InitBinder에 등록하지 않고, Validator를 빈으로 등록해서 사용해도 된다.
@Component
public class EventValidator {
public void validate(Event event, Errors errors) {
if (event.getName().equalsIgnoreCase("aaa")){
errors.rejectValue("name", "wrongValue", "the value is not allowed");
}
}
}
@Controller
@SessionAttributes("event")
public class EventController {
@Autowired
EventValidator eventValidator;
@InitBinder
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
}
@ModelAttribute
public void categories(Model model){
model.addAttribute("categories", List.of("study", "seminar", "hobby", "social"));
}
@GetMapping("/events/form/name")
public String eventsFormName(Model model) {
model.addAttribute("event", new Event());
// 자동으로 세션에 넣어줌
return "events/form-name";
}
@PostMapping("/events/form/name")
public String eventsFormNameSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult){
if(bindingResult.hasErrors()){
// 스프링이 기본적으로 제공하는 Validation Error 검증
return "/events/form-name";
}
eventValidator.validate(event, bindingResult);
// 원하는 시점에 빈으로 등록한 Validator가 검증
return "redirect:/events/form/limit";
}
@GetMapping("/events/form/limit")
public String eventsFormLimit(@ModelAttribute @Valid Event event, Model model) {
model.addAttribute("event", event);
// 자동으로 세션에 넣어줌
return "events/form-limit";
}
@PostMapping("/events/form/limit")
public String eventsFormLimitSubmit(@ModelAttribute @Valid Event event, BindingResult bindingResult, SessionStatus sessionStatus, RedirectAttributes attributes){
if(bindingResult.hasErrors()){
return "/events/form-limit";
}
sessionStatus.setComplete();
// 데이터베이스에서 save 했다고 가정
attributes.addFlashAttribute("newEvent", event);
return "redirect:/events/list";
}
@GetMapping("/events/list")
public String getEvents(Model model,
@SessionAttriubte LocalDateTime visitTime){
System.out.println(visitTime);
Event spring = new Event();
spring.setName("spring");
spring.setLimit(10);
Event newEvent = (Event) model.asMap().get("newEvent");
// 데이터베이스에서 읽어왔다고 가정한다.
List<Event> eventList = new ArrayList<>();
eventList.add(spring);
eventList.add(newEvent);
model.addAttribute("eventList", eventList);
return "/events/list";
}
}
또한 특정 모델 객체에만 바인딩 또는 Validator 설정을 적용하고 싶은 경우 이름을 @InitBinder에 이름을 지정하면 된다.
@InitBinder("event")
public void initEventBinder(WebDataBinder webDataBinder){
webDataBinder.setDisallowedFields("id");
webDataBinder.addValidators(new EventValidator());
}
참고