티스토리 뷰

SpringBoot+Thymeleaf

Validation 체크하기

joyHong 2020. 2. 20. 00:14

지난 포스팅에서는 사용자의 입력을 받아 데이터를 저장하고 저장된 결과 목록을 AJAX로 받아와 원하는 fragments에 보여지도록 하였다.

이번에는 사용자의 입력을 받을 때 입력값이 valid한지를 체크하는 예제를 생성해보려고 한다.

자바스크립트로 처리할 수 있는 부분이지만 스프링부트와 타임리프를 쓸 때는 어떻게 하는지에 대해서도 알아두면 좋지 않을까 생각한다.

validation 체크를 하기 위한 예제로 test8로 요청하면 처리할 컨트롤러와 test8.html을 생성하겠다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.joyhong.controller;
 
 
 
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
 
import com.joyhong.service.BookService;
 
@Controller
public class TestController2 {
    
    private Logger logger = LoggerFactory.getLogger(TestController.class);
    
    @Autowired
    private BookService bookService;
 
    @RequestMapping(value = "/test8", method = RequestMethod.GET)
    public String test8(Model model, Book book) {
        return "test/test8";
    }
    
    @RequestMapping(value = "/test8", method = RequestMethod.POST)
    public String checkBook(Model model, @Valid Book book, BindingResult bindingResult) {
 
        if (bindingResult.hasErrors()) {
            return "test/test8 :: #form";
        }
        
        bookService.createBook(book);
        model.addAttribute("bookMap", bookService.readBookAll());
        return "test/test8 :: #list";
    }
    
 
}
 
 
 

/test8요청은 GET방식으로 들어올 때와 POST 방식으로 들어올 때를 구분하여 각각 하나씩 생성하였다.

GET방식으로 들어오는 경우는 처음 진입할 사용되어지고, 입력버튼을 누르게 되면 POST 방식으로 넘기도록 할 것이기 때문에 이 때 사용된다. valid 체크도 POST 방식으로 넘어오게 된다.

그래서 GET 방식으로 test8 요청이 들어오면 단순히 test8.html을 화면에 보여주게 되는데 test8.html은 아래와 같이 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" lang="ko">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
<h3>Validation Check</h3>
<p>책 정보 입력</p>
<form id="form" th:object="${book}">
    <table>
    <tr>
        <td>책제목</td>
        <td>
            <input type="text" th:field="*{title}" placeholder="책 제목을 입력하세요">
        </td>
        <td class="err" th:if="${#fields.hasErrors('title')}" th:errors="*{title}">Name Error</td>
    </tr>
    <tr>
        <td>저자명</td>
        <td>
            <input type="text" th:field="*{creator}" placeholder="저자명을 입력하세요">
        </td>
        <td class="err" th:if="${#fields.hasErrors('creator')}" th:errors="*{creator}">Name Error</td>
    </tr>
    <tr>
        <td>출판사</td>
        <td>
            <input type="text" th:field="*{publisher}" placeholder="출판사명을 입력하세요">
        </td>
        <td class="err" th:if="${#fields.hasErrors('publisher')}" th:errors="*{publisher}">Name Error</td>
    </tr>
    <tr>
        <td>출판연도</td>
        <td>
            <input type="text" th:field="*{publishedYear}">
        </td>
    </tr>
    </table>
    <button type="button" onclick="inputData2(this)" >입력</button>
</form>
</div>
<div id="list">
<th:block th:if="${bookMap != null}">
<h3>책 목록</h3>
<table border=1>
    <tr>
        <th>번호</th>
        <th>제목</th>
        <th>저자</th>
        <th>출판사</th>
        <th>출판연도</th>
    </tr>
    <tr th:each="entry : ${bookMap}" th:with="book=${entry.value}">
        <td th:text="${book.seq}"></td>
        <td th:text="${book.title}"></td>
        <td th:text="${book.creator}"></td>
        <td th:text="${book.publisher}"></td>
        <td th:text="${book.publishedYear}"></td>
    </tr>
