本文目錄一覽:
- 1、JSR303校驗的使用
- 2、Spring JSR303驗證,為什麼在頁面上使用 form:error顯示不了錯誤信息
- 3、javax 是如何實現依賴
- 4、如何自定義JSR-303標準的validator
- 5、spring mvc為什麼不能返回基本數據類型
JSR303校驗的使用
SpringBoot中如果使用此數據檢驗,需添加依賴:
常用的校驗
使用例子
錯誤提示
name不是郵箱格式
Spring JSR303驗證,為什麼在頁面上使用 form:error顯示不了錯誤信息
說明你對jsr的自定義類型轉化器ConversionService沒有了解,你雖然model裏面已經添加了jsp中的modelAttribute的模型,但是你modelAttribute中的名字沒有對應你的PortalUser類中的名字,應該jsp中modelAttribute=「」portalUser「」,你就可以解決你的問題
備註:在jsp中的modelAttribute必須要modelAttribute=”POJO類名小寫”,原理和springmvc.xml中配置conversionService 的默認bean一樣意思
javax 是如何實現依賴
參數校驗是我們程序開發中必不可少的過程。用戶在前端頁面上填寫表單時,前端js程序會校驗參數的合法性,當數據到了後端,為了防止惡意操作,保持程序的健壯性,後端同樣需要對數據進行校驗。後端參數校驗最簡單的做法是直接在業務方法裏面進行判斷,當判斷成功之後再繼續往下執行。但這樣帶給我們的是代碼的耦合,冗餘。當我們多個地方需要校驗時,我們就需要在每一個地方調用校驗程序,導致代碼很冗餘,且不美觀。
那麼如何優雅的對參數進行校驗呢?JSR303就是為了解決這個問題出現的,本篇文章主要是介紹 JSR303,Hibernate Validator 等校驗工具的使用,以及自定義校驗註解的使用。
校驗框架介紹
JSR303 是一套JavaBean參數校驗的標準,它定義了很多常用的校驗註解,我們可以直接將這些註解加在我們JavaBean的屬性上面,就可以在需要校驗的時候進行校驗了。註解如下:
Hibernate validator 在JSR303的基礎上對校驗註解進行了擴展,擴展註解如下:
Spring validtor 同樣擴展了jsr303,並實現了方法參數和返回值的校驗
Spring 提供了MethodValidationPostProcessor類,用於對方法的校驗
代碼實現
添加JAR包依賴
在pom.xml中添加如下依賴:
!–jsr 303–
dependency
groupIdjavax.validation/groupId
artifactIdvalidation-api/artifactId
version1.1.0.Final/version
/dependency
!– hibernate validator–
dependency
groupIdorg.hibernate/groupId
artifactIdhibernate-validator/artifactId
version5.2.0.Final/version
/dependency
最簡單的參數校驗
1、Model 中添加校驗註解
public class Book { private long id; /**
* 書名 */
@NotEmpty(message = “書名不能為空”) private String bookName; /**
* ISBN號 */
@NotNull(message = “ISBN號不能為空”) private String bookIsbn; /**
* 單價 */
@DecimalMin(value = “0.1”,message = “單價最低為0.1”)
private double price; // getter setter ……. }
2、在controller中使用此校驗
/**
* 添加Book對象
* @param book */
@RequestMapping(value = “/book”, method = RequestMethod.POST) public void addBook(@RequestBody @Valid Book book) {
System.out.println(book.toString());
}
當訪問這個post接口時,如果參數不符合Model中定義的話,程序中就回拋出400異常,並提示錯誤信息。
自定義校驗註解
雖然jSR303和Hibernate Validtor 已經提供了很多校驗註解,但是當面對複雜參數校驗時,還是不能滿足我們的要求,這時候我們就需要 自定義校驗註解。
下面以「List數組中不能含有null元素」為實例自定義校驗註解
1、註解定義如下:
package com.beiyan.validate.annotation;import javax.validation.Constraint;import javax.validation.Payload;import java.lang.annotation.*;import static java.lang.annotation.ElementType.*;import static java.lang.annotation.ElementType.PARAMETER;import static java.lang.annotation.RetentionPolicy.RUNTIME;/**
* 自定義參數校驗註解
* 校驗 List 集合中是否有null 元素 */@Target({ElementType.ANNOTATION_TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(validatedBy = ListNotHasNullValidatorImpl.class)////此處指定了註解的實現類為ListNotHasNullValidatorImplpublic @interface ListNotHasNull { /**
* 添加value屬性,可以作為校驗時的條件,若不需要,可去掉此處定義 */
int value() default 0;
String message() default “List集合中不能含有null元素”;
Class?[] groups() default {};
Class? extends Payload[] payload() default {}; /**
* 定義List,為了讓Bean的一個屬性上可以添加多套規則 */
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER})
@Retention(RUNTIME)
@Documented
@interface List {
ListNotHasNull[] value();
}
}
2、註解實現類:
package com.beiyan.validate.annotation;import org.springframework.stereotype.Service;import javax.validation.ConstraintValidator;import javax.validation.ConstraintValidatorContext;import java.util.List;/**
* 自定義註解ListNotHasNull 的實現類
* 用於判斷List集合中是否含有null元素 */@Servicepublic class ListNotHasNullValidatorImpl implements ConstraintValidatorListNotHasNull, List { private int value;
@Override public void initialize(ListNotHasNull constraintAnnotation) { //傳入value 值,可以在校驗中使用
this.value = constraintAnnotation.value();
} public boolean isValid(List list, ConstraintValidatorContext constraintValidatorContext) { for (Object object : list) { if (object == null) { //如果List集合中含有Null元素,校驗失敗
return false;
}
} return true;
}
}
3、model添加註解:
public class User {
//其他參數 ……./**
* 所擁有的書籍列表 */
@NotEmpty(message = “所擁有書籍不能為空”)
@ListNotHasNull(message = “List 中不能含有null元素”)
@Valid private ListBook books; //getter setter 方法…….}
使用方法同上,在在需要校驗的Model上面加上@Valid 即可
分組驗證
對同一個Model,我們在增加和修改時對參數的校驗也是不一樣的,這個時候我們就需要定義分組驗證,步驟如下
1、定義兩個空接口,分別代表Person對象的增加校驗規則和修改校驗規則
/**
* 可以在一個Model上面添加多套參數驗證規則,此接口定義添加Person模型新增時的參數校驗規則 */public interface PersonAddView {
}/**
* 可以在一個Model上面添加多套參數驗證規則,此接口定義添加Person模型修改時的參數校驗規則 */public interface PersonModifyView {
}
2、Model上添加註解時使用指明所述的分組
public class Person { private long id; /**
* 添加groups 屬性,說明只在特定的驗證規則裏面起作用,不加則表示在使用Deafault規則時起作用 */
@NotNull(groups = {PersonAddView.class, PersonModifyView.class}, message = “添加、修改用戶時名字不能為空”, payload = ValidateErrorLevel.Info.class)
@ListNotHasNull.List({
@ListNotHasNull(groups = {PersonAddView.class}, message = “添加上Name不能為空”),
@ListNotHasNull(groups = {PersonModifyView.class}, message = “修改時Name不能為空”)}) private String name;
@NotNull(groups = {PersonAddView.class}, message = “添加用戶時地址不能為空”) private String address;
@Min(value = 18, groups = {PersonAddView.class}, message = “姓名不能低於18歲”)
@Max(value = 30, groups = {PersonModifyView.class}, message = “姓名不能超過30歲”) private int age; //getter setter 方法……}
3、啟用校驗
此時啟用校驗和之前的不同,需要指明啟用哪一組規則
/**
* 添加一個Person對象
* 此處啟用PersonAddView 這個驗證規則
* 備註:此處@Validated(PersonAddView.class) 表示使用PersonAndView這套校驗規則,若使用@Valid 則表示使用默認校驗規則,
* 若兩個規則同時加上去,則只有第一套起作用 */
@RequestMapping(value = “/person”, method = RequestMethod.POST) public void addPerson(@RequestBody @Validated({PersonAddView.class, Default.class}) Person person) {
System.out.println(person.toString());
} /**
* 修改Person對象
* 此處啟用PersonModifyView 這個驗證規則 */
@RequestMapping(value = “/person”, method = RequestMethod.PUT) public void modifyPerson(@RequestBody @Validated(value = {PersonModifyView.class}) Person person) {
System.out.println(person.toString());
}
Spring validator 方法級別的校驗
JSR和Hibernate validator的校驗只能對Object的屬性進行校驗,不能對單個的參數進行校驗,spring 在此基礎上進行了擴展,添加了MethodValidationPostProcessor攔截器,可以實現對方法參數的校驗,實現如下:
1、實例化MethodValidationPostProcessor
@Bean public MethodValidationPostProcessor methodValidationPostProcessor() { return new MethodValidationPostProcessor();
}
2、在所要實現方法參數校驗的類上面添加@Validated,如下
@RestController
@Validatedpublic class ValidateController {
}
3、在方法上面添加校驗規則:
@RequestMapping(value = “/test”, method = RequestMethod.GET) public String paramCheck(@Length(min = 10) @RequestParam String name) {
System.out.println(name); return null;
}
當方法上面的參數校驗失敗,spring 框架就回拋出異常
{ “timestamp”: 1476108200558, “status”: 500, “error”: “Internal Server Error”, “exception”: “javax.validation.ConstraintViolationException”, “message”: “No message available”, “path”: “/test”}
如何自定義JSR-303標準的validator
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern;
@Pattern.List({
@Pattern(
regexp = “[a-z0-9!#$%』*+/=?^_『{|}~-]+(?:\\.[a-z0-9!#$%』*+/=?^_『{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?”) })
@Constraint(validatedBy = {})
@Documented
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR,
ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Email {
String message() default “{invalid.email}”;
Class?[] groups() default {};
Class? extends Payload[] payload() default {};
@Documented
@Target({
ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR,
ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@interface List {
Email[] value();
}
}
public interface PwdGroup {
}
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import javax.validation.groups.Default;
public class User {
@Min(1)
private int userId;
@NotNull(message = “用戶名不能為空!”)
@Size(min = 1, message = “用戶名不能為空!”)
private String userName;
@NotNull
@Size(min = 6, max = 20, message = “密碼長度必須在6-20之間!”, groups = { PwdGroup.class })
private String userPwd;
@Min(value = 18, message = “{user.validation.age.Min.message}”)
@Max(value = 60, message = “年齡最大值必須是60”)
private int userAge;
private String email;
public User(int userId, String userName, String userPwd, int userAge,
String email) {
super();
this.userName = userName;
this.userPwd = userPwd;
this.userAge = userAge;
this.email = email;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public static void main(String[] args) {
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
User user = new User(1, “a”, “b”, 10, “1222”);
SetConstraintViolationUser constraintViolations = validator
.validate(user);
for (ConstraintViolationUser constraintViolation : constraintViolations) {
System.out.println(constraintViolation.getPropertyPath() + ” “
+ constraintViolation.getMessage());
}
System.out.println();
constraintViolations = validator.validate(user, PwdGroup.class);
for (ConstraintViolationUser constraintViolation : constraintViolations) {
System.out.println(constraintViolation.getPropertyPath() + ” “
+ constraintViolation.getMessage());
}
System.out.println();
constraintViolations = validator.validate(user, Default.class,
PwdGroup.class);
for (ConstraintViolationUser constraintViolation : constraintViolations) {
System.out.println(constraintViolation.getPropertyPath() + ” “
+ constraintViolation.getMessage());
}
}
}
spring mvc為什麼不能返回基本數據類型
們都是表現層框架,都是基於 MVC 模型編寫的。
它們的底層都離不開原始 ServletAPI。
它們處理請求的機制都是一個核心控制器。
區別:
Spring MVC 的入口是 Servlet, 而 Struts2 是 Filter。
Spring MVC 是基於方法設計的,而 Struts2 是基於類,Struts2 每次執行都會創建一個動作類。所以 Spring MVC 會稍微比 Struts2 快些。
Spring MVC 使用更加簡潔,同時還支持 JSR303, 處理 ajax 的請求更方便。
(JSR303 是一套 JavaBean 參數校驗的標準,它定義了很多常用的校驗註解,我們可以直接將這些註解加在我們 JavaBean 的屬性上面,就可以在需要校驗的時候進行校驗了。)
Struts2 的 OGNL 表達式使頁面的開發效率相比 Spring MVC 更高些,但執行效率並沒有比 JSTL 提升,尤其是 struts2 的表單標籤,遠沒有 html 執行效率高。
2.SpringMVC不同返回值類型的響應
準備工作:在webapp下創建一個response.jsp頁面
在WEB-INF/pages目錄下創建一個success.jsp頁面
創建一個User類(username,password,age三個屬性)
創建一個UserController
2.1.返回值是String類型的響應
controller 方法返回字符串可以指定邏輯視圖名,通過視圖解析器解析為物理視圖地址。
使用這種方法會通過視圖解析器解析出對應地址:WEB-INF/pages/xxx.jsp
2.1.1.在response.jsp頁面寫一個超鏈接
a href=”user/testString” testString/a
2.1.2.在UserController寫返回值是String類型的方法
複製代碼
//指定邏輯視圖名,經過視圖解析器解析為 jsp 物理路徑:/WEB-INF/pages/success.jsp
@RequestMapping(“/testString”)
public String testString(Model model){
System.out.println(“testString方法執行了…”);
// 模擬從數據庫中查詢出User對象
User user = new User();
user.setUsername(“美美”);
user.setPassword(“123”);
user.setAge(30);
// model對象
model.addAttribute(“user”,user);
return “success”;
}
複製代碼
2.1.3.在success.jsp頁面通過el表達式取值
h3執行成功/h3
${user.username}
${user.password}
2.2.返回值是void類型的響應
2.2.1.在response.jsp頁面寫一個超鏈接
a href=”user/testVoid” testVoid/a
2.2.2.在UserController寫返回值是void類型的方法
因為是void類型,不能像上一個String類型一樣直接返回一個字符串(一個jsp頁面),所以需要用到servlet的原始API,在Controller方法的形參上定義
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/227798.html