본문 바로가기

개발/Backend

[Spring Boot] 예제로 배우는 스프링부트 입문 | Form값 검증

Validator 사용하기 

데이터 검증은 form의 데이터를 파라미터로 받아 데이터를 조작하고 모델에 담아 뷰에 보여주는 과정에서 파라미터가 데이터로써 사용 가능한지 파악하는 단계 

 

이런 Form에서 입력 값이 올바른지 validator를 통해 검증하는 것 

 

ContentDto.java

package com.study.springboot;

import lombok.Data;

@Data
public class ContentDto {
	private int id;
	private String writer;
	private String content;
}
  • id,writer, contents 변수를 갖고 있음
  • 롬복을 이용했으므로 getter, setter 등은 자동으로 작성됨 => 파라미터를 이 command객체를 통해 받을 수 있게 해줌 

 


MyController.java

package com.study.springboot;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {

    @RequestMapping("/")
    public @ResponseBody String root() throws Exception{
        return "Validator (1)";
    }

    @RequestMapping("/insertForm")
    public String insert1() {

    	return "createPage";       
    }
     
    @RequestMapping("/create")
    public String insert2(@ModelAttribute("dto") ContentDto contentDto,
    		              BindingResult result)
    {
    	String page = "createDonePage";
    	System.out.println(contentDto);
    	
    	ContentValidator validator = new ContentValidator();
    	validator.validate(contentDto, result);
    	if (result.hasErrors()) {
    		page = "createPage";
    	}
        
    	return page;       
    }
}

 

  • 파라미터로 Command 객체를 받음
  • @ModelAttribute는 command객체의 변수명을 이용해서 jsp페이지에서 이용할 수 있는 command객체의 이름이 길거나 다른 이름으로 만들고 싶을 때 사용하는 어노테이션 => ${dto,writer}이런식으로 이용 
  • contentsDto에 들어온 파라미터를 검증하기 위해 ContentValidator 타입의 변수 이용
  •  validate 검사 결과를 result 변수에 넣음 

ContentValidator.java

package com.study.springboot;

import org.springframework.validation.Errors;
import org.springframework.validation.Validator;

public class ContentValidator implements Validator {

	@Override
	public boolean supports(Class<?> arg0) {
		return ContentDto.class.isAssignableFrom(arg0);  // 검증할 객체의 클래스 타입 정보
	}

	@Override
	public void validate(Object obj, Errors errors) {

		ContentDto dto = (ContentDto)obj;
		
		String sWriter = dto.getWriter();
		if(sWriter == null || sWriter.trim().isEmpty()) {
			System.out.println("Writer is null or empty");
			errors.rejectValue("writer", "trouble");
		}
		
		String sContent = dto.getContent();
		if(sContent == null || sContent.trim().isEmpty()) {
			System.out.println("Content is null or empty");
			errors.rejectValue("content", "trouble");
		}

	}
	
}
  • validator인터페이스를 implement
  • validate함수에 검증하고 싶은 로직 구현
  • 검증을 하고 에러가 나면 spring-boot-contain에서 관리하는 errors라는 빈 객체에다가 error를 넣어주면 다른 클래스에서도 사용 가능
  • null이나 값이 비어 있으면 spring boot가 관리하는 errors 개체에 키값과 value값을 넣어주면 됨

 

ValidationUtils 사용하기 

파라미터의 값을 구해 null인지 아니면 비어 있는지 체크하는 코드는 모든 개발자가 만들어야하는 코드임 

=> 스프링 프레임워크에서 유틸리티 제공 

 

ContentValidate.java

package com.study.springboot;

import org.springframework.validation.Errors;
import org.springframework.validation.ValidationUtils;
import org.springframework.validation.Validator;

public class ContentValidator implements Validator {

	@Override
	public boolean supports(Class<?> arg0) {
		return ContentDto.class.isAssignableFrom(arg0);  // 검증할 객체의 클래스 타입 정보
	}

	@Override
	public void validate(Object obj, Errors errors) {

		ContentDto dto = (ContentDto)obj;

		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "writer", "writer is empty.");
		String sWriter = dto.getWriter();
		if (sWriter.length() < 3) {
			errors.rejectValue("writer", "writer is too short.");
		}
		

