如何實現 Java SpringBoot 自動驗證入參數據的有效性

来源:https://www.cnblogs.com/vipsoft/archive/2023/04/13/17314686.html
-Advertisement-
Play Games

Java SpringBoot 通過javax.validation.constraints下的註解,實現入參數據自動驗證 如果碰到 `@NotEmpty` 否則不生效,註意看下 `@RequestBody` 前面是否加上了`@Valid` ...


Java SpringBoot 通過javax.validation.constraints下的註解,實現入參數據自動驗證
如果碰到 @NotEmpty 否則不生效,註意看下 @RequestBody 前面是否加上了@Valid

Validation常用註解彙總

Constraint 詳細信息
@Null 被註釋的元素必須為 null
@NotNull 被註釋的元素必須不為 null
@NotBlank 被註釋的元素不能為空(空格視為空)
@NotEmpty 被註釋的元素不能為空 (允許有空格)
@Size(max, min) 被註釋的元素的大小必須在指定的範圍內
@Min(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@Max(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@Pattern(value) 被註釋的元素必須符合指定的正則表達式
@DecimalMin(value) 被註釋的元素必須是一個數字,其值必須大於等於指定的最小值
@DecimalMax(value) 被註釋的元素必須是一個數字,其值必須小於等於指定的最大值
@AssertTrue 被註釋的元素必須為 true
@AssertFalse 被註釋的元素必須為 false
@Digits (integer, fraction) 被註釋的元素必須是一個數字,其值必須在可接受的範圍內
@Past 被註釋的元素必須是一個過去的日期
@Future 被註釋的元素必須是一個將來的日期

示例

 /**
   * 用戶名
   */
  @NotBlank(message = "用戶名不能為空")
  private String username;
  /**
   * 用戶真實姓名
   */
  @NotBlank(message = "用戶真實姓名不能為空")
  private String name;

  /**
   * 密碼
   */
  @Pattern(regexp = "^(?:(?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*[^A-Za-z0-9]))(?=^[^\\u4e00-\\u9fa5]{0,}$).{8,20}$", message = "密碼過於簡單有被盜風險,請保證密碼大於8位,並且由大小寫字母、數字,特殊符號組成")  
  private String password;

  /**
   * 郵箱
   */
  @NotBlank(message = "郵箱不能為空")
  @Email(message = "郵箱格式不正確")
  private String email;

  /**
   * 手機號
   */
  @NotBlank(message = "手機號不能為空")
  @Pattern(regexp = "^(1[0-9])\\d{9}$", message = "手機號格式不正確")
  private String mobile;

Demo

入參對象上,添加註解及說明

package com.vipsoft.web.entity;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.io.Serializable;

/**
 * 定時任務調度
 */
public class QuartzJob implements Serializable {

    private static final long serialVersionUID = 1L;

    /**
     * 任務序號
     */
    private long jobId;

    /**
     * 任務名稱
     */
    @NotBlank(message = "任務名稱不能為空")
    @Size(max = 10, message = "任務名稱不能超過10個字元")
    private String jobName;

    /**
     * 任務組名
     */
    @NotBlank(message = "任務組名不能為空")
    @Size(max = 10, message = "任務組名不能超過10個字元")
    private String jobGroup;

    /**
     * 調用目標字元串
     */
    private String invokeTarget;

    /**
     * 執行表達式
     */
    private String cronExpression;

    /**
     * cron計劃策略 0=預設,1=立即觸發執行,2=觸發一次執行,3=不觸發立即執行
     */
    private String misfirePolicy = "0";

    /**
     * 併發執行 0=允許,1=禁止
     */
    private String concurrent;

    /**
     * 任務狀態(0正常 1暫停)
     */
    private String status;

    /**
     * 備註
     */
    private String remark;
}

Controller @RequestBody 前面必須加上 @Valid 否則不生效

import javax.validation.Valid;

@RestController
@RequestMapping("schedule")
public class ScheduleController {

    private Logger logger = LoggerFactory.getLogger(ScheduleController.class);
  
    @RequestMapping("/add")
    public ApiResult addTask(@Valid @RequestBody QuartzJob param) throws Exception {
        logger.info("添加調度任務 => {} ", JSONUtil.toJsonStr(param));
        
        return new ApiResult("添加成功");
    }
}

異常處理,統一返回對象,方便前端解析
GlobalExceptionHandler

package com.vipsoft.web.exception;

import cn.hutool.core.util.StrUtil;
import com.vipsoft.web.utils.ApiResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

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

    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
 
    /**
     * 處理自定義異常
     */
    @ExceptionHandler(CustomException.class)
    public ApiResult handleException(CustomException e) {
        // 列印異常信息
        logger.error("### 異常信息:{} ###", e.getMessage());
        return new ApiResult(e.getCode(), e.getMessage());
    }

    /**
     * 參數錯誤異常
     */
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class})
    public ApiResult handleException(Exception e) {
        if (e instanceof MethodArgumentNotValidException) {
            MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e;
            BindingResult result = validException.getBindingResult();
            StringBuffer errorMsg = new StringBuffer();
            if (result.hasErrors()) {
                List<ObjectError> errors = result.getAllErrors();
                errors.forEach(p -> {
                    FieldError fieldError = (FieldError) p;
                    errorMsg.append(fieldError.getDefaultMessage()).append(",");
                    logger.error("### 請求參數錯誤:{" + fieldError.getObjectName() + "},field{" + fieldError.getField() + "},errorMessage{" + fieldError.getDefaultMessage() + "}");
                });
                return new ApiResult(6001, errorMsg.toString());
            }
        } else if (e instanceof BindException) {
            BindException bindException = (BindException) e;
            if (bindException.hasErrors()) {
                logger.error("### 請求參數錯誤: {}", bindException.getAllErrors());
            }
        }
        return new ApiResult(6001, "參數無效");
    }

    /**
     * 處理HttpRequestMethodNotSupporte異常
     * @param e
     * @return
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Object methodHandler(HttpRequestMethodNotSupportedException e) {
        // 列印異常信息
        logger.error("### 異常信息:{} ###", e.getMessage());
        return new ApiResult(6000, e.getMessage());
    }

    /**
     * 處理所有不可知的異常
     */
    @ExceptionHandler(Exception.class)
    public ApiResult handleOtherException(Exception e) {
        // 列印異常信息
        logger.error("### 系統內部錯誤:{} ###", e.getMessage(), e);
        String warnMsg = StrUtil.isEmpty(e.getMessage()) ? "### 系統內部錯誤 ###" : e.getMessage();
        return new ApiResult(6000, "系統內部錯誤", e.getMessage());
    }

}