</table> 
</th:block>
</div>
 
<script th:src="@{/js/jquery.min.js}"></script>
<script th:src="@{/js/book.js}"></script>
</body>
</html>
 
 

form태그에서는 th:object="${book}" 을 지정하여 Book 클래스에 매핑되도록 하였고 th:field를 사용하여 Book 클래스의 변수들을 지정하였다. 사용자가 폼에 값을 입력하고 입력 버튼을 누르면 inputData2() 라는 자바스크립트 함수에서 처리하게 하였는데 자바스크립트는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function inputData2(){
    var book = $('#form').serialize();
    $.ajax({
        url: "/home/test8",
        data: book,
        type:"POST",
        cache: false
    }).done(function (fragment) {
        if ($(fragment).find("#form").prevObject["0"].length > 0) {
            $("#form").replaceWith(fragment);
        }
        else{
            $("#list").replaceWith(fragment);
            $("input[type=text]").val("");
            $('.err').text("");
        }
    });
}
 
 
 

폼의 값을 test8에 POST 방식으로 넘기는데 결과에 따라 화면에서 변경되는 값이 달라지도록 하였다. 이는 컨트롤러에서 먼저 살펴보면, test8에 대한 POST 방식을 처리할 때

@Valid Book book 를 사용하여 Book 클래스에 매핑된 값이 valid 한지를 체크하는 어노테이션을 붙였고,

BindingResult bindingResult 를 사용하여 validation 체크결과가 담긴 객체를 통해

bindingResult.hasErrors() 가 true이면 즉, 에러가 있으면 test8.html에 id가  form 인 부분을 내용을 바꾸도록 하였다.

그리고 false 이면 book 객체의 값을 업무로직에 보내 저장하고 다시 전체 목록을 받아와 test8.html에 id가 list 인 부분의 내용을 바꾸도록 하였다.

따라서 위의 자바스크립트에서는 form에 대한 내용이면 그 부분을 변경하고,

아니면 list 부분을 변경하고 input 태그의 값을 지우고, err 클래스인 텍스트값을 없애도록 하였다.

 

그럼 이제 Book 클래스의 내용을 조금 손 봐야 한다.

컨트롤러에서 주고 받는 Book 클래스에는 Validation을 위한 어노테이션이 들어가야 한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
 
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
 
public class Book {
    
    private long seq;
    @NotBlank(message="제목은 반드시 입력해야 합니다.")
    private String title;
    @NotBlank(message="저자는 반드시 입력해야 합니다.")
    private String creator;
    @NotNull
    @Size(min=2, message="두 글자 이상 입력해야 합니다.")
    private String publisher;
    private int publishedYear;
    
    public long getSeq() {
        return seq;
    }
    public void setSeq(long seq) {
        this.seq = seq;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getCreator() {
        return creator;
    }
    public void setCreator(String creator) {
        this.creator = creator;
    }
    public String getPublisher() {
        return publisher;
    }
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }
    public int getPublishedYear() {
        return publishedYear;
    }
    public void setPublishedYear(int publishedYear) {
        this.publishedYear = publishedYear;
    }
    
}
 
 
 

여기서는 제목, 저자명, 출판사에 대해서만 valid한지를 체크하도록 하였는데 

@NotBlank 을 사용하여 null을 허용하지 않도록 한 것과

@NotNull 을 사용하여 null과 공백문자열을 허용하지 않도록 한것

그리고 @Size 을 통해 길이에 대한 제한을 둔 것 을 사용하였다.

이외에도 여러가지가 있는데 자세한 내용을 공식 사이트를 참조하면 좋을 것 같다.

그리고 message에 valid하지 않을 경우에 대한 메세지를 입력하면 된다.

 

그럼 이제 결과를 확인해보면

처음 화면
제목만 입력할 경우 에러메세지
모든 정보를 입력후 입력버튼 누른 화면

 

최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함