国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring Boot】SpringBoot參數驗證以及實現原理

這篇具有很好參考價值的文章主要介紹了【Spring Boot】SpringBoot參數驗證以及實現原理。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

前言

參數驗證很重要,是平時開發(fā)環(huán)節(jié)中不可少的一部分,但是我想很多后端同事會偷懶,干脆不做,這樣很可能給系統(tǒng)的穩(wěn)定性和安全性帶來嚴重的危害。
那么在Spring Boot應用中如何做好參數校驗工作呢,本文提供了小技巧以及驗證實現原理,你知道幾個呢?

SpringBoot參數驗證技巧(12個技巧)

一、使用驗證注解

Spring Boot 提供了內置的驗證注解,可以幫助簡單、快速地對輸入字段進行驗證,例如檢查 null 或空字段、強制執(zhí)行長度限制、使用正則表達式驗證模式以及驗證電子郵件地址。

  • 設置依賴
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
  • 一些最常用的驗證注釋包括:

    • @NotNull:指定字段不能為空。
    • @NotEmpty:指定列表字段不能為空。
    • @NotBlank:指定字符串字段不得為空或僅包含空格。
    • @Min 和 @Max:指定數字字段的最小值和最大值。
    • @Pattern:指定字符串字段必須匹配的正則表達式模式。
    • @Email:指定字符串字段必須是有效的電子郵件地址。
      更多注解見下面附錄
  • 具體用法參考下面例子:

    public class User {
        @NotNull
        private Long id;
    
        @NotBlank
        @Size(min = 2, max = 50)
        private String firstName;
    
        @NotBlank
        @Size(min = 2, max = 50)
        private String lastName;
    
        @Email
        private String email;
    
        @NotNull
        @Min(18)
        @Max(99)
        private Integer age;
    
        @NotEmpty
        private List<String> hobbies;
    
        @Pattern(regexp = "[A-Z]{2}\d{4}")
        private String employeeId;
     }
    

附:以下是 validation-api中提供的可用的注解列表

注解 含義
@Null 驗證對象必須為 null
@NotNull 驗證對象不為 null
@NotBlank 驗證字符串不能為空null或"",只能用于字符串驗證
@NotEmpty 驗證對象不得為空,可用于Map和數組
@Pattern 驗證字符串是否滿足正則表達式
@AssertTrue 驗證 boolean 類型值為 true
@AssertFalse 驗證 boolean 類型值為 false
@Min(value) 驗證數字的大小是否大于等于指定的值
@Max(value) 驗證數字的大小是否小于等于指定的值
@DecimalMin(value) 驗證數字的大小是否大于等于指定的值,小數存在精度
@DecimalMax(value) 驗證數字的大小是否小于等于指定的值,小數存在精度
@Size(max, min) 驗證對象(字符串、集合、數組)長度是否在指定范圍之內
@Digits(integer, fraction) 驗證數字是否符合指定格式
@Pattern(value) 驗證字符串是否符合正則表達式的規(guī)則
@ParameterScriptAssert 可以在方法參數級別上執(zhí)行腳本驗證,以驗證傳遞給方法的參數是否符合指定的條件。該注解可以與 JSR 223 兼容的腳本引擎一起使用,例如 JavaScript、Groovy、Python 等。- script:腳本表達式,用于執(zhí)行參數驗證。該表達式應該返回一個 boolean 類型的值,表示驗證是否通過。- lang:腳本語言的名稱,默認為 “groovy”。
@Email 驗證字符串是否符合電子郵件地址的格式。
@Future 驗證一個日期或時間是否在當前時間之后。
@FutureOrPresent 驗證一個日期或時間是否在當前時間之后或等于當前時間。
@past 驗證一個日期或時間是否在當前時間之前。
@PastOrPresent 驗證一個日期或時間是否在當前時間之前或等于當前時間。
@Positive 驗證數字是否是正整數,0無效
@PositiveOrZero 驗證數字是否是正整數
@Negative 驗證數字是否是負整數,0無效
@NegativeOrZero 驗證數字是否是負整數

二、使用自定義驗證注解

