在上一篇Day 15 - Spring Boot 註冊與登入中,我們已經初步完成了註冊與登入的基礎功能,但我們要記得,Spring Boot 為了簡化開發的流程,提供了許多開箱即用的依賴,這篇我們就要介紹Spring Boot 提供關於資料驗證的依賴,也就是Day 07 - Spring Boot 常用依賴中提到spring-boot-starter-validation
,主要透過註釋的方式進行,可以進一步簡化我們的程式碼,讓我們更專注在業務邏輯上。
當然,不免俗的要先看一下它提供的註釋,以下列出一些常用的註釋,可以不用背下來,但要記得有關於資料驗證的功能,可以先查一下它有沒有提供相關的註釋。
@Valid
: 註釋在方法中要校驗的參數上,用於啟動校驗,可搭配BindingResult 物件獲取校驗失敗的訊息;也可以註釋在成員屬性上,用於進行嵌套驗證。@Validated
: 對於@Valid 的封裝,由Spring 提供的校驗機制,比@Valid 多了分組功能,但必須配合@Valid 才能進行嵌套驗證。@Email
: 被註釋的屬性必須是電子信箱格式。@Pattern
: 被註釋的屬性必須符合指定的正則表示法。@Null
: 被註釋的屬性必須為Null。@NotNull
: 被註釋的屬性必須不為Null。@NotEmpty
: 被註釋的字串不可為空。@NotBlank
: 被註釋的字串非null 且長度必須大於0。@Length
: 被註釋的字串長度必須在指定的範圍內。@Min(value)
: 被註釋的屬性必須為一個數字且大於或等於指定的最小值。@Max(value)
: 被註釋的屬性必須為一個數字且小於或等於指定的最大值。@DecimalMin(value)
: 被註釋的屬性必須為一個數字且大於或等於指定的最小值。@DecimalMax(value)
: 被註釋的屬性必須為一個數字且小於或等於指定的最大值。@Size(max, min)
: 被註釋的屬性必須為一個數字且在指定的範圍內。@Digits(integer, fraction)
: 被註釋的屬性必須為一個數字且在可接收的範圍內。@Range
: 被註釋的屬性必須在合適的範圍內。@AssertTrue
: 被註釋的屬性必須為一個布林值且為true。@AssertFalse
: 被註釋的屬性必須為一個布林值且為false。@Past
: 被註釋的屬性必須為一個過去的日期。@Future
: 被註釋的屬性必須為一個未來的日期。<!-- Spring Validator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
package com.example.demo.entity;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class MemberAccount extends Base {
private String id;
@Email(message = "帳號必須是Email 格式")
@NotBlank(message = "帳號不可為空")
private String username;
@NotBlank(message = "密碼不可為空")
@Pattern(regexp = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)[\\w]{6,16}$",
message = "密碼必須為長度6~16位碼大小寫英文加數字")
private String password;
private String salt;
}
@Controller
public class MemberAccountController {
// 略...
@RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(
@Valid @ModelAttribute MemberAccount memberAccount,
HttpSession session,
RedirectAttributes redirectAttributes) {
MemberAccountVO memberAccountVO = memberAccountService.login(memberAccount);
if(memberAccountVO == null) {
redirectAttributes.addFlashAttribute("MESSAGE", "帳號或密碼錯誤");
return "redirect:login";
}
session.setAttribute("member", memberAccountVO);
return "redirect:information";
}
// 略...
@RequestMapping(value = "/register", method = RequestMethod.POST)
public String doRegister(
@Valid @ModelAttribute MemberAccountVO memberAccountVO,
RedirectAttributes redirectAttributes) {
Optional<String> optional = memberAccountService.register(memberAccountVO);
String message = optional.orElse("註冊成功");
redirectAttributes.addFlashAttribute("MESSAGE", message);
return "redirect:login";
}
}
可以看到註冊的業務邏輯,少了前面對帳號及密碼格式的判斷,別小看這邊只少了兩行,當專案越來越大,搭配@Validated
為驗證邏輯進行分組,可以減少各處的驗證判斷。
@Service
public class MemberAccountServiceImpl implements MemberAccountService {
// 略...
@Override
public Optional<String> register(MemberAccountVO memberAccountVO) {
// TODO Auto-generated method stub
// 檢查兩次輸入密是否相符
if(!memberAccountVO.getPassword().equals(memberAccountVO.getCheckPassword())) return Optional.of("兩次輸入密碼不相符");
// 檢查帳號是否重複註冊
MemberAccount data = memberAccountDao.findMemberAccountByUsername(memberAccountVO.getUsername());
if(data != null) return Optional.of("該帳號已被使用");
// 產生鹽值
String salt = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");
// 密碼加密
String md5Password = getMd5Password(memberAccountVO.getPassword(), salt);
// 新增MemberAccount 資料
MemberAccount memberAccount = new MemberAccount();
memberAccount.setUsername(memberAccountVO.getUsername());
memberAccount.setPassword(md5Password);
memberAccount.setSalt(salt);
memberAccount.setCreate_by(memberAccountVO.getUsername());
memberAccount.setUpdate_by(memberAccountVO.getUsername());
Integer id = memberAccountDao.insert(memberAccount);
if(id == 0) return Optional.of("新增會員帳號時發生錯誤");
// 新增Member 資料
Member member = new Member();
member.setMa_id(String.valueOf(id));
member.setName(memberAccountVO.getName());
member.setCreate_by(memberAccountVO.getUsername());
member.setUpdate_by(memberAccountVO.getUsername());
Integer result = memberService.insert(member);
if(result == 0) return Optional.of("新增會員資料時發生錯誤");
return Optional.empty();
}
// 略...
}
使用SpringBoot進行優雅的資料驗證_部落格園精華區 - MdEditor
SpringBoot - 第二十章 | 資料驗證(二)