		ValidationUtils.rejectIfEmptyOrWhitespace(errors, "content", "content is empty.");

	}
	
}
  • validation-utils 패키지의 rejectIfEmptyOrWhitespace라는 메소드로 클래스를 별도로 new하지 않고 사용
  • 이름이 없거나 화이트 스페이스면 errors 변수에 세번째 변수의 내용을 담겠다는 것 

이렇게 기본으로 제공되는 메서드를 이용하거나 직접 만든 검증 로직을 통해 에러에 내용을 담아줄 수 있음 

 

initBinder 사용하기 

미리 제공되는 initBinder에 검증클래스를 이용해서 약한 결합을 만들고 validated annotation을 이용해서 코드를 간략화시켜보자 

validater를 매번 새로운 객체를 할당함 => 스프링은 강한결합 비선호

 

MyController.java

package com.study.springboot;

import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class MyController {

    @RequestMapping("/")
    public @ResponseBody String root() throws Exception{
        return "Validator (3)";
    }

    @RequestMapping("/insertForm")
    public String insert1() {

    	return "createPage";       
    }
     
    @RequestMapping("/create")
    public String insert2(@ModelAttribute("dto") @Validated ContentDto contentDto,
    		              BindingResult result)
    {
    	String page = "createDonePage";
    	System.out.println(contentDto);
    	
//    	ContentValidator validator = new ContentValidator();
//    	validator.validate(contentDto, result);
    	if (result.hasErrors()) {
    		if (result.getFieldError("writer") != null) {
    			System.out.println("1:" + result.getFieldError("writer").getCode());
    		}
    		if (result.getFieldError("content") != null) {
    			System.out.println("2:" + result.getFieldError("content").getCode());
    		}

    		page = "createPage";
    	}
        
    	return page;       
    }

    @InitBinder
    protected void initBinder(WebDataBinder binder) {
    	binder.setValidator(new ContentValidator());
    }
}
  • setValidator로 우리가 만든 ConetentValidator를 넣어주면 서비스가 만들어질 때 init가 될 때 최초의 한번만 new가 돼서 바인딩됨
  • 단순히 에러가 있는지 확인하는 것뿐만 아니라 에러에 대해 키값을 이용해 에러를 찾아오고 출력함 

Valid 어노테이션 사용하기 

사용자가 검증 클래스를 만들지 않아도 어노테이션을 이용하여 파라미터를 쉽게 검증할 수 있음 

 

ContentDto.java

package com.study.springboot;

import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class ContentDto {
	private int id;
	@NotNull(message="writer is null.")
	@NotEmpty(message="writer is empty.")
	@Size(min=3, max=10, message="writer min 3, max 10.")
	private String writer;
	@NotNull(message="content is null.")
	@NotEmpty(message="content is empty.")
	private String content;
}
  • 메세지로 에러 처리를 할 수 있음 

MyController.java

@Controller
public class MyController {

    @RequestMapping("/")
    public @ResponseBody String root() throws Exception{
        return "Validator (4)";
    }

    @RequestMapping("/insertForm")
    public String insert1() {

    	return "createPage";       
    }
     
    @RequestMapping("/create")
    public String insert2(@ModelAttribute("dto") @Valid ContentDto contentDto,
    		              BindingResult result)
    {
    	String page = "createDonePage";
    	System.out.println(contentDto);
    	
    	if (result.hasErrors()) {
//    		if (result.getFieldError("writer") != null) {
//    			System.out.println("1:" + result.getFieldError("writer").getCode());
//    		}
//    		if (result.getFieldError("content") != null) {
//    			System.out.println("2:" + result.getFieldError("content").getCode());
//    		}
    		if (result.getFieldError("writer") != null) {
        		System.out.println("1:"+result.getFieldError("writer").getDefaultMessage());
    		}
    		if (result.getFieldError("content") != null) {
        		System.out.println("2:"+result.getFieldError("content").getDefaultMessage());
    		}

    		page = "createPage";
    	}
        
    	return page;       
    }

//    @InitBinder
//    protected void initBinder(WebDataBinder binder) {
//    	binder.setValidator(new ContentValidator());
//    }
}