Java參數(shù)校驗中validation和validator的區(qū)別詳解
1. 參數(shù)校驗概述
常見的業(yè)務(wù)開發(fā)中無可避免的會進(jìn)行請求參數(shù)校驗,一般對于復(fù)雜的業(yè)務(wù)參數(shù)校驗,可以通過校驗類單獨的校驗方法進(jìn)行處理,通常對于一些與業(yè)務(wù)無關(guān)簡單的參數(shù)校驗可以采用javax.validation 和 hibernate-validator通過注解的方式實現(xiàn)校驗。
2. validation與validator區(qū)別
javax的validation是Java定義的一套基于注解的數(shù)據(jù)校驗規(guī)范,目前已經(jīng)從JSR 303的1.0版本升級到JSR 349的1.1版本,再到JSR 380的2.0版本(2.0完成于2017.08),已經(jīng)經(jīng)歷了三個版本。 需要注意的是,JSR只是一項標(biāo)準(zhǔn),它規(guī)定了一些校驗注解的規(guī)范,但沒有實現(xiàn),比如@Null、@NotNull、@Pattern等,它們位于 javax.validation.constraints這個包下。而hibernate validator是對這個規(guī)范的實現(xiàn),并增加了一些其他校驗注解,如 @NotBlank、@NotEmpty、@Length等,它們位于org.hibernate.validator.constraints這個包下。
如果我們的項目使用了Spring Boot,hibernate validator框架已經(jīng)集成在 spring-boot-starter-web中,所以無需再添加其他依賴。如果不是Spring Boot項目,需要添加如下依賴。
<dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency>
3. validation注解說明
注解 | 說明 |
@Null | 被注釋的元素必須為null |
@NotNull | 被注釋的元素不能為null |
@AssertTrue | 被注釋的元素必須為true |
@AssertFalse | 被注釋的元素必須為false |
@Min(value) | 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值 |
@Max(value) | 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值 |
@DecimalMin(value) | 被注釋的元素必須是一個數(shù)字,其值必須大于等于指定的最小值 |
@DecimalMax(value) | 被注釋的元素必須是一個數(shù)字,其值必須小于等于指定的最大值 |
@Size(max,min) | 被注釋的元素的大小必須在指定的范圍內(nèi) |
@Digits(integer, fraction) | 被注釋的元素必須是一個數(shù)字,其值必須必須在可接受的范圍內(nèi) |
@Past | 被注釋的元素必須是一個過去的日期 |
@Future | 被注釋的元素必須是一個將來的日期 |
@Pattern(value) | 被注釋的元素必須符合指定的正則表達(dá)式 |
4. validator注解說明
注解 | 說明 |
@NotBlank | 被注釋的元素不能為null,去除空格( trim() 之后 size > 0) 且長度必須大于0,只能用于注解字符串 |
@NotEmpty | 被注釋的元素值不為null且不為空,支持字符串、集合、Map和數(shù)組類型 |
@Length(min=,max=) | 檢查所屬的字段的長度是否在min和max之間,只能用于字符串 |
被注釋的元素必須是電子郵箱地址 | |
@Range(min=,max=,message=) | 被注釋的元素必須在合適的范圍內(nèi) |
@Pattern(regex=,flag=) | 被注釋的元素必須符合指定的正則表達(dá)式 |
注意:
1.正則表達(dá)式@Pattern注解只用于String類型的字段上。數(shù)字類型的可用@Range注解。
2.需要在Controller中請求對象或者參數(shù)前加@Validated或@Valid注解一起使用, @Validated和@Valid注解區(qū)別不是很大,一般情況下任選一個即可,區(qū)別如下:
注解 @Validated @Valid 所屬的包屬于org.springframework.validation.annotation包下的,是spring提供的屬于javax.validation包下,是jdk給提供的是否支持分組和排序是否
雖然@Validated比@Valid更加強(qiáng)大,在@Valid之上提供了分組功能和驗證排序功能,不過在實際項目中一直沒有用到過 Hibernate-validate框架中的注解是需要加在實體中一起使用的
5. 日期格式化說明
java日期問題,針對Date類型字段。
1.接收前端校驗注解,@DateTimeFormat 接受前臺的時間格式 傳到后臺的格式。
@DateTimeFormat(pattern="yyyy-MM-dd") private Date born;
2.后端返回給前端日期格式化,使用場景數(shù)據(jù)庫存儲的是yyyy-MM-dd HH:mm:ss,但是前端需要yyyy-MM-dd的時候可以使用此注解。
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd") private Date born;
6. 實現(xiàn)驗證
6.1 引入依賴
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.5.0</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.example</groupId> <artifactId>category</artifactId> <version>0.0.1-SNAPSHOT</version> <name>category</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.4</version> </dependency> <!--數(shù)據(jù)庫連接誒--> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--常用工具--> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> <version>30.1.1-jre</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> <version>5.6.3</version> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> </dependency> <!--swagger2--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> <version>2.6</version> </dependency> <!--字段校驗--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>2.0.1.Final</version> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.0.13.Final</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
6.2 代碼實現(xiàn)
1.實體類
import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.hibernate.validator.constraints.Length; import org.hibernate.validator.constraints.Range; import javax.validation.constraints.*; /** * 員工實體類 * * @author zrj * @since 2021/7/31 **/ @Data @ApiModel(value = "Employee", description = "員工信息") public class Employee { @NotNull(message = "userId is empty") @ApiModelProperty(value = "員工ID") private Integer id; @NotBlank(message = "員工姓名不能為空") @Length(min = 1, max = 100, message = "員工姓名長度不能超過50字") @ApiModelProperty(value = "員工姓名") private String name; @Range(min = 1, max = 200, message = "年齡范圍[1,200]") @ApiModelProperty(value = "年齡") private Integer age; @Pattern(regexp = "^[0-1]$", message = "員工類型范圍[0,1]") @ApiModelProperty(value = "員工類型(0行政崗;1基礎(chǔ)崗") private String type; @Pattern(regexp = "^[1][^0^1^2][0-9]{9}$", message = "員工手機(jī)號碼不合法") @ApiModelProperty(value = "員工手機(jī)號碼") private String phone; @Email(message = "員工郵箱不合法") @Length(min = 1, max = 50, message = "員工郵箱長度") @ApiModelProperty(value = "員工郵箱") private String email; @Length(min = 0, max = 200, message = "備注長度不能超過100字") @ApiModelProperty(value = "備注") private String remarks; }
2.控制類
import com.example.category.entity.Employee; import com.example.category.entity.Response; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.*; import javax.validation.Valid; /** * 員工控制類 * * @author zrj * @since 2021/7/31 **/ @RestController @RequestMapping("/employee") @Api(value = "employee", description = "員工管理") public class EmployeeController { @GetMapping("/test") @ApiOperation(value = "test測試", notes = "test測試", httpMethod = "GET") public Response test() { return Response.success("查詢成功", null); } /** * Valid測試 * 這里職位測試@Valid,所以不在寫其他各層 */ @PostMapping("/validEpmloyee") @ApiOperation(value = "Valid測試", notes = "Valid測試", httpMethod = "POST") public Response<Employee> validEpmloyee(@Valid @RequestBody Employee employee) { System.out.println("測試請求對象:" + employee); if (employee != null) { return Response.success("查詢成功", employee); } return Response.fail("查詢失敗"); } }
3.結(jié)果集響應(yīng)碼
package com.example.category.entity; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; /** * 結(jié)果集封裝 * * @author zrj * @date 2021/6/2 * @since V1.0 **/ @Data @Component public class Response<T> { private static ResponseCode responseCode; /** * 提示消息 */ private String message; /** * 具體返回的數(shù)據(jù) */ private T data; /** * 狀態(tài)碼 */ private String code; private Response(String code, String message, T data) { this.message = message; this.code = code; this.data = data; } private Response(String code, String msg) { this.message = msg; this.code = code; } @Autowired public Response(ResponseCode responseCode) { Response.responseCode = responseCode; } /** * 返回成功Response對象 */ public static <T> Response<T> success(String successMessage, T data) { return new Response<>(responseCode.getSuccessCode(), successMessage, data); } /** * 返回錯誤Response對象 */ public static <T> Response<T> fail(String errorMessage) { return new Response<>(responseCode.getErrorCode(), errorMessage); } }
import lombok.Data; import org.springframework.stereotype.Component; /** * 響應(yīng)碼 * * @author zrj * @date 2021/6/2 * @since V1.0 **/ @Data @Component public class ResponseCode { public String successCode = "200"; public String errorCode = "500"; public String authErrorCode = "300"; }
4.異常切面封裝類
import com.example.category.entity.Response; import com.fasterxml.jackson.databind.JsonMappingException; import lombok.extern.slf4j.Slf4j; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.util.CollectionUtils; import org.springframework.validation.ObjectError; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException; import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException; import java.util.List; import java.util.Set; /** * 異常切面封裝類 * * @author zrj * @since 2021/7/31 **/ @ControllerAdvice @ResponseBody @Slf4j public class ExceptionHandlerAdvice { /** * Exception */ @ExceptionHandler(Exception.class) public Response<String> handleGlobalException(Exception exception, HandlerMethod handlerMethod) { if (exception instanceof MethodArgumentNotValidException) { List<ObjectError> errors = ((MethodArgumentNotValidException) exception).getBindingResult().getAllErrors(); StringBuilder sb = new StringBuilder(); if (!CollectionUtils.isEmpty(errors)) { for (ObjectError error : errors) { if (sb.length() != 0) { sb.append(","); } sb.append(error.getDefaultMessage()); } } return Response.fail(sb.toString()); } // 約束異常 if (exception instanceof ConstraintViolationException) { Set<ConstraintViolation<?>> exceptionSet = ((ConstraintViolationException) exception).getConstraintViolations(); StringBuilder sb = new StringBuilder(); if (!CollectionUtils.isEmpty(exceptionSet)) { for (ConstraintViolation<?> set : exceptionSet) { if (sb.length() != 0) { sb.append(","); } sb.append(set.getMessageTemplate()); } } return Response.fail(sb.toString()); } // 參數(shù)類型轉(zhuǎn)換異常處理 if (exception instanceof MethodArgumentTypeMismatchException) { return Response.fail(((MethodArgumentTypeMismatchException) exception).getName() + " 類型不匹配"); } if (exception instanceof JsonMappingException) { return Response.fail("JSON格式錯誤, " + exception.getLocalizedMessage()); } if (exception instanceof HttpMessageNotReadableException) { return Response.fail("請求體格式錯誤, " + exception.getLocalizedMessage()); } if (exception instanceof MissingServletRequestParameterException) { String paramName = ((MissingServletRequestParameterException) exception).getParameterName(); return Response.fail(paramName + " 不能為空"); } //if (exception instanceof MarketingException) { // MarketingException marketingException = (MarketingException) exception; // return RdfaResult.fail(marketingException.getErrorCodeEnum().getCode(), exception.getMessage()); //} // 其他異常打印日志 log.error("{}.{} error, ", handlerMethod.getBeanType().getSimpleName(), handlerMethod.getMethod().getName(), exception); //if (exception instanceof RpcException) { // return RdfaResult.fail(ErrorCodeEnum.RPC_ERROR.getCode(), "RPC調(diào)用錯誤,請稍后重試"); //} return Response.fail("服務(wù)器內(nèi)部錯誤,請聯(lián)系開發(fā)人員!"); } }
6.3 實現(xiàn)驗證
到此這篇關(guān)于Java參數(shù)校驗中validation和validator的區(qū)別詳解的文章就介紹到這了,更多相關(guān)validation和validator的區(qū)別內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于MyBaties的基本配置標(biāo)簽總結(jié)
今天給大家?guī)淼氖顷P(guān)于MyBaties基礎(chǔ)的相關(guān)知識,文章圍繞著MyBaties的基本配置標(biāo)簽展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹
這篇文章主要介紹了java環(huán)境中的JDK、JVM、JRE詳細(xì)介紹的相關(guān)資料,對于初學(xué)者還是有必要了解下,細(xì)致說明他們是什么,需要的朋友可以參考下2016-11-11從內(nèi)存地址解析Java的static關(guān)鍵字的作用
這篇文章主要介紹了從內(nèi)存地址解析Java的static關(guān)鍵字的作用,包括靜態(tài)成員變量和靜態(tài)方法等重要內(nèi)容,需要的朋友可以參考下2015-10-10配置idea將Java與數(shù)據(jù)庫連接起來實現(xiàn)一個簡單的圖書管理系統(tǒng)
這篇文章主要給大家介紹了關(guān)于配置idea將Java與數(shù)據(jù)庫連接起來實現(xiàn)一個簡單的圖書管理系統(tǒng)的相關(guān)資料,本文從基于Java的圖書管理系統(tǒng)的背景、系統(tǒng)設(shè)計、數(shù)據(jù)庫設(shè)計和系統(tǒng)實現(xiàn)等方面進(jìn)行了詳細(xì)的研究,需要的朋友可以參考下2023-12-12