Spring Validation

基本概念

一般的web application都是靠View進行輸入的驗證,然而,前端的驗證可能會因為瀏覽器的版本或java script被使用者停用而失效,所以,需要伺服器端的驗證,Spring Validation就是屬於伺服器端的驗證。

設定

要使用Spring Validation,請在pom.xml中的<dependencies></dependencies>中加入以下的設定,加完之後,就可以了。(Thymeleaf的設定請參閱Spring View)

   <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-validation</artifactId>
  </dependency>

驗證規則

首先,驗證的規則在Model裡設定,例如,可以設定name與address不可以是空白且至少輸weight入一個字,最小值為0。請注意:如果變數的資料型態是文字,不能用Min或Max,如果變數的資料型態是數字,不能用Size。

package com.example.demo.entity;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

public class Customer {
 @NotNull
 @Size(min=1)
 private String name;
 @NotNull
 @Size(min=1)
 private String address;
 @Min(0)
 private int weight;

 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }

 public String getAddress() {
  return address;
 }
 public void setAddress(String address) {
  this.address = address;
 }

 public int getWeight() {
  return weight;
 }
 public void setWeight(int weight) {
  this.weight = weight;
 }
}

接下來,在Controller中,必須設定要去使用Model裡的validation,可以在model前(或@ModelAttribute前)加入@Valid,就會啟動model中的validation,另外,為了要取得驗證後的結果,加入BindingResult bindingResult。可以使用hasErrors()來處理錯誤。以下面的範例而言,就是將使用者導回原本的表單。

package com.example.demo.controller;

import javax.validation.Valid;

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.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

import com.example.demo.entity.Customer;

@Controller
public class CustomerController {
    @RequestMapping(value = "/customerCreate", method = RequestMethod.GET)
    public ModelAndView openForm(Customer customer) {
       ModelAndView model = new ModelAndView("customerCreate");
       model.addObject(customer);
       return model;
    }

    @RequestMapping(value = "/customerCreate", method = RequestMethod.POST)
    public ModelAndView processForm(@Valid @ModelAttribute Customer customer, BindingResult bindingResult) {
       ModelAndView model = new ModelAndView("customerDone");
       if (bindingResult.hasErrors()) {
         model = new ModelAndView("customerCreate");
         return model;
       }
       model.addObject(customer);
       return model;
    }
    
}

前面的View (表單),可以顯示錯誤訊息。可以使用fields.hasErrors('name'),了解是否name這個欄位有錯誤,利用errors="*{name}",可以顯示這個欄位的錯誤訊息。因為前面的controller將所有變數包在customer中,為了不需要一直指定customer,thymeleaf可以使用th:object="${customer}",後面就可以直接使用*{name},否則就必須使用${customer.name},如以下範例。

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8"/>
    <title>Create New Customer</title>
</head>
<body>

<form action="customerCreate" th:object="${customer}" method ="post">

 name:<input type="text" name="name" th:field="*{name}"/><br/>
 <div th:if="${#fields.hasErrors('name')}" th:errors="*{name}"></div>
 address:<input type="text" name = "address" th:field="*{address}"/><br/>
 <div th:if="${#fields.hasErrors('address')}" th:errors="*{address}"></div>
 weight:<input type="text" name ="weight" th:field="*{weight}"/><br/>
 <div th:if="${#fields.hasErrors('weight')}" th:errors="*{weight}"></div>
 <input type="submit" value="Submit"/>

</form>

</body>
</html>

客製訊息

Spring Validation會提供標準的錯誤訊息,這些訊息也可以被客製,如以下範例。不過,為了能提供多語系功能,建議利用message.properties (詳參:http://spr.com/part-4-internationalization-in-spring-boot/ )

 @NotNull
 @Size(min=1, message="不能是空白")
 private String name;
 @NotNull
 @Size(min=1, message="不能是空白")
 private String address;
 @Min(value=0, message="必須大於0")
 private int weight;

當我們在應該輸入數字的欄位中留空白時,會產生typeMismatch的錯誤,如果要客製那部份的錯誤訊息,可以進行以下的設定。

在application.properties裡新增:

spring.messages.basename=messages
spring.messages.encoding=UTF-8

新增/src/main/resource/messages.properties,並放入以下內容 (對應的中文字內容是「 必須是個整數」) (詳參: https://en.wikipedia.org/wiki/.properties )。

typeMismatch.int=\u5FC5\u9808\u662F\u500B\u6574\u6578
typeMismatch.java.lang.Integer=\u5FC5\u9808\u662F\u500B\u6574\u6578


參考資料