雖然 Spring Boot 的內置驗證注釋很有用,但它們可能無法涵蓋所有情況。如果有特殊參數驗證的場景,可以使用 Spring 的 JSR 303 驗證框架創(chuàng)建自定義驗證注釋。自定義注解可以讓你的的驗證邏輯更具可重用性和可維護性。

假設我們有一個應用程序,用戶可以在其中創(chuàng)建帖子。每個帖子都應該有一個標題和一個正文,并且標題在所有帖子中應該是唯一的。雖然 Spring Boot 提供了用于檢查字段是否為空的內置驗證注釋,但它沒有提供用于檢查唯一性的內置驗證注釋。在這種情況下,我們可以創(chuàng)建一個自定義驗證注解來處理這種情況。

  • 首先,我們創(chuàng)建自定義約束注解UniqueTitle :
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueTitleValidator.class)
public @interface UniqueTitle {
    String message() default "Title must be unique";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}
  • 接下來,我們創(chuàng)建一個PostRepository接口,目的是從數據庫中檢索帖子:
public interface PostRepository extends JpaRepository<Post, Long> {
    Post findByTitle(String title);
}
  • 然后我們需要定義驗證器類 UniqueTitleValidator,如下所示:
@Component
public class UniqueTitleValidator implements ConstraintValidator<UniqueTitle, String> {

    @Autowired
    private PostRepository postRepository;

    @Override
    public boolean isValid(String title, ConstraintValidatorContext context) {
        if (title == null) {
            return true;
        }
        return Objects.isNull(postRepository.findByTitle(title));
    }
}

UniqueTitleValidator實現了ConstraintValidator接口,它有兩個泛型類型:
第一個是自定義注解UniqueTitle
第二個是正在驗證的字段類型(在本例中為String). 我們還自動裝配了PostRepository 類以從數據庫中檢索帖子。
isValid()方法通過查詢 PostRepository 來檢查 title 是否為 null 或者它是否是唯一的。如果 title 為 null 或唯一,則驗證成功,并返回 true。

  • 最后定義了自定義驗證注釋和驗證器類后,我們現在可以使用它來驗證 Spring Boot 應用程序中的帖子標題:
public class Post {
    @UniqueTitle
    private String title;

    @NotNull
    private String body;
}

我們已將 @UniqueTitle 注釋應用于 Post 類中的 title 變量。驗證此字段時,這將觸發(fā) UniqueTitleValidator 類中定義的驗證邏輯。

三、在服務器端驗證

除了前端或者客戶端做了驗證意外,服務器端驗證輸入是至關重要的。它可以確保在處理或存儲任何惡意或格式錯誤的數據之前將其捕獲,這對于應用程序的安全性和穩(wěn)定性至關重要。
假設我們有一個允許用戶創(chuàng)建新帳戶的 REST 端點。端點需要一個包含用戶用戶名和密碼的 JSON 請求體。為確保輸入有效,我們可以創(chuàng)建一個 DTO(數據傳輸對象)類并將驗證注釋應用于其字段:

public class UserDTO {

    @NotBlank
    private String username;

    @NotBlank
    private String password;
}

我們使用@NotBlank注解來確保username和password字段不為空或 null。
接下來,我們可以創(chuàng)建一個控制器方法來處理 HTTP POST 請求并在創(chuàng)建新用戶之前驗證輸入:

@RestController
@RequestMapping("/users")
@Validated
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody UserDTO userDto) {
        userService.createUser(userDto);
        return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully");
    }
}

我們使用 Spring 的@Validated注解來啟用方法級驗證,我們還將 @Valid 注釋應用于 userDto 參數以觸發(fā)驗證過程。

四、提供有意義的錯誤信息

當驗證失敗時,必須提供清晰簡潔的錯誤消息來描述出了什么問題以及如何修復它。

這是一個示例,如果我們有一個允許用戶創(chuàng)建新用戶的 RESTful API。我們要確保姓名和電子郵件地址字段不為空,年齡在 18 到 99 歲之間,除了這些字段,如果用戶嘗試使用重復的“用戶名”創(chuàng)建帳戶,我們還會提供明確的錯誤消息或“電子郵件”。
為此,我們可以定義一個帶有必要驗證注釋的模型類 User,如下所示:

