Spring MVC Validation | اعتبارسنجی در Spring MVC
توضیحات جلسه
جزوه و مستندات
مفاهیم کلیدی
- Jakarta Validation API
مشخصه و استاندارد رسمی در اکوسیستم جاوا (شناختهشده با نام JSR 303) جهت اعتبارسنجی اعلانی دادهها روی فیلدهای مدل به کمک انوتیشنها، به جای پیادهسازی بلوکهای شرطی تکراری.
- Hibernate Validator
پیادهسازی مرجع استاندارد Jakarta Validation که علاوه بر قواعد پایه استاندارد، مجموعهای اختصاصی از قیود کاربردی نظیر فرمت کارتهای اعتباری، بارکدها و آدرسهای اینترنتی را فراهم میکند.
spring-boot-starter-validation
استارتر اختصاصی Spring Boot جهت اتصال موتور اعتبارسنجی؛ از نسخه 2.3 به بعد دیگر در استارتر وب گنجانده نشده و باید به طور مستقل به فایل مدیریت وابستگی پروژه افزوده شود.
@Null
بررسی میکند که مقدار عنصر حتماً برابر با null باشد.
@NotNull
تضمین میکند که مقدار ارجاع دادهشده برابر با null نباشد؛ با این حال رشته خالی یا کالکشن بدون عضو را معتبر در نظر میگیرد.
@NotEmpty
علاوه بر بررسی عدم برابری با null، تضمین میکند که اندازه آرایه، کالکشن، مپ یا طول رشته بزرگتر از صفر باشد.
@NotBlank
مختص متغیرهای متنی که تضمین میکند مقدار رشته نه null باشد و نه صرفاً از کاراکترهای فضای خالی تشکیل شده باشد (طول رشته پس از حذف فاصلهها باید بیشتر از صفر باشد).
@AssertTrue
بررسی میکند که فیلد منطقی از نوع boolean یا Boolean حتماً دارای مقدار true باشد.
@AssertFalse
بررسی میکند که فیلد منطقی از نوع boolean یا Boolean حتماً دارای مقدار false باشد.
@Min
تضمین میکند که مقدار عددی یا رشتهای قابل تبدیل به عدد، بزرگتر یا مساوی با حداقل مقدار تعیینشده باشد.
@Max
تضمین میکند که مقدار عددی یا رشتهای قابل تبدیل به عدد، کوچکتر یا مساوی با حداکثر مقدار تعیینشده باشد.
@DecimalMin
بررسی میکند که مقدار عددی، بزرگتر یا مساوی با مقدار تعیینشده به صورت رشتهای باشد؛ پارامتر inclusive امکان تعیین شمول یا عدم شمول مساوی را فراهم میکند.
@DecimalMax
بررسی میکند که مقدار عددی، کوچکتر یا مساوی با مقدار تعیینشده به صورت رشتهای باشد؛ پارامتر inclusive امکان تعیین شمول یا عدم شمول مساوی را فراهم میکند.
@Positive
بررسی میکند که مقدار عددی کاملاً مثبت و بزرگتر از صفر باشد.
@PositiveOrZero
بررسی میکند که مقدار عددی مثبت یا دقیقاً مساوی صفر باشد.
@Negative
بررسی میکند که مقدار عددی کاملاً منفی و کوچکتر از صفر باشد.
@NegativeOrZero
بررسی میکند که مقدار عددی منفی یا مساوی صفر باشد.
@Digits
بررسی میکند که ساختار عددی حداکثر دارای تعداد مشخصی از ارقام در بخش صحیح (integer) و بخش اعشار (fraction) باشد.
@Size
محدود کردن اندازه طول رشتهها، اعضای کالکشنها، مپها و آرایهها در بازه بسته حداقل (min) و حداکثر (max).
@Pattern
انطباق دقیق مقدار متنی با یک عبارت منظم (Regex) به همراه پرچمهای تطبیق اختیاری.
@Email
بررسی صحت ساختار آدرس ایمیل در توالی کاراکترها بر اساس استانداردهای متنی.
@Past
تضمین میکند که مقدار زمانی یا تقویمی حتماً تاریخی در گذشته باشد.
@PastOrPresent
بررسی میکند که مقدار زمانی مشخصشده در گذشته یا همزمان با لحظه جاری باشد.
@Future
تضمین میکند که مقدار زمانی یا تقویمی حتماً تاریخی در آینده باشد.
@FutureOrPresent
بررسی میکند که مقدار زمانی مشخصشده در آینده یا همزمان با لحظه جاری باشد.
@CreditCardNumber
انوتیشن اختصاصی Hibernate Validator جهت اعتبارسنجی صحت شماره کارت بانکی بر اساس الگوریتم چکسام فرمول Luhn برای ممانعت از خطاهای تایپی.
@Currency
بررسی تطابق واحد پولی یک شیء MonetaryAmount با لیست واحدهای ارزی مجاز تعریفشده.
@DurationMin
بررسی میکند که مقدار مدتزمان در ساختار Duration از حداقل زمان تعریفشده کمتر نباشد.
@DurationMax
بررسی میکند که مقدار مدتزمان در ساختار Duration از حداکثر زمان تعریفشده بیشتر نباشد.
@EAN
بررسی اعتبار توالی کاراکترها به عنوان یک بارکد استاندارد نظیر EAN-13.
@IpAddress
بررسی صحت ساختار آدرس شبکه و اطمینان از فرمت معتبر IPv4 یا IPv6.
@ISBN
بررسی صحت شناسه استاندارد بینالمللی کتاب با پشتیبانی از ساختارهای دهرقمی یا سیزدهرقمی.
@Length
انوتیشن اختصاصی Hibernate Validator برای بررسی طول رشته متنی در بازه مشخص حداقل و حداکثر.
@CodePointLength
بررسی طول رشته متنی بر اساس تعداد کاراکترهای یونیکد (Code Points) به همراه استراتژی نرمالسازی.
@LuhnCheck
اجرای مستقیم الگوریتم بررسی مجموع ارقام لوهن روی بخشی از رشته متنی با تعیین اندیسهای شروع، پایان و رقم کنترلی.
@Mod10Check
اجرای الگوریتم اعتبارسنجی رقم کنترلی بر پایه محاسبات باقیمانده تقسیم بر 10 با اعمال وزنها و ضرایب سفارشی.
@Mod11Check
اجرای الگوریتم اعتبارسنجی رقم کنترلی بر پایه محاسبات باقیمانده تقسیم بر 11 با امکان تعریف آستانه رشد ضرایب.
@Normalized
بررسی این موضوع که رشته متنی بر اساس یکی از فرمهای استاندارد یونیکد نرمالسازی شده باشد.
@Range
بررسی قرار داشتن یک مقدار عددی یا رشته متنی عددی در یک محدوده مشخص حداقل و حداکثر.
@ScriptAssert
انوتیشن اختصاصی در سطح کلاس (Class-Level) که با استفاده از موتورهای اسکریپتنویسی استاندارد جاوا (JSR 223) منطق اعتبارسنجی پیچیده میان چندین فیلد همزمان را بررسی میکند.
@UniqueElements
بررسی میکند که تمام عناصر موجود در یک کالکشن بر اساس متد equals() کاملاً یکتا و فاقد عضو تکراری باشند.
@URL
اعتبارسنجی آدرس اینترنتی بر پایه مشخصات استاندارد RFC 2396 با قابلیت کنترل پروتکل، میزبان و پورت.
@UUID
بررسی اعتبار قالب شناسه منحصربهفرد جهانی مطابق استاندارد RFC 4122 با تنظیمات اختصاصی نسخه و فرمت حروف.
@BitcoinAddress
بررسی صحت ساختار آدرس شبکه بیتکوین بر اساس انواع استانداردهای مجاز شبکه رمزارز.
@CNPJ
بررسی شماره ثبت شرکتها و اشخاص حقوقی کشور برزیل.
@CPF
بررسی کد ملی و شناسه مالیاتی اشخاص حقیقی کشور برزیل.
@TituloEleitoral
اعتبارسنجی شماره کارت رأیدهندگان کشور برزیل.
@NIP
اعتبارسنجی شماره شناسایی مالیات بر ارزش افزوده کشور لهستان.
@PESEL
بررسی شماره شناسایی ملی شهروندان کشور لهستان.
@REGON
اعتبارسنجی شناسه ملی ثبت تجاری اشخاص حقوقی در لهستان با پشتیبانی از ارقام 9 و 14 رقمی.
@INN
بررسی شماره شناسایی مالیاتدهندگان کشور روسیه برای اشخاص حقیقی و حقوقی.
@KorRRN
اعتبارسنجی شماره ثبت هویت مقیمین کشور کره جنوبی.
@Valid
انوتیشن استاندارد در امضای متدهای کنترلر جهت صدور فرمان اجرای فرایند ارزیابی قیود مدل، پس از اتصال دادهها و قبل از اجرای بدنه متد.
Errors
اینترفیس اختصاصی فریمورک اسپرینگ جهت جمعآوری، ردگیری و گزارش خطاهای ناشی از بایندینگ و اعتبارسنجی در کنترلر.
موارد مصاحبه ای
- تفاوت دقیق عملکردی میان سه انوتیشن
@NotNull،@NotEmptyو@NotBlankچیست؟
انوتیشن @NotNull صرفاً عدم اشاره به null را بررسی میکند و رشتههای خالی را معتبر میداند؛ @NotEmpty علاوه بر رد null، بررسی میکند طول رشته یا کالکشن بزرگتر از صفر باشد اما فضاهای خالی را میپذیرد؛ @NotBlank انحصاری رشتههاست و مقدار را trim کرده و وجود حداقل یک کاراکتر معتبر غیر از فاصله را الزامی میسازد.
- تغییر شیوه مدیریت وابستگی اعتبارسنجی از نسخه 2.3 فریمورک Spring Boot به بعد چه بود؟
تا قبل از نسخه 2.3، ابزار اعتبارسنجی به صورت درونساخت در پکیج spring-boot-starter-web وجود داشت؛ اما از نسخه 2.3 به بعد، ماژول اعتبارسنجی تفکیک شد و نیازمند افزودن مستقیم spring-boot-starter-validation به فایل تنظیمات بیلد است.
- محدودیت انوتیشنهای استاندارد Jakarta Validation در مقایسه با انوتیشنهای Hibernate Validator از نظر سطح تعریف چیست؟
تمامی قیود تعریفشده در استاندارد Jakarta Validation صرفاً در سطح فیلد یا متد اعمال میشوند؛ در حالی که Hibernate Validator انوتیشنهایی نظیر @ScriptAssert را برای اعمال اعتبارسنجیهای چندفیلدی در سطح کلاس فراهم کرده است.
- قانون الزامی در ترتیب قرارگیری پارامتر
Errorsدر کنترلرهای Spring MVC چیست؟
پارامتر Errors (یا همتای آن BindingResult) الزاماً باید بلافاصله پس از آرگومان مدل نشانهگذاریشده با @Valid در امضای متد قرار گیرد، در غیر این صورت فریمورک به جای بایند کردن خطاها، اکسپشن پرتاب میکند.
- آیا موفقیت در اعتبارسنجی
@CreditCardNumberبه معنای فعال بودن و قابلیت شارژ حساب کارت است؟
خیر؛ این انوتیشن فقط صحت الگوریتم ریاضی فرمول Luhn را برای ممانعت از خطاهای تایپی میسنجد و هیچ استعلامی از حساب بانکی، موجودی یا اتصال کارت به درگاه پرداخت به عمل نمیآورد.
- کدام انوتیشنهای اعتبارسنجی روی ساختار DDL و جدول دیتابیس در Hibernate تأثیرگذار هستند؟
انوتیشن @NotNull ستون را معادل not null قرار میدهد؛ انوتیشنهای @Size و @Length طول ستون را معادل مقدار ماکزیمم ست میکنند؛ انوتیشن @Digits برای تعیین دقت و مقیاس ستون عددی استفاده میشود و @Min و @Max قید check constraint به ساختار جدول دیتابیس اضافه میکنند.
سناریو کاربردی
- اعتبارسنجی اعلانی مدل داده و مدیریت پاسخ در متد کنترلر
در این سناریو، فیلدهای سفارش از جمله نام، ترکیبات، اطلاعات پرداخت و قالبهای متنی بر اساس قیود استاندارد اعتبارسنجی شده و در صورت نقض هر قید، کنترلر از ادامه پردازش ممانعت کرده و کاربر را با خطاهای مربوطه به فرم بازمیگرداند:
۱. تعریف قیود اعتبارسنجی روی کلاس مدل:
@Data
public class TacoOrder {
@NotBlank(message = "Delivery name is required")
private String deliveryName;
@NotBlank(message = "Street is required")
private String deliveryStreet;
@CreditCardNumber(message = "Not a valid credit card number")
private String ccNumber;
@Pattern(regexp = "^(0[1-9]|1[0-2])([\\/])([2-9][0-9])$", message = "Must be formatted MM/YY")
private String ccExpiration;
@Digits(integer = 3, fraction = 0, message = "Invalid CVV")
private String ccCVV;
@NotNull
@Size(min = 1, message = "You must choose at least 1 ingredient")
private List<Ingredient> ingredients = new ArrayList<>();
}
۲. بررسی خطاهای اعتبارسنجی در متد لایه کنترلر:
@Slf4j
@Controller
@RequestMapping("/orders")
public class OrderController {
@PostMapping
public String processOrder(@Valid TacoOrder order, Errors errors) {
if (errors.hasErrors()) {
log.warn("Validation failed for submitted order: {}", errors.getAllErrors());
return "orderForm";
}
log.info("Order processed successfully: {}", order);
return "redirect:/";
}
}
در صورتی که هر یک از قیود نقض شود، متد errors.hasErrors() مقدار true برمیگرداند و به جای پردازش منطق تجاری یا ذخیرهسازی، جریان کنترل دوباره به فایل نمای مربوطه ارجاع داده میشود تا پیامهای خطا بر اساس ویژگی message به کاربر نمایش داده شوند.
بیشتر بدانید
- ویژگیهای مشترک در تمام قیود اعتبارسنجی
مطابق مشخصه Jakarta Validation، هر انوتیشن اعتبارسنجی به طور پیشفرض دارای سه پارامتر اساسی شامل message (پیام نمایش دادهشده به کاربر هنگام نقض قید)، groups (دستهبندی و مرحلهبندی اعتبارسنجی) و payload (حمل دادههای فرادادهای اضافه به سمت سیستم پردازش خطا) است.
- مکانیزم الگوریتم لوهن در اعتبارسنجی دادهها
فرمول ریاضی لوهن بر پایه محاسبات مجموع ارقام با اعمال ضرایب متناوب کار میکند و یک ابزار اعتبارسنجی ارزانقیمت از نظر بار محاسباتی است که بدون نیاز به برقراری ارتباط شبکه، بخش عمدهای از اشتباهات سهوی کاربر را در ورود شماره کارت شناسایی میکند.
- پشتیبانی بومی از تایپهای زمانی جاوا 8
انوتیشنهای زمانی از جمله @Past و @Future کلاسهای قدیمی نظیر Date و همچنین کلاسهای مدرن بسته java.time مثل LocalDate، LocalDateTime، Instant و YearMonth را بدون نیاز به مبدل اضافی پشتیبانی میکنند.
