jsr303代碼校驗(jsr303自定義校驗參數)

本文目錄一覽:

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;

  @Email

  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-hant/n/227798.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-09 21:21
下一篇 2024-12-09 21:21

相關推薦

  • Python周杰倫代碼用法介紹

    本文將從多個方面對Python周杰倫代碼進行詳細的闡述。 一、代碼介紹 from urllib.request import urlopen from bs4 import Bea…

    編程 2025-04-29
  • Python字符串寬度不限制怎麼打代碼

    本文將為大家詳細介紹Python字符串寬度不限制時如何打代碼的幾個方面。 一、保持代碼風格的統一 在Python字符串寬度不限制的情況下,我們可以寫出很長很長的一行代碼。但是,為了…

    編程 2025-04-29
  • Python基礎代碼用法介紹

    本文將從多個方面對Python基礎代碼進行解析和詳細闡述,力求讓讀者深刻理解Python基礎代碼。通過本文的學習,相信大家對Python的學習和應用會更加輕鬆和高效。 一、變量和數…

    編程 2025-04-29
  • 三星內存條參數用法介紹

    本文將詳細解釋三星內存條上面的各種參數,讓你更好地了解內存條並選擇適合自己的一款。 一、容量大小 容量大小是內存條最基本的參數,一般以GB為單位表示,常見的有2GB、4GB、8GB…

    編程 2025-04-29
  • Python3定義函數參數類型

    Python是一門動態類型語言,不需要在定義變量時顯示的指定變量類型,但是Python3中提供了函數參數類型的聲明功能,在函數定義時明確定義參數類型。在函數的形參後面加上冒號(:)…

    編程 2025-04-29
  • Python滿天星代碼:讓編程變得更加簡單

    本文將從多個方面詳細闡述Python滿天星代碼,為大家介紹它的優點以及如何在編程中使用。無論是剛剛接觸編程還是資深程序員,都能從中獲得一定的收穫。 一、簡介 Python滿天星代碼…

    編程 2025-04-29
  • 倉庫管理系統代碼設計Python

    這篇文章將詳細探討如何設計一個基於Python的倉庫管理系統。 一、基本需求 在着手設計之前,我們首先需要確定倉庫管理系統的基本需求。 我們可以將需求分為以下幾個方面: 1、庫存管…

    編程 2025-04-29
  • 寫代碼新手教程

    本文將從語言選擇、學習方法、編碼規範以及常見問題解答等多個方面,為編程新手提供實用、簡明的教程。 一、語言選擇 作為編程新手,選擇一門編程語言是很關鍵的一步。以下是幾個有代表性的編…

    編程 2025-04-29
  • Spring Boot中發GET請求參數的處理

    本文將詳細介紹如何在Spring Boot中處理GET請求參數,並給出完整的代碼示例。 一、Spring Boot的GET請求參數基礎 在Spring Boot中,處理GET請求參…

    編程 2025-04-29
  • Python input參數變量用法介紹

    本文將從多個方面對Python input括號里參數變量進行闡述與詳解,並提供相應的代碼示例。 一、基本介紹 Python input()函數用於獲取用戶輸入。當程序運行到inpu…

    編程 2025-04-29

發表回復

登錄後才能評論