public class User {

    @NotBlank(message = "用戶名不能為空")
    private String name;

    @NotBlank(message = "Email不能為空")
    @Email(message = "無效的Emaild地址")
    private String email;

    @NotNull(message = "年齡不能為空")
    @Min(value = 18, message = "年齡必須大于18")
    @Max(value = 99, message = "年齡必須小于99")
    private Integer age;
}

我們使用 message屬性為每個驗證注釋提供了自定義錯誤消息。

接下來,在我們的 Spring 控制器中,我們可以處理表單提交并使用 @Valid 注釋驗證用戶輸入:

@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;

    @PostMapping
    public ResponseEntity<String> createUser(@Valid @RequestBody User user, BindingResult result) {
        if (result.hasErrors()) {
            List<String> errorMessages = result.getAllErrors().stream()
                    .map(DefaultMessageSourceResolvable::getDefaultMessage)
                    .collect(Collectors.toList());
            return ResponseEntity.badRequest().body(errorMessages.toString());
        }

        // save the user to the database using UserService
        userService.saveUser(user);

        return ResponseEntity.status(HttpStatus.CREATED).body("User created successfully");
    }
}

我們使用 @Valid 注釋來觸發(fā) User 對象的驗證,并使用 BindingResult 對象來捕獲任何驗證錯誤。

五、將 i18n 用于錯誤消息

如果你的應用程序支持多種語言,則必須使用國際化 (i18n) 以用戶首選語言顯示錯誤消息。
以下是在 Spring Boot 應用程序中使用 i18n 處理錯誤消息的示例

  • 首先,在資源目錄下創(chuàng)建一個包含默認錯誤消息的 messages.properties 文件
# messages.properties
user.name.required=Name is required.
user.email.invalid=Invalid email format.
user.age.invalid=Age must be a number between 18 and 99.
  • 接下來,為每種支持的語言創(chuàng)建一個 messages_xx.properties 文件,例如,中文的 messages_zh_CN.properties。
user.name.required=名稱不能為空.
user.email.invalid=無效的email格式.
user.age.invalid=年齡必須在1899歲之間.
  • 然后,更新您的驗證注釋以使用本地化的錯誤消息
public class User {
    @NotNull(message = "{user.id.required}")
    private Long id;

    @NotBlank(message = "{user.name.required}")
    private String name;

    @Email(message = "{user.email.invalid}")
    private String email;

    @NotNull(message = "{user.age.required}")
    @Min(value = 18, message = "{user.age.invalid}")
    @Max(value = 99, message = "{user.age.invalid}")
    private Integer age;
}
  • 最后,在Spring 配置文件中配置 MessageSource bean 以加載 i18n 消息文件
@Configuration
public class AppConfig {
    @Bean
    public MessageSource messageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }

    @Bean
    public LocalValidatorFactoryBean validator() {
        LocalValidatorFactoryBean validatorFactoryBean = new LocalValidatorFactoryBean();
        validatorFactoryBean.setValidationMessageSource(messageSource());
        return validatorFactoryBean;
    }
}

現在,當發(fā)生驗證錯誤時,錯誤消息將根據隨請求發(fā)送的“Accept-Language”標頭以用戶的首選語言顯示。

六、使用分組驗證

驗證組是 Spring Boot 驗證框架的一個強大功能,允許您根據其他輸入值或應用程序狀態(tài)應用條件驗證規(guī)則。

現在有一個包含三個字段的User類的情況下:firstName、lastName和email。我們要確保如果 email 字段為空,則 firstName 或 lastName 字段必須非空。否則,所有三個字段都應該正常驗證。

為此,我們將定義兩個驗證組:EmailNotEmpty 和 Default。EmailNotEmpty 組將包含當 email 字段不為空時的驗證規(guī)則,而 Default 組將包含所有三個字段的正常驗證規(guī)則。

創(chuàng)建帶有驗證組的 User 類

public class User {
    @NotBlank(groups = Default.class)
    private String firstName;

    @NotBlank(groups = Default.class)
    private String lastName;

    @Email(groups = EmailNotEmpty.class)
    private String email;

