Spring Boot

[ Spring Boot + JPA + Thymeleaf ] validation 추가

현쥬스주스 2021. 3. 2. 21:39

Bean Validation


도메인 로직에서 값을 검증할 수 있게 도와주는 인터페이스이다.

 

주요 어노테이션들은 아래와 같다.

 

 

<직접 검증을 하고 싶을 때 사용>

@AssertTrue

@AssertFalse

 

<문자열을 다룰 때 사용>

@NotNull // null 불가능

@NotEmpty // null, 빈 문자열(스페이스 포함X) 불가

@NotBlank // null, 빈 문자열, 스페이스만 포함한 문자열 불가

@Size(min=?, max=?) // 최소 길이, 최대 길이 제한

@Null // null만 가능

<숫자를 다룰 때 사용>

@Positive // 양수만 허용

@PositiveOrZero // 양수와 0만 허용

@Negative // 음수만 허용

@NegativeOrZero // 음수와 0만 허용

@Min(?) // 최소값 제한

@Max(?) // 최대값 제한 ​

 

<정규식 관련>

@Email // 이메일 형식만가능 (기본 제공)

@Pattern(regexp="?") // 직접 정규식을 쓸 수 있음

 

사용방법은,

검증하고자 하는 Entity에 @Valid를 붙이며, 이에 대한 결과를 받기 위해 BindingResult를 추가하여 사용할 수 있다.

 

Depedency


dependencies { 
    compile('org.springframework.boot:spring-boot-starter-web') 
    compile('org.springframework.boot:spring-boot-starter-validation') 
    compile('org.projectlombok:lombok')
    runtime('com.h2database:h2')
    testCompile('org.springframework.boot:spring-boot-starter-test')
}

 

 

Controller


- BoardController.java

import com.example.myhome.model.Board;
import com.example.myhome.repository.BoardRepository;
import com.example.myhome.validator.BoardValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;

    @Autowired
    private BoardRepository boardRepository;

    @Autowired
    private BoardValidator boardValidator;

    // 리스트 출력
    @GetMapping("/list")
    public String form(Model model, @RequestParam(required = false) Long id){
        return "board/form";
    }
    @PostMapping("/form/save")
    public String saveForm(@Valid Board board, BindingResult bindingResult){
        boardValidator.validate(board, bindingResult);
        if(bindingResult.hasErrors()){
            return "board/form";
        }

        boardRepository.save(board);
        return "redirect:/board/list";
    }

saveForm 메서드를 보면 @Valid와 BindingResult를 추가한것을 볼수있다.

bindingResult값을 받아와 hasErrors()를 사용하여 유효성을 통과하였는지 확인하는것이다.

 

boardValidator.validate(board, bindingResult); 코드에 대해서는 하단에서 다시 설명할것이다.

 

 

Model


- Board.java

package com.example.myhome.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Entity
@Data
public class Board {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @NotNull
    @Size(min=2,max=30)
    private String title;
    private String content;
}

어노테이션을 사용하여 게시물 제목 글자수를 2~30글자까지만 제한하도록 명시하였다.

 

View


- form.html

 <input type="hidden" th:field="*{id}">
        <div class="mb-3">
            <label for="exampleFormControlInput1" class="foboardrm-label">제목</label>
            <input type="text" class="form-control" id="exampleFormControlInput1" th:field="*{title}">
            <input type="text" class="form-control" id="exampleFormControlInput1" th:classappend="${#fields.hasErrors('title')} ? 'is-invalid' " th:field="*{title}">
            <div class="invalid-feedback" th:if="${#fields.hasErrors('title')}" th:errors="*{title}">
                제목 에러메시지
            </div>
        </div>
        <div class="mb-3">
            <label for="exampleFormControlTextarea1" class="form-label">내용</label>
            <textarea class="form-control" id="exampleFormControlTextarea1" rows="3" th:field="*{content}"></textarea>
            <textarea class="form-control" id="exampleFormControlTextarea1" rows="3" th:classappend="${#fields.hasErrors('content')} ? 'is-invalid' " th:field="*{content}"></textarea>
            <div class="invalid-feedback" th:if="${#fields.hasErrors('content')}" th:errors="*{content}">
                내용 에러메시지
            </div>
        </div>
        <div class="text-right">
            <a type="button" class="btn btn-primary" th:href="@{/board/list}">이전</a>

만일 해당 조건을 충족하지 못했을 경우 에러메시지를 표현해주기 위하여 form페이지에 Thymeleaf문법으로 에러메시지 출력 부분을 추가해주었다.

 

하지만, 위의 제공되는 에노테이션 말고 다른 방식으로 검증방식을 추가해야 할 경우 직접 클래스를 만들어 사용하는 방법도 있다.

 

Custom Validation


validator패키지 생성 후 BoardValidator.java 파일을 생성해준다.

 

- BoardValidator.java

package com.example.myhome.validator;

import com.example.myhome.model.Board;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
import org.thymeleaf.util.StringUtils;

@Component
public class BoardValidator implements Validator {
    @Override
    public boolean supports(Class<?> clazz) {
        return Board.class.equals(clazz);
    }

    @Override
    public void validate(Object obj, Errors errors) {
        Board b = (Board) obj;
        if(StringUtils.isEmpty(b.getContent())){
            errors.rejectValue("content","key","내용을 입력하세요");
        }


    }
}

validator를 상속하는 클래스를 작성해주고 validate 메서드에 추가하고 싶은 제한조건에 대해 작성 후

BoardController에서 BoardValidator를 @Autowired 후 validate메서드를 사용해준다.

 

@PostMapping("/form/save")
    public String saveForm(@Valid Board board, BindingResult bindingResult){
        boardValidator.validate(board, bindingResult);
        if(bindingResult.hasErrors()){
            return "board/form";
        }

        boardRepository.save(board);
        return "redirect:/board/list";
    }