ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [ Spring Boot + JPA + Thymeleaf ] validation 추가
    Spring Boot 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";
        }
Designed by Tistory.