    // getters and setters omitted for brevity
    public interface EmailNotEmpty {}
    public interface Default {}
}

請注意,我們在User類中定義了兩個接口,EmailNotEmpty和 Default。這些將作為我們的驗證組。

接下來,我們更新Controller使用這些驗證組

@RestController
@RequestMapping("/users")
@Validated
public class UserController {
    public ResponseEntity<String> createUser(
            @Validated({org.example.model.ex6.User.EmailNotEmpty.class}) @RequestBody User userWithEmail,
            @Validated({User.Default.class}) @RequestBody User userWithoutEmail)
    {
        // Create the user and return a success response
       
    }
}

我們已將@Validated注釋添加到我們的控制器,表明我們想要使用驗證組。我們還更新了 createUser 方法,將兩個 User 對象作為輸入,一個在 email 字段不為空時使用,另一個在它為空時使用。
@Validated 注釋用于指定將哪個驗證組應用于每個 User 對象。對于 userWithEmail 參數,我們指定了 EmailNotEmpty 組,而對于 userWithoutEmail 參數,我們指定了 Default 組。

進行這些更改后,現在將根據“電子郵件”字段是否為空對“用戶”類進行不同的驗證。如果為空,則 firstName 或 lastName 字段必須非空。否則,所有三個字段都將正常驗證。

七、對復雜邏輯使用跨域驗證

如果需要驗證跨多個字段的復雜輸入規(guī)則,可以使用跨字段驗證來保持驗證邏輯的組織性和可維護性。跨字段驗證可確保所有輸入值均有效且彼此一致,從而防止出現意外行為。

假設我們有一個表單,用戶可以在其中輸入任務的開始日期和結束日期,并且我們希望確保結束日期不早于開始日期。我們可以使用跨域驗證來實現這一點。

  • 首先,我們定義一個自定義驗證注解EndDateAfterStartDate:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EndDateAfterStartDateValidator.class)
public @interface EndDateAfterStartDate {
    String message() default "End date must be after start date";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
  • 然后,我們創(chuàng)建驗證器EndDateAfterStartDateValidator:
public class EndDateAfterStartDateValidator implements ConstraintValidator<EndDateAfterStartDate, TaskForm> {
    @Override
    public boolean isValid(TaskForm taskForm, ConstraintValidatorContext context) {
        if (taskForm.getStartDate() == null || taskForm.getEndDate() == null) {
            return true;
        }

        return taskForm.getEndDate().isAfter(taskForm.getStartDate());
    }
}
  • 最后,我們將EndDateAfterStartDate注釋應用于我們的表單對象TaskForm:
@EndDateAfterStartDate
public class TaskForm {
    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate startDate;

    @NotNull
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate endDate;
}

現在,當用戶提交表單時,驗證框架將自動檢查結束日期是否晚于開始日期,如果不是,則提供有意義的錯誤消息。

八、對驗證錯誤使用異常處理

可以使用異常處理ExceptionHandler來統(tǒng)一捕獲和處理驗證錯誤。
以下是如何在 Spring Boot 中使用異常處理來處理驗證錯誤的示例:

@RestControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
                                                                  HttpHeaders headers, HttpStatus status,
                                                                  WebRequest request) {
        Map<String, Object> body = new LinkedHashMap<>();
        body.put("timestamp", LocalDateTime.now());
        body.put("status", status.value());

        // Get all errors
        List<String> errors = ex.getBindingResult()
                .getFieldErrors()
                .stream()
                .map(x -> x.getDefaultMessage())
                .collect(Collectors.toList());

        body.put("errors", errors);

        return new ResponseEntity<>(body, headers, status);
    }
}
  • 在這里,我們創(chuàng)建了一個用 @RestControllerAdvice 注解的 RestExceptionHandler 類來處理我們的 REST API 拋出的異常。

  • 然后我們創(chuàng)建一個用 @ExceptionHandler 注解的方法來處理在驗證失敗時拋出的 MethodArgumentNotValidException。
    在處理程序方法中,我們創(chuàng)建了一個 Map 對象來保存錯誤響應的詳細信息,包括時間戳、HTTP 狀態(tài)代碼和錯誤消息列表。我們使用 MethodArgumentNotValidException 對象的 getBindingResult() 方法獲取所有驗證錯誤并將它們添加到錯誤消息列表中。

  • 最后,我們返回一個包含錯誤響應詳細信息的ResponseEntity對象,包括作為響應主體的錯誤消息列表、HTTP 標頭和 HTTP 狀態(tài)代碼。
    有了這個異常處理代碼,我們的 REST API 拋出的任何驗證錯誤都將被捕獲并以結構化和有意義的格式返回給用戶,從而更容易理解和解決問題。

