Spring Boot 中的验证
在本文中,通过Gradle项目,让我们了解如何验证示例应用程序并在浏览器中显示输出。该应用程序准备为Spring Boot类型,在本文中让我们了解如何通过命令行执行。
示例项目
项目结构:
因为这是 Gradle 项目,所以我们需要检查
build.gradle
buildscript { ext { springBootVersion = '2.3.1.RELEASE' } repositories { mavenCentral() } dependencies { classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}") } } apply plugin: 'java' apply plugin: 'eclipse' apply plugin: 'org.springframework.boot' apply plugin: 'io.spring.dependency-management' group = 'gfg' version = '0.0.1-SNAPSHOT' sourceCompatibility = 8 repositories { mavenCentral() } dependencies { implementation('org.springframework.boot:spring-boot-starter-data-jpa') // This is very much essential for validation implementation('org.springframework.boot:spring-boot-starter-validation') implementation('org.springframework.boot:spring-boot-starter-web') runtimeOnly('com.h2database:h2') testImplementation('org.springframework.boot:spring-boot-starter-test') testImplementation('org.junit.jupiter:junit-jupiter-engine:5.0.1') // these dependencies are needed when running with Java 11, since they // are no longer part of the JDK implementation('javax.xml.bind:jaxb-api:2.3.1') implementation('org.javassist:javassist:3.23.1-GA') } test{ useJUnitPlatform() }
gradlew.bat(Windows 的 Gradle 启动脚本)
@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @rem @rem ########################################################################## @rem Set local scope for the variables with windows NT shell if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. set DEFAULT_JVM_OPTS= @rem Find java.exe if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NULL 2>&1 if "%ERRORLEVEL%" == "0" goto init echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :findJavaFromJavaHome set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto init echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo. echo Please set the JAVA_HOME variable in your environment to match the echo location of your Java installation. goto fail :init @rem Get command-line arguments, handling Windows variants if not "%OS%" == "Windows_NT" goto win9xME_args :win9xME_args @rem Slurp the command line arguments. set CMD_LINE_ARGS= set _SKIP=2 :win9xME_args_slurp if "x%~1" == "x" goto execute set CMD_LINE_ARGS=%* :execute @rem Setup the command line set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% :end @rem End local scope for the variables with windows NT shell if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal :omega
现在让我们看看应用程序开始执行的主应用程序文件
SampleValidationApplication.java
- Java
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication public class SampleValidationApplication {
public static void main(String[] args) { SpringApplication.run(SampleValidationApplication.class, args); } } |
让我们看看有助于以有意义且清晰的方式产生验证错误的必要文件
ErrorHandlingControllerAdviceSample.java
- Java
import javax.validation.ConstraintViolation; import javax.validation.ConstraintViolationException;
import org.springframework.http.HttpStatus; import org.springframework.validation.FieldError; import org.springframework.web.bind.MethodArgumentNotValidException; 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.bind.annotation.ResponseStatus;
@ControllerAdvice class ErrorHandlingControllerAdviceSample {
@ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody ValidationErrorResponse onConstraintValidationException(ConstraintViolationException e) { ValidationErrorResponse error = new ValidationErrorResponse(); for (ConstraintViolation violation : e.getConstraintViolations()) { error.getViolations().add(new Violation(violation.getPropertyPath().toString(), violation.getMessage())); } return error; }
@ExceptionHandler(MethodArgumentNotValidException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody ValidationErrorResponse onMethodArgumentNotValidException(MethodArgumentNotValidException e) { ValidationErrorResponse error = new ValidationErrorResponse(); for (FieldError fieldError : e.getBindingResult().getFieldErrors()) { error.getViolations().add(new Violation(fieldError.getField(), fieldError.getDefaultMessage())); } return error; }
} |
ValidationErrorResponse.java
- Java
import java.util.ArrayList; import java.util.List;
public class ValidationErrorResponse {
private List<Violation> violations = new ArrayList<>();
public List<Violation> getViolations() { return violations; }
public void setViolations(List<Violation> violations) { this.violations = violations; } } |
Violation.java
- Java
public class Violation {
private final String fieldName;
private final String message;
public Violation(String fieldName, String message) { this.fieldName = fieldName; this.message = message; }
public String getFieldName() { return fieldName; }
public String getMessage() { return message; } } |
ValidateGivenParametersByController.java
这是控制器文件,我们可以在其中放置用于条件检查的注释
- Java
import javax.validation.ConstraintViolationException; import javax.validation.constraints.Min; import javax.validation.constraints.Max; import javax.validation.constraints.Email; import javax.validation.constraints.Positive; import javax.validation.constraints.NegativeOrZero;
import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController;
@RestController @Validated class ValidateGivenParametersByController {
@GetMapping("/validatePathVariable/{id}") ResponseEntity<String> validatePathVariable(@PathVariable("id") @Min(5) int id) { return ResponseEntity.ok("valid"); }
@GetMapping("/validateRequestParameterWithMin") ResponseEntity<String> validateRequestParameterWithMin(@RequestParam("id") @Min(0) int id) { return ResponseEntity.ok("valid"); }
@GetMapping("/validateRequestParameterWithMax") ResponseEntity<String> validateRequestParameterWithMax(@RequestParam("id") @Max(5) int id) { return ResponseEntity.ok("valid"); }
@GetMapping("/validateRequestParameterWithEmailId") ResponseEntity<String> validateRequestParameterWithEmailId(@Email @RequestParam(name = "emailId") String emailId) { return ResponseEntity.ok("valid"); }
@GetMapping("/validateRequestParameterWithPositive") ResponseEntity<String> validateRequestParameterWithPositive(@Positive @RequestParam(name = "id") int id) { return ResponseEntity.ok("valid"); }
@GetMapping("/validateRequestParameterWithNegativeOrZero") ResponseEntity<String> validateRequestParameterWithNegativeOrZero(@NegativeOrZero @RequestParam(name = "id") int id) { return ResponseEntity.ok("valid"); }
@ExceptionHandler(ConstraintViolationException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) @ResponseBody String handleConstraintViolationException(ConstraintViolationException e) { return "Given input is not valid due to validation error: " + e.getMessage(); }
} |
通过命令行,我们可以按如下方式执行项目
现在让我们测试以下内容
测试 1:
http://localhost:8080/validatePathVariable/90
这是有效的,因为我们的代码中 id 应该是 @Min(5))。同时,如果我们传递
http://localhost:8080/validatePathVariable/1
将会抛出错误
测试2:
http://localhost:8080/validateRequestParameterWithMin?id=-10
这里应用了@Min(0),因此我们可以在下面看到验证错误消息
测试 3:
http://localhost:8080/validateRequestParameterWithMax?id=10
这里应用了@Max(5),因此
测试 4:
http://localhost:8080/validateRequestParameterWithEmailId?emailId=a.com
这里 emailId 没有正确给出
测试 5:
http://localhost:8080/validateRequestParameterWithPositive?id=-200
因此仅接受正数
测试 6:
http://localhost:8080/validateRequestParameterWithNegativeOrZero?id=100
因此仅接受负数或零
最后
在整个项目中,我们可以使用必要的注释并验证输入字段。我们还可以给出适当的错误消息,使软件更高效。