統一返回對像 ApiResult

package com.vipsoft.web.utils;


//import com.github.pagehelper.PageInfo;

import java.io.Serializable;

public class ApiResult implements Serializable {

    /**
     * 返回編碼 0:失敗、1:成功
     */
    private int code;

    /**
     * 返回消息
     */
    private String message;

    /**
     * 返回對象
     */
    private Object data;

    /**
     * 分頁對象
     */
    private Page page;

    public ApiResult() {
        this.code = 1;
        this.message = "請求成功";
    }

    public ApiResult(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    public ApiResult(Integer code, String message, Object data) {
        this.code = code;
        this.message = message;
        this.setData(data);
    }

    public ApiResult(Object data) {
        this.code = 1;
        this.message = "請求成功";
        this.setData(data);
    }

//    public ApiResult(PageInfo pageInfo) {
//        this.code = 1;
//        this.message = "請求成功";
//        this.setData(pageInfo.getList());
//        this.setPage(convertToPage(pageInfo));
//    }
//
//    public Page convertToPage(PageInfo pageInfo) {
//        Page result = new Page();
//        result.setTotalCount(pageInfo.getTotal());
//        result.setPageNum(pageInfo.getPageNum());
//        result.setPageCount(pageInfo.getPages());
//        result.setPageSize(pageInfo.getPageSize());
//        result.setPrePage(pageInfo.getPrePage());
//        result.setNextPage(pageInfo.getNextPage());
//        return result;
//    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public Page getPage() {
        return page;
    }

    public void setPage(Page page) {
        this.page = page;
    }
}

運行結果如下
image


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 前言 做了個python的小項目,需要打包為桌面端的exe使用,結果一打包,體積直接上百兆了,研究了下,使用虛擬環境打出的包會更乾凈小巧。 安裝anaconda(用作python的虛擬環境管理工具) 安裝:https://repo.anaconda.com/archive/Anaconda3-202 ...
  • 判斷閏年 初始版本 year = input('請輸入一個年份:') while not year.isdigit(): year = input("抱歉,您的輸入有誤,請輸入一個整數:") year = int(year) if year % 400 == 0: print(year, "是閏年! ...
  • 在工作中,我們會將重要的文檔進行加密,並且設置用戶的訪問許可權,其他外部人員均無法打開,只有獲取該許可權的用戶才有資格打開文檔。此外,限制用戶的使用許可權,極大程度上阻止了那些有意要篡改、拷貝其中內容的人,提高文檔的安全性。與此同時,文檔加密的另一大作用是為了防止丟失,因為可能存在員工出差或離職時,將文檔 ...
  • 聲明 本文章中所有內容僅供學習交流使用,不用於其他任何目的,不提供完整代碼,抓包內容、敏感網址、數據介面等均已做脫敏處理,嚴禁用於商業用途和非法用途,否則由此產生的一切後果均與作者無關! 本文章未經許可禁止轉載,禁止任何修改後二次傳播,擅自使用本文講解的技術而導致的任何意外,作者均不負責,若有侵權, ...
  • Vue3的UI Framework中有Element-Plus、BalmUI、Quasar、PrimeVue、Ant Design Vue等UI Framework. Element-Plus是Element-UI的Vue3版,Element-UI的使用人數的基數較大,Github上的Star數也較 ...
  • 大數據時代,各行各業對數據採集的需求日益增多,網路爬蟲的運用也更為廣泛,越來越多的人開始學習網路爬蟲這項技術,K哥爬蟲此前已經推出不少爬蟲進階、逆向相關文章,為實現從易到難全方位覆蓋,特設【0基礎學爬蟲】專欄,幫助小白快速入門爬蟲,本期為數據存儲。 概述 上期我們介紹到了文件存儲,講到瞭如何將數據存 ...
  • 函數進階 函數的作用域 作用域又可以被稱為命名空間,指變數起作用的範圍。Python變數作用域可以分為四種,分別為局部作用域、嵌套作用域、全局作用域、內置作用域。 | 作用域 | 英文 | | | | | 局部作用域 | Local | | 嵌套作用域 | Enclosing | | 全局作用域 | ...
  • 一、事件背景: 某天凌晨,一陣急促的鈴聲將我從周公那裡拉了過來,接聽電話後,一臉懵逼。 什麼情況?XX後臺宕機了?當日日誌也不列印了,前端發起的請求,都報超時,重啟後又恢復了,不清楚會不會再次宕機。 出現這種情況,我第一時間想的是為什麼是00:00:00宕機?難道後臺嫌我這個大齡程式員睡得早了? 然 ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...