九、測試你的驗證邏輯

需要為你的驗證邏輯編寫單元測試,以幫助確保它正常工作。

@DataJpaTest
public class UserValidationTest {

    @Autowired
    private TestEntityManager entityManager;

    @Autowired
    private Validator validator;

    @Test
    public void testValidation() {
        User user = new User();
        user.setFirstName("John");
        user.setLastName("Doe");
        user.setEmail("invalid email");

        Set<ConstraintViolation<User>> violations = validator.validate(user);

        assertEquals(1, violations.size());
        assertEquals("must be a well-formed email address", violations.iterator().next().getMessage());
    }
}

我們使用 JUnit 5 編寫一個測試來驗證具有無效電子郵件地址的“用戶”對象。然后我們使用 Validator 接口來驗證 User 對象并檢查是否返回了預期的驗證錯誤。

十、 PathVariable校驗

@GetMapping("/path/{group:[a-zA-Z0-9_]+}/{userid}")
@ResponseBody
public String path(@PathVariable("group") String group, @PathVariable("userid") Integer userid) {
    return group + ":" + userid;
}

用法是:路徑變量:正則表達式。當請求URI不滿足正則表達式時,客戶端將收到404錯誤碼。不方便的地方是,不能通過捕獲異常的方式,向前端返回統(tǒng)一的、自定義格式的響應參數。

十一、方法參數校驗

@GetMapping("/validate1")
@ResponseBody
public String validate1(
        @Size(min = 1,max = 10,message = "姓名長度必須為1到10")@RequestParam("name") String name,
        @Min(value = 10,message = "年齡最小為10")@Max(value = 100,message = "年齡最大為100") @RequestParam("age") Integer age) {
    return "validate1";
}

十二、異常攔截

通過設置全局異常處理,統(tǒng)一向前端返回校驗信息

import com.scj.springbootdemo.WebResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.ObjectError;
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 javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.Set;

/**
 * 全局異常處理器
 */
@ControllerAdvice
public class GlobalExceptionHandler {

    private Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

