Spring in Action Chapter 2 | کتاب spring in action فصل دوم
📖توضیحات درس
📄جزوه
مفاهیم کلیدی
- Spring MVC
فریمورک وب در Spring برای مدیریت requestهای HTTP، آمادهسازی داده و ارسال آن به view جهت تولید response است. در applicationهای وب مبتنی بر browser، معمولاً controller داده را آماده میکند و view آن را به HTML تبدیل میکند.
- User Interface (UI)
بخش قابل مشاهده application برای کاربر است. در applicationهای Spring، اولین تجربه کاربر معمولاً از طریق UI وب در browser شکل میگیرد، بنابراین طراحی صحیح لایه وب اهمیت زیادی دارد.
- Controller
کلاسی در Spring MVC که مسئول دریافت و پردازش requestهای HTTP است. این کلاس یا داده را مستقیم در response مینویسد، یا آن را به view میفرستد تا HTML تولید شود.
- View
بخشی که دادههای آمادهشده توسط controller را render میکند و خروجی نهایی HTML را برای browser میسازد.
- Model
ساختاری برای انتقال داده از controller به view. دادههایی که در Model قرار میگیرند، در view قابل استفادهاند تا صفحه بر اساس آنها ساخته شود.
- Domain
مجموعه مفاهیم اصلی business application. در این سناریو، مفاهیمی مانند Ingredient، Taco، TacoOrder و Customer بخشی از domain هستند.
- Domain Class
کلاسی که یک مفهوم واقعی از domain را مدل میکند. مثلاً Ingredient شامل ویژگیهایی مثل id، name و type است تا مواد اولیه taco را نمایش دهد.
- Ingredient
یک domain object برای نمایش ماده اولیه taco. این شیء حداقل شامل شناسه، نام و نوع است تا هم قابل ارجاع باشد و هم بتوان آن را دستهبندی کرد.
- Request Mapping
مکانیزم نگاشت requestهای HTTP به methodهای controller. این نگاشت با annotationهایی مثل @RequestMapping، @GetMapping و @PostMapping انجام میشود.
@Controller
کلاس را به عنوان controller معرفی میکند و باعث میشود Spring آن را در component scanning پیدا کرده و به عنوان Bean ثبت کند.
@RequestMapping
برای تعریف مسیر کلی requestهایی که یک controller یا method مدیریت میکند استفاده میشود. وقتی در سطح class استفاده شود، مسیر پایه را مشخص میکند.
@GetMapping
برای مدیریت requestهای GET استفاده میشود. مثلاً اگر class روی /design map شده باشد، یک method با @GetMapping همان صفحه طراحی را نمایش میدهد.
@PostMapping
برای مدیریت requestهای POST استفاده میشود؛ یعنی زمانی که فرم توسط کاربر submit میشود و داده باید پردازش شود.
- Logical View Name
رشتهای که controller برمیگرداند تا Spring view متناظر را پیدا کند. مثلاً بازگرداندن "design" یعنی باید view مربوط به صفحه طراحی render شود.
- Form Binding
فرآیندی که در آن دادههای ارسالشده از فرم HTML به objectهای Java مانند Taco یا TacoOrder تبدیل و متصل میشوند.
@ModelAttribute
برای افزودن داده به Model قبل از اجرای handler method استفاده میشود. این annotation کمک میکند دادههای مشترک مثل لیست ingredientها یا objectهای اولیه فرم بهصورت خودکار در view در دسترس باشند.
- Session State
اطلاعاتی که بین چند request از یک کاربر حفظ میشود. وقتی فرایندی چندمرحلهای باشد، نگهداری state در session ضروری میشود.
@SessionAttributes
مشخص میکند برخی attributeهای model باید در session نگهداری شوند. این کار برای فرایندهایی مثل ساخت سفارش چندمرحلهای مفید است.
TacoOrderدر Session
چون طراحی taco فقط بخشی از فرایند کامل سفارش است، object مربوط به سفارش باید بین چند request حفظ شود تا اطلاعات مرحلهبهمرحله از بین نرود.
- Filtering Data for View
دادهها قبل از ارسال به view ممکن است بر اساس نیاز صفحه دستهبندی یا فیلتر شوند. در این سناریو، ingredientها بر اساس type گروهبندی میشوند تا نمایش فرم منظمتر و قابلفهمتر باشد.
- Validation
فرآیند بررسی صحت داده ورودی کاربر قبل از پردازش نهایی. هدف آن جلوگیری از ورود داده ناقص، نامعتبر یا ناسازگار با قوانین business است.
- JavaBean Validation API
استانداردی برای تعریف قوانین validation روی fieldهای object با annotation. این روش باعث میشود به جای if/elseهای پراکنده، قوانین بهصورت declarative روی model تعریف شوند.
spring-boot-starter-validation
dependency لازم برای فعالسازی validation در Spring Boot. از نسخههای جدید Spring Boot باید این starter را صریحاً به project اضافه کرد.
- Declarative Validation
روشی که در آن قوانین validation روی propertyهای class تعریف میشوند، نه داخل منطق controller. این رویکرد کد را خواناتر، نگهداریپذیرتر و قابلتستتر میکند.
@Valid
روی پارامتر method قرار میگیرد تا Spring بعد از form binding و قبل از اجرای logic، object را validate کند.
Errors
شیئی که نتیجه validation را نگه میدارد. اگر validation خطا داشته باشد، controller میتواند با hasErrors() تصمیم بگیرد داده پردازش نشود و فرم دوباره نمایش داده شود.
@NotNull
برای اطمینان از null نبودن مقدار field استفاده میشود.
@NotBlank
برای fieldهای متنی استفاده میشود تا مقدار هم null نباشد و هم خالی یا فقط whitespace نباشد.
@Size
برای کنترل حداقل یا حداکثر طول رشته یا تعداد عناصر collection استفاده میشود. مثلاً میتوان تعیین کرد نام taco حداقل چند کاراکتر باشد یا لیست ingredientها حداقل یک عضو داشته باشد.
@CreditCardNumber
اعتبار اولیه شماره کارت را بررسی میکند و مطمئن میشود فرمت آن با الگوریتم Luhn سازگار است. این annotation معتبر بودن ساختاری را چک میکند، نه واقعی بودن حساب بانکی.
- Luhn Algorithm
الگوریتمی برای بررسی ساختاری شماره کارت. این الگوریتم خطاهای رایج ورودی را تشخیص میدهد، اما تضمین نمیکند کارت واقعاً فعال یا قابلاستفاده باشد.
@Pattern
برای اعتبارسنجی مقدار بر اساس regular expression استفاده میشود. مثلاً برای فرمت MM/YY در تاریخ انقضای کارت مناسب است.
@Digits
برای اطمینان از تعداد مشخصی رقم عددی استفاده میشود. مثلاً CVV باید دقیقاً سه رقم باشد.
- Validation Error Messages
هر annotation validation میتواند message داشته باشد تا در صورت خطا، پیام واضحی به کاربر نمایش داده شود.
- Redisplay Form on Validation Failure
اگر validation شکست بخورد، controller به جای ادامه پردازش، همان view فرم را برمیگرداند تا کاربر خطاها را اصلاح کند.
- HTTP 500 Internal Server Error
اگر controller داده را به view بفرستد ولی view مربوطه تعریف نشده باشد، درخواست ممکن است با خطای 500 مواجه شود؛ چون Spring قادر به render کردن پاسخ نیست.
@Slf4j
annotation مربوط به Lombok که بهصورت خودکار یک logger از نوع SLF4J در class ایجاد میکند تا برای logging استفاده شود.
- SLF4J
یک facade برای logging در Java که abstraction مناسبی روی frameworkهای logging فراهم میکند.
- View Controller
برای مسیرهای سادهای که فقط باید یک view را بدون منطق خاص یا model data نمایش دهند، میتوان بهجای controller کامل از view controller استفاده کرد.
WebMvcConfigurerوaddViewController
امکان ثبت مسیرهای ساده GET را بدون نوشتن controller سفارشی فراهم میکند؛ زمانی مفید است که هیچ پردازش یا model خاصی لازم نباشد.
- Template Engine
ابزاری برای تولید HTML از روی template و داده model. Spring علاوه بر Thymeleaf از گزینههایی مثل FreeMarker، Groovy templates و Mustache هم پشتیبانی میکند.
موارد مصاحبه ای
- Spring MVC چه مسئلهای را حل میکند؟
لایه وب application را مدیریت میکند؛ یعنی request را دریافت میکند، داده را آماده میکند و response مناسب مثل HTML یا داده REST را برمیگرداند.
- تفاوت Controller و View چیست؟
Controller منطق دریافت و آمادهسازی داده را انجام میدهد، ولی View فقط داده را render میکند و خروجی نهایی را برای کاربر میسازد.
- نقش Model در Spring MVC چیست؟
داده را از controller به view منتقل میکند تا view بتواند بر اساس آن صفحه را تولید کند.
@Controllerچه کاری انجام میدهد؟
کلاس را به عنوان web controller معرفی میکند و آن را برای component scanning و ثبت بهعنوان bean آماده میسازد.
- تفاوت
@RequestMappingو@GetMappingچیست؟
@RequestMapping annotation عمومی برای mapping requestها است، اما @GetMapping نسخه تخصصی برای requestهای GET است و خوانایی بیشتری دارد.
- خانواده annotationهای mapping در Spring MVC چه هستند؟
@RequestMapping، @GetMapping، @PostMapping، @PutMapping، @DeleteMapping و @PatchMapping.
- وقتی controller رشته
"design"را برمیگرداند چه اتفاقی میافتد؟
Spring آن را به عنوان logical view name تفسیر میکند و view متناظر را برای render کردن model پیدا میکند.
@ModelAttributeچه مزیتی دارد؟
امکان میدهد قبل از اجرای handler، دادههای موردنیاز فرم یا view مثل objectهای خالی یا لیستهای انتخابی بهطور خودکار در model قرار گیرند.
- چرا از
@SessionAttributesاستفاده میشود؟
برای حفظ state بین چند request در فرایندهای چندمرحلهای، مثل زمانی که کاربر چند taco را در قالب یک سفارش میسازد.
- چرا validation را با annotation انجام میدهیم و نه با if/else در controller؟
چون validation declarative کد را تمیزتر، قابلنگهداریتر و قابلاستفاده مجدد میکند و منطق controller را ساده نگه میدارد.
@Validدقیقاً چه زمانی اعمال میشود؟
بعد از bind شدن داده فرم به object و قبل از اجرای method controller.
- نقش
Errorsدر validation چیست؟
نتیجه validation را نگه میدارد تا controller بتواند تشخیص دهد آیا باید داده پردازش شود یا فرم دوباره نمایش داده شود.
- تفاوت
@NotNullو@NotBlankچیست؟
@NotNull فقط null نبودن را بررسی میکند، اما @NotBlank برای رشتهها علاوه بر null نبودن، خالی نبودن و whitespace-only نبودن را هم چک میکند.
@Sizeدر چه مواردی استفاده میشود؟
برای محدود کردن طول رشته یا تعداد عناصر collection؛ مثلاً حداقل طول نام یا حداقل یک ingredient انتخابشده.
@CreditCardNumberچه چیزی را تضمین میکند؟
فقط معتبر بودن ساختاری شماره کارت بر اساس الگوریتم Luhn را بررسی میکند، نه فعال بودن یا قابلشارژ بودن کارت.
- برای اعتبارسنجی فرمت
MM/YYاز چه چیزی استفاده میشود؟
از @Pattern همراه با regular expression.
- اگر validation شکست بخورد، رفتار درست controller چیست؟
باید پردازش را متوقف کند و همان view فرم را برگرداند تا کاربر خطاها را اصلاح کند.
- اگر view تعریف نشده باشد چه خطایی محتمل است؟
در زمان render درخواست ممکن است HTTP 500 Internal Server Error رخ دهد.
- چه زمانی بهجای controller کامل از view controller استفاده میشود؟
وقتی فقط نمایش یک view ساده لازم است و نه model data و نه پردازش خاصی موردنیاز است.
- چرا
Ingredientبهid،nameوtypeنیاز دارد؟
id برای ارجاع یکتا، name برای نمایش به کاربر، و type برای دستهبندی و نمایش ساختیافته در فرم.
سناریو کاربردی
- صفحه طراحی taco با Spring MVC
در این سناریو یک صفحه وب برای ساخت taco سفارشی ایجاد میشود:
-
یک
domain classبه نامIngredientتعریف میشود تا مواد اولیه را با ویژگیهایی مثلid،nameوtypeمدل کند. -
یک controller برای مسیر
/designساخته میشود. -
این controller درخواست
GETرا دریافت میکند و داده لازم برای فرم را آماده میسازد. -
لیست ingredientها در controller تولید و بر اساس
typeدستهبندی میشود. -
با استفاده از
@ModelAttribute، این دادهها بهModelاضافه میشوند تا view بتواند آنها را نمایش دهد. -
همزمان یک object خالی از
Tacoبرای bind شدن فرم و یکTacoOrderبرای نگهداری وضعیت سفارش در session ساخته میشود. -
متد نمایش فرم، نام view مانند
designرا برمیگرداند تا صفحه HTML مربوطه render شود. -
منطق مرحلهبهمرحله validation فرم
برای جلوگیری از داده نامعتبر:
- روی classهای
TacoوTacoOrderannotationهای validation تعریف میشوند. - برای
Tacoبررسی میشود که نام خالی نباشد و حداقل یک ingredient انتخاب شده باشد. - برای
TacoOrderفیلدهای آدرس نباید خالی باشند. - شماره کارت با
@CreditCardNumber، تاریخ انقضا با@PatternوCVVبا@Digitsبررسی میشوند. - در متدهای
POST، پارامتر ورودی با@Validمشخص میشود. - اگر
Errors.hasErrors()مقدار true بدهد، controller فرم را دوباره نمایش میدهد. - اگر خطایی وجود نداشته باشد، داده پردازش میشود و فرایند سفارش ادامه پیدا میکند.
این سناریو بهخوبی نشان میدهد که در Spring MVC، لایه وب معمولاً با این جریان کار میکند:
- دریافت request
- آمادهسازی model
- نمایش فرم
- bind کردن داده فرم به object
- validation
- ادامه پردازش یا بازگشت به فرم در صورت خطا
بیشتر بدانید
- نکته معماری
در این فصل controller فعلاً خودش لیست ingredientها را میسازد، اما در معماری درستتر این داده باید از repository یا database دریافت شود تا controller فقط نقش هماهنگکننده داشته باشد.
- نکته طراحی domain
قبل از نوشتن controller و view، بهتر است domain model مشخص شود؛ چون ساختار objectها پایه طراحی form، validation و data flow را تعیین میکند.
- نکته درباره
@ModelAttribute
این annotation برای دادههایی که در چند request handler یا چند render مختلف موردنیازند بسیار مفید است و از تکرار کد جلوگیری میکند.
- نکته درباره session
نگهداری objectهای چندمرحلهای در session باید کنترلشده باشد؛ چون stateful شدن بیش از حد میتواند مدیریت memory و مقیاسپذیری را سختتر کند.
- نکته validation
قرار دادن قوانین validation روی model باعث میشود همان قوانین در چند controller یا حتی چند نوع ورودی قابلاستفاده باشند.
- نکته تجربه کاربری
صرف validation کافی نیست؛ باید خطاها در خود فرم به کاربر نمایش داده شوند تا کاربر دقیقاً بداند چه چیزی را باید اصلاح کند.
- نکته نسخه Spring Boot
در نسخههای جدید Spring Boot، validation دیگر همیشه بهصورت implicit همراه web starter اضافه نمیشود؛ بنابراین باید spring-boot-starter-validation را صریحاً اضافه کنید.
- نکته logging
استفاده از @Slf4j با Lombok باعث کاهش boilerplate در تعریف logger میشود و برای tracing و debug در controllerها مفید است.
- نکته viewهای ساده
اگر صفحهای فقط باید نمایش داده شود و هیچ model یا logic خاصی ندارد، استفاده از addViewController در WebMvcConfigurer سبکتر از نوشتن controller کامل است.
- نکته انتخاب view technology
هرچند Thymeleaf گزینه رایج در Spring Boot است، اما Spring به template engineهای دیگری هم متصل میشود؛ انتخاب آن باید بر اساس نیاز پروژه، سادگی template و تجربه تیم انجام شود.