    /**
     * 用來處理bean validation異常
     * @param ex
     * @return
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public  WebResult resolveConstraintViolationException(ConstraintViolationException ex){
        WebResult errorWebResult = new WebResult(WebResult.FAILED);
        Set<ConstraintViolation<?>> constraintViolations = ex.getConstraintViolations();
        if(!CollectionUtils.isEmpty(constraintViolations)){
            StringBuilder msgBuilder = new StringBuilder();
            for(ConstraintViolation constraintViolation :constraintViolations){
                msgBuilder.append(constraintViolation.getMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if(errorMessage.length()>1){
                errorMessage = errorMessage.substring(0,errorMessage.length()-1);
            }
            errorWebResult.setInfo(errorMessage);
            return errorWebResult;
        }
        errorWebResult.setInfo(ex.getMessage());
        return errorWebResult;
    }

    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public WebResult resolveMethodArgumentNotValidException(MethodArgumentNotValidException ex){
        WebResult errorWebResult = new WebResult(WebResult.FAILED);
        List<ObjectError>  objectErrors = ex.getBindingResult().getAllErrors();
        if(!CollectionUtils.isEmpty(objectErrors)) {
            StringBuilder msgBuilder = new StringBuilder();
            for (ObjectError objectError : objectErrors) {
                msgBuilder.append(objectError.getDefaultMessage()).append(",");
            }
            String errorMessage = msgBuilder.toString();
            if (errorMessage.length() > 1) {
                errorMessage = errorMessage.substring(0, errorMessage.length() - 1);
            }
            errorWebResult.setInfo(errorMessage);
            return errorWebResult;
        }
        errorWebResult.setInfo(ex.getMessage());
        return errorWebResult;
    }
}


Spring method validation的實現原理

spring method validation實現原理研究

  • 一言以蔽之:
    spring validation方法級別校驗的實現是通過MethodValidationPostProcessor類動態(tài)注冊AOP切面,使用MethodValidationInterceptor對切點方法織入增強。

注意:必須要掌握:AOP的基本概念、攔截器的功能和原理、spring aware接口的功能和大致原理。 如果對以上知識的不太清楚的話,建議首先研究下這些。

具體實現流程如下所示:

  • 如下圖所示,在MethodValidationPostProcessor的afterPropertiesSet方法中,動態(tài)創(chuàng)建了一個AnnotationMatchingPointcut類型切點,同時調用createMethodValidationAdvice方法創(chuàng)建出對應的增強。

注意:afterPropertiesSet方法是InitializingBean接口中定義的方法,用于在spring容器初始化的時候,進行對Bean的一些初始化操作,調用的時機是在bean的屬性都set完畢。

【Spring Boot】SpringBoot參數驗證以及實現原理

  • AnnotationMatchingPointcut,見文知意,即注解匹配類型的切點,MethodValidationPostProcessor會創(chuàng)建一個這樣的切點。如下圖,其中classAnnotationType接收到的值Validated.class,表明該切點匹配所有標注了Validated注解的類,同時checkInherited參數是true,表明即使子類不標注Validated注解,但是其父類或者接口標注之后,那么子類也會命中切點。
    【Spring Boot】SpringBoot參數驗證以及實現原理

  • 創(chuàng)建完切點之后,會創(chuàng)建增強,創(chuàng)建過程如下所示:
    【Spring Boot】SpringBoot參數驗證以及實現原理

  • 其中MethodValidationInterceptor是aop聯(lián)盟MethodInterceptor接口的實現,MethodInterceptor接口中聲明了invoke方法,在該方法實現中,可以織入對應的增強。

@FunctionalInterface
public interface MethodInterceptor extends Interceptor {

	/**
	 * Implement this method to perform extra treatments before and
	 * after the invocation. Polite implementations would certainly
	 * like to invoke {@link Joinpoint#proceed()}.
	 * @param invocation the method invocation joinpoint
	 * @return the result of the call to {@link Joinpoint#proceed()};
	 * might be intercepted by the interceptor
	 * @throws Throwable if the interceptors or the target object
	 * throws an exception
	 */
	Object invoke(MethodInvocation invocation) throws Throwable;

}
  • 其中MethodInterceptor織入增強的代碼如下所示:
    【Spring Boot】SpringBoot參數驗證以及實現原理

  • 在這里調用Bean validation的檢驗接口

  1. 進行方法參數的校驗
execVal.validateParameters(invocation.getThis(), 
    			methodToValidate,  invocation.getArguments(), groups);
  1. 進行方法返回值的校驗
execVal.validateReturnValue(invocation.getThis(), 
						methodToValidate, returnValue, groups);
  1. 如果存在違反約束的情況,將會拋出ConstraintViolationException異常,我們可以使用ExceptionHandler顯示捕獲該異常,然后返回前端對應的message。
if (!result.isEmpty()) {
	throw new ConstraintViolationException(result);
}
  • 捕獲異常代碼可以參考如下:
@ControllerAdvice
public class GlobalExceptionHandler {

    @ResponseBody
    @ExceptionHandler
    public String handleException(Throwable e) {
        //方法級別校驗異常,注意筆者這里使用快速失敗機制,如果存在一條違反的約定,那么就不會繼續(xù)后續(xù)的校驗,所以這里返回的ConstraintViolations只有一條
        //讀者可以根據自己的需求,按需返回對應的錯誤信息
        if (e instanceof ConstraintViolationException) {
            return ((ConstraintViolationException) e).getConstraintViolations().iterator().next().getMessage();
        }

        //對象級別校驗,綁定異常
        if (e instanceof BindException) {
            return e.getMessage();
        }

        return e.getMessage();
    }
}

相關標準

JSR 303 是Bean驗證的規(guī)范 ,Hibernate Validator 是該規(guī)范的參考實現,它除了實現規(guī)范要求的注解外,還額外實現了一些注解。
validation-api-1.1.0.jar 包括如下約束注解:

約束注解 說明
@AssertFalse 被注釋的元素必須為 false
@AssertTrue 被注釋的元素必須為 true
@DecimalMax(value) 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
@DecimalMin(value) 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
@Digits (integer, fraction) 被注釋的元素必須是一個數字,其值必須在可接受的范圍內
@Null 被注釋的元素必須為null
@NotNull 被注釋的元素必須不為null
@Min(value) 被注釋的元素必須是一個數字,其值必須大于等于指定的最小值
@Max(value) 被注釋的元素必須是一個數字,其值必須小于等于指定的最大值
@Size(max, min) 被注釋的元素的大小必須在指定的范圍內
@Past 被注釋的元素必須是一個過去的日期
@Future 被注釋的元素必須是一個將來的日期
@Pattern(value) 被注釋的元素必須符合指定的正則表達式

hibernate-validator-5.3.6.jar 包括如下約束注解:

約束注解 說明
@Email 被注釋的元素必須是電子郵箱地址
@Length 被注釋的字符串的大小必須在指定的范圍內
@NotBlank 被注釋的字符串的必須非空
@NotEmpty 被注釋的字符串、集合、Map、數組必須非空
@Range 被注釋的元素必須在合適的范圍內
@SafeHtml 被注釋的元素必須是安全Html
@URL 被注釋的元素必須是有效URL

總結

客戶端驗證可以通過向用戶提供即時反饋并減少對服務器的請求數量來改善用戶體驗。但是,不應依賴它作為驗證輸入的唯一方法??蛻舳蓑炞C很容易被繞過或操縱,因此必須在服務器端驗證輸入,以確保安全性和數據完整性。

有效的驗證對于任何 Web 應用程序的穩(wěn)定性和安全性都是必不可少的。Spring Boot 提供了一套工具和庫來簡化驗證邏輯并使其更易于維護。通過遵循本文中討論的最佳實踐,您可以確保您的驗證組件有效并提供出色的用戶體驗。文章來源地址http://www.zghlxwxcb.cn/news/detail-415008.html

到了這里,關于【Spring Boot】SpringBoot參數驗證以及實現原理的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 【Spring】SpringBoot的10個參數驗證技巧

    【Spring】SpringBoot的10個參數驗證技巧

    參數驗證很重要,是平時開發(fā)環(huán)節(jié)中不可少的一部分,但是我想很多后端同事會偷懶,干脆不錯,這樣很可能給系統(tǒng)的穩(wěn)定性和安全性帶來嚴重的危害。那么在Spring Boot應用中如何做好參數校驗工作呢,本文提供了10個小技巧,你知道幾個呢? Spring Boot提供了內置的驗證注解,

    2024年02月10日
    瀏覽(20)
  • 從零開始學Spring Boot系列-前言

    在數字化和信息化的時代,Java作為一種成熟、穩(wěn)定且廣泛應用的編程語言,已經成為構建企業(yè)級應用的首選。而在Java生態(tài)系統(tǒng)中,Spring框架無疑是其中最為耀眼的一顆明星。它提供了全面的編程和配置模型,用于構建企業(yè)級應用。隨著Spring Boot的出現,這一框架變得更加易于

    2024年02月22日
    瀏覽(34)
  • Spring Boot中的SimpMessagingTemplate是什么,原理,以及如何使用

    Spring Boot中的SimpMessagingTemplate是什么,原理,以及如何使用

    SimpMessagingTemplate是Spring Framework中的一個類,用于向WebSocket客戶端發(fā)送消息。在Spring Boot應用程序中,可以使用SimpMessagingTemplate來實現WebSocket通信的消息發(fā)送功能。本文將介紹SimpMessagingTemplate的原理和使用方法。 SimpMessagingTemplate是Spring Framework中的一個類,用于向WebSocket客戶端

    2024年02月09日
    瀏覽(38)
  • Spring Boot中的@EnableWebSocketMessageBroker注解是什么,原理,以及如何使用

    Spring Boot中的@EnableWebSocketMessageBroker注解是什么,原理,以及如何使用

    WebSocket是一種在Web瀏覽器和Web服務器之間進行雙向通信的技術。在傳統(tǒng)的HTTP通信中,客戶端向服務器發(fā)送請求,服務器響應請求,然后關閉連接。而在WebSocket中,客戶端和服務器之間的連接始終保持打開狀態(tài),可以隨時互相發(fā)送消息,實現實時通信。 Spring Boot提供了對WebSo

    2024年02月12日
    瀏覽(28)
  • 【SpringBoot3】Spring Boot 3.0 介紹以及新特性

    【SpringBoot3】Spring Boot 3.0 介紹以及新特性

    Spring Boot 3.0 是 Spring Boot 框架的一個重要版本,它在保持了 Spring Boot 的一貫優(yōu)點的同時,也進行了一些重要的改進和更新。 首先,Spring Boot 3.0 對 Java 版本的要求進行了更新。這個版本要求使用 Java 17 作為最低版本,以利用最新的語言特性和性能改進。如果你正在使用的是

    2024年01月17日
    瀏覽(40)
  • Spring boot框架 JWT實現用戶賬戶密碼登錄驗證

    Spring boot框架 JWT實現用戶賬戶密碼登錄驗證

    目錄 1、JWT定義 1、1 JWT工作流程 1、2 JWT優(yōu)點 2、添加依賴項到pom.xml? 3、創(chuàng)建用戶實體類 ?4、實現認證服務 5、登錄請求處理 6、生成JWT JWT(JSON Web Token)是一種用于在網絡應用間傳遞信息的安全傳輸方式。它是一種緊湊且自包含的方式,通過使用數字簽名來驗證數據的完整性

    2024年02月07日
    瀏覽(21)
  • 讓你的Demo更安全--Spring Boot實現短信驗證碼

    隨著移動互聯(lián)網的普及,短信驗證碼已經成為了很多應用的常用登錄和注冊方式之一。在傳統(tǒng)的應用中,我們一般使用第三方集成商提供的短信驗證碼服務來實現短信驗證碼的發(fā)送和驗證,但是這些服務有可能存在時間限制、價格過高等限制。 為了解決這些問題,我們可以使

    2024年02月07日
    瀏覽(19)
  • SQL注入原理以及Spring Boot如何防止SQL注入(含詳細示例代碼)

    點擊下載《SQL注入原理以及Spring Boot如何防止SQL注入(含詳細示例代碼)》 SQL注入是一種針對數據庫的攻擊技術,攻擊者通過在應用程序的輸入字段中插入或“注入”惡意的SQL代碼,從而在數據庫服務器上執(zhí)行非授權的SQL查詢。這種攻擊可能導致數據泄露、數據篡改、甚至執(zhí)

    2024年02月20日
    瀏覽(30)
  • spring boot3登錄開發(fā)-2(2短信驗證碼接口實現)

    spring boot3登錄開發(fā)-2(2短信驗證碼接口實現)

    ? ??個人主頁:? ? ?蒾酒 ??系列專欄:《spring boot實戰(zhàn)》 ??山高路遠,行路漫漫,終有歸途 目錄 寫在前面 上文銜接 內容簡介 短信驗證碼接口實現 1.依賴導入 2.接口分析 3.實現思路 3.功能實現 創(chuàng)建發(fā)送短信工具類 配置阿里云短信服務 接口代碼實現 4.功能測試 寫在最后

    2024年03月23日
    瀏覽(21)
  • spring boot3登錄開發(fā)-2(1圖形驗證碼接口實現)

    spring boot3登錄開發(fā)-2(1圖形驗證碼接口實現)

    ??個人主頁:? ? ?蒾酒 ??系列專欄:《spring boot實戰(zhàn)》 ?? 山高路遠,行路漫漫,終有歸途。 目錄 前置條件 內容簡介 圖形驗證碼接口實現 導入糊涂工具依賴 接口分析 編寫驗證碼接口 測試驗證碼接口 本文銜接上文,請從上文開始 spring boot3x登錄開發(fā)-上(整合jwt)-CSDN博客

    2024年02月20日
    瀏覽(19)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包