16. مقدمهای بر Spring MVC
16.1. نقش Spring MVC در یک برنامه وب
بیایید نقش Spring MVC را در توسعهٔ برنامههای وب در نظر بگیریم. اغلب، چنین برنامهای بر روی یک معماری چندلایه مانند زیر ساخته میشود:
![]() |
- لایه [Web] لایهای است که با کاربر وباپلیکیشن تعامل میکند. کاربر از طریق صفحات وبی که در یک مرورگر نمایش داده میشوند، با وباپلیکیشن تعامل دارد. Spring MVC در این لایه قرار دارد، و تنها در این لایه؛
- لایه [métier] قواعد کسبوکار برنامه را پیادهسازی میکند، مانند محاسبه حقوق یا فاکتور. این لایه دادهها را از کاربر از طریق لایه [Web] و از SGBD از طریق لایه [DAO] استفاده میکند؛
- لایه [DAO] (ابجکتهای دسترسی به داده)، لایه [ORM] (نقشهبردار شیء–رابطهای) و درایور JDBC دسترسی به دادهها در SGBD را مدیریت میکنند. لایه [ORM] بهعنوان پلی میان اشیایی که توسط لایه [DAO] مدیریت میشوند و سطر و ستونهای جداول در یک پایگاه داده رابطهای عمل میکند. یک مشخصه که با نام JPA (Java Persistence API) شناخته میشود، امکان انتزاع از ORM در حال استفاده را فراهم میکند، به شرطی که آن را پیادهسازی کند. در این آموزش چنین خواهد بود، بنابراین از این پس ما به لایه ORM به عنوان لایه JPA اشاره خواهیم کرد؛
- ادغام لایهها توسط فریمورک Spring انجام میشود؛
16.2. مدل توسعه Spring MVC
اسپرینگ MVC الگوی معماری موسوم به MVC (مدل–نما–کنترلکننده) را به شرح زیر پیادهسازی میکند:
![]() |
پردازش یک درخواست مشتری به شرح زیر انجام میشود:
- درخواست – URLهای درخواستی به شکل http://machine:port/contexte/Action/param1/param2/....?p1=v1&p2=v2&... هستند. [Front Controller] از یک فایل پیکربندی یا anotationهای جاوا برای «مسیردهی» درخواست به کنترلکننده صحیح و اکشن صحیح در آن کنترلکننده استفاده میکند. برای این کار، از فیلد [Action] در URL استفاده میکند. باقیمانده URL و [/param1/param2/...] شامل پارامترهای اختیاری است که به اکشن ارسال خواهند شد. «C» در MVC در این مورد، رشته [Front Controller, Contrôleur, Action] است. اگر هیچ کنترلری نتواند اقدام درخواستی را مدیریت کند، وبسرور پاسخ خواهد داد که URL درخواستی یافت نشد.
- پردازش
- (ادامه)
- عمل انتخابشده میتواند از پارامترهای parami که توسط [Front Controller] به آن ارسال شدهاند، استفاده کند. این پارامترها ممکن است از چندین منبع بیایند:
- مسیر [/param1/param2/...] از URL،
- پارامترهای [p1=v1&p2=v2] از URL,
- پارامترهای ارسالشده توسط مرورگر در درخواست آن؛
- هنگام پردازش درخواست کاربر، ممکن است اقدام به لایههای [métier] و [2b] نیاز داشته باشد. پس از پردازش درخواست مشتری، ممکن است پاسخهای مختلفی ایجاد شود. یک مثال کلاسیک این است:
- یک صفحهٔ خطا اگر درخواست نتوانست به درستی پردازش شود
- در غیر این صورت، یک صفحه تأیید
- اقدام دستور نمایش یک نمای مشخص را صادر میکند [3]. این نما دادههایی را که به عنوان مدل نما شناخته میشوند، نمایش میدهد. این همان M در MVC است. اقدام این مدل M [2c] را ایجاد کرده و دستور نمایش یک نما V [3] را صادر میکند؛
- پاسخ – نمای انتخابشده V از مدل M ساختهشده توسط اقدام برای inicialise کردن بخشهای پویا از پاسخی که باید به کلاینت ارسال کند، استفاده میکند و سپس این پاسخ را ارسال میکند.
برای یک سرویس وب / jSON، معماری قبلی کمی تغییر میکند:
![]() |
- در [4a]، قالب—که یک کلاس جاوا است—توسط یک کتابخانه jSON به یک رشته jSON تبدیل میشود؛
- در [4b]، این رشته jSON به مرورگر ارسال میشود؛
اکنون بیایید ارتباط بین معماری وب MVC و معماری لایهلایه را روشن کنیم. بسته به نحوه تعریف مدل، این دو مفهوم ممکن است مرتبط باشند یا نباشند. بیایید یک برنامه وب تکلایه Spring MVC را در نظر بگیریم:
![]() |
اگر لایه [Web] را با استفاده از Spring MVC پیادهسازی کنیم، در واقع یک معماری وب MVC خواهیم داشت اما یک معماری چندلایه نخواهیم داشت. در اینجا لایه [web] همه چیز را مدیریت خواهد کرد: ارائه، منطق کسبوکار و دسترسی به دادهها. این اکشنها هستند که این کار را انجام میدهند.
اکنون، بیایید یک معماری وب چندلایه را در نظر بگیریم:
![]() |
لایه [Web] را میتوان بدون فریمورک و بدون پیروی از مدل MVC پیادهسازی کرد. بنابراین ما در واقع یک معماری چندلایه داریم، اما لایه وب مدل MVC را پیادهسازی نمیکند.
برای مثال، در محیط .NET، لایه [Web]میتواند با استفاده از ASP.NET و MVC پیادهسازی شود که منجر به یک معماری لایهای با یک لایه [Web] از نوع MVC میشود. پس از انجام این کار، این لایه ASP.NET MVC میتواند با یک لایه استاندارد ASP.NET (WebForms) جایگزین شود در حالی که بقیه حفظ میشوند (لایه کسبوکار، DAO، ORM) دقیقاً همانطور که هست. سپس ما یک معماری لایهای داریم که شامل یک لایه [Web] است که دیگر از نوع MVC نیست.
در MVC بیان کردیم که مدل M همان نما V است، c.a.d – مجموعهای از دادههایی که توسط نما V نمایش داده میشوند. تعریف دیگری از مدل M برای MVC ارائه شده است:
![]() |
بسیاری از نویسندگان معتقدند آنچه در سمت راست لایه [Web] قرار دارد، مدل M از MVC را تشکیل میدهد. برای جلوگیری از ابهام، میتوان به موارد زیر اشاره کرد:
- مدل دامنه وقتی به کل بخش سمت راست لایه [Web] اشاره میشود
- مدل نماهنگامی که به دادههای نمایشدادهشده توسط یک نما V اشاره میشود
از این پس، اصطلاح «مدل M» منحصراً به مدل یک نما V اشاره خواهد داشت.
16.3. یک پروژه وب / jSON با استفاده از Spring MVC
وبسایت [http://spring.io/guides] آموزشهای شروع کار را برای کمک به شما در کاوش اکوسیستم Spring ارائه میدهد. ما یکی از این آموزشها را دنبال خواهیم کرد تا درباره پیکربندی Maven مورد نیاز برای یک پروژه Spring MVC بیاموزیم.
16.3.1. پروژهٔ نمایشی
![]() |
- در [1]، ما یکی از راهنماهای Spring را وارد میکنیم؛
![]() |
- در [2]، مثال [Rest Service] را انتخاب میکنیم؛
- در [3]، پروژه Maven را انتخاب میکنیم؛
- در [4]، نسخه نهایی راهنما را انتخاب میکنیم؛
- در [5]، تأیید میکنیم؛
- در [6]، پروژه واردشده؛
خدمات وب که از طریق استاندارد URL قابل دسترسی هستند و متن jSON را بازمیگردانند، اغلب به عنوان خدمات REST (انتقال وضعیت REpresentational) شناخته میشوند. یک سرویس زمانی RESTful نامیده میشود که از قوانین خاصی پیروی کند.
حال بیایید پروژهٔ واردشده را بررسی کنیم، با پیکربندی Maven آن شروع میکنیم.
16.3.2. پیکربندی Maven
فایل [pom.xml] به شرح زیر است:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.2.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<properties>
<start-class>hello.Application</start-class>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</pluginRepository>
</pluginRepositories>
</project>
- خطوط ۶–۸: ویژگیهای پروژه Maven. یک تگ [<packaging>] که نوع فایلی را که توسط ساخت Maven تولید میشود مشخص میکند، وجود ندارد. در غیاب آن، نوع [jar] استفاده میشود. بنابراین، این برنامه یک برنامهٔ قابل اجرای کنسولی است و نه یک برنامهٔ وب، که در این صورت بستهبندی آن [war] خواهد بود؛
- خطوط ۱۰–۱۴: پروژه Maven یک پروژه والد به نام [spring-boot-starter-parent] دارد. این پروژه بیشتر وابستگیهای پروژه را تعریف میکند. این وابستگیها ممکن است کافی باشند، که در این صورت هیچ وابستگی دیگری اضافه نمیشود، یا ممکن است کافی نباشند، که در این صورت وابستگیهای missing اضافه میشوند؛
- خطوط 17–20: آرتیفکت [spring-boot-starter-web] شامل کتابخانههای مورد نیاز برای یک پروژه Spring (MVC) از نوع سرویس وب است، که در آن هیچ ویوی (view) تولید نمیشود. این آرتیفکت شامل تعداد بسیار زیادی کتابخانه، از جمله کتابخانههای مربوط به یک سرور Tomcat تعبیهشده است. این اپلیکیشن بر روی همین سرور اجرا خواهد شد؛
کتابخانههای گنجاندهشده در این پیکربندی بسیار زیاد هستند:
![]() | ![]() |
در بالا سه آرشیو مربوط به سرور Tomcat آمده است.
16.3.3. معماری یک سرویس Spring [web / jSON]
برای یک سرویس وب / jSON، Spring MVC مدل MVC را به شرح زیر پیادهسازی میکند:
![]() |
- در [4a]، مدل — که یک کلاس جاوا است — توسط کتابخانه jSON به رشته jSON تبدیل میشود؛
- در [4b]، این رشته jSON به مرورگر ارسال میشود؛
16.3.4. C
![]() |
برنامه واردشده دارای کنترلر زیر است:
package hello;
import java.util.concurrent.atomic.AtomicLong;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class GreetingController {
private static final String template = "Hello, %s!";
private final AtomicLong counter = new AtomicLong();
@RequestMapping("/greeting")
public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {
return new Greeting(counter.incrementAndGet(), String.format(template, name));
}
}
- خط ۹: تگ [@RestController] کلاس [GreetingController] را بهعنوان یک کنترلر Spring مشخص میکند، یعنی متدهای آن برای رسیدگی به URL ثبت شدهاند. ما anotation مشابه [@Controller] را دیدهایم. نوع بازگشتی متدهای این کنترلر [String] بود که نام view قابل نمایش بود. در اینجا، متفاوت است. متدهای یک کنترلکننده از نوع [@RestController] اشیایی را بازمیگردانند که برای ارسال به مرورگر سریال میشوند. نوع سریالسازی انجامشده به پیکربندی Spring با شناسه MVC بستگی دارد. در اینجا، آنها به صورت jSON سریالیزه خواهند شد. وجود کتابخانه jSON در میان وابستگیهای پروژه باعث میشود که Spring Boot به طور خودکار پروژه را به این شکل پیکربندی کند؛
- خط 14: آناوتیشن [@RequestMapping]، URL را که متد آن را پردازش میکند مشخص مینماید، در این مورد URL [/greeting]؛
- خط ۱۵: ما قبلاً تگ [@RequestParam] را توضیح دادهایم. نتیجه بازگردانده شده توسط متد یک شیء از نوع [Greeting] است.
- خط ۱۲: یک عدد صحیح بلند از نوع اتمی. این بدان معناست که از دسترسی همزمان پشتیبانی میکند. چندین نخ ممکن است بخواهند همزمان مقدار متغیر [counter] را افزایش دهند. این موضوع به درستی مدیریت خواهد شد. یک نخ تنها پس از آنکه نخ در حال تغییر آن، عملیات خود را تکمیل کرد، میتواند مقدار شمارنده را بخواند.
16.3.5. مدل M
مدل M تولید شده توسط روش قبلی، شیء زیر [Greeting] است:
![]() |
package hello;
public class Greeting {
private final long id;
private final String content;
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
public long getId() {
return id;
}
public String getContent() {
return content;
}
}
تبدیل jSON این شیء، رشتهٔ کاراکتری {"id":n,"content":"text"} را ایجاد خواهد کرد. در نهایت، رشتهای که توسط متد کنترلکننده تولید میشود، jSON، به شکل زیر خواهد بود:
یا
16.3.6. اجرا
![]() |
کلاس [Application.java] کلاس اجرایی پروژه است. کد آن به شرح زیر است:
package hello;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan
@EnableAutoConfiguration
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
ما قبلاً این کد را در مثال قبلی دیدهایم و توضیح دادهایم. بیایید پروژه را اجرا کنیم:
![]() |
خروجیهای کنسول زیر تولید میشوند:
- خط ۱۳: سرور Tomcat روی پورت ۸۰۸۰ شروع به کار میکند (خط ۱۲);
- خط ۱۷: سرولت [DispatcherServlet] موجود است؛
- خط ۲۰: متد [GreetingController.greeting] کشف شده است؛
برای آزمایش برنامه وب، ما URL و [http://localhost:8080/greeting] را درخواست میکنیم:
![]() | ![]() |
ما در واقع رشتهٔ مورد انتظار jSON را دریافت میکنیم. شاید ارزش داشته باشد نگاهی به سربرگهای HTTP ارسالشده توسط سرور بیندازیم. برای انجام این کار، از افزونهٔ کروم به نام [Advanced Rest Client] استفاده خواهیم کرد (Chrome / Ctrl-T / منوی [Applications] / [Advanced Rest Client] – رجوع شود به پیوستها، بند 23.11):
![]() |
- در [1]، URL درخواستشده؛
- در [2]، از روش GET استفاده میشود؛
- در [3]، پاسخ jSON است؛
- در [4]، سرور اعلام کرد که در حال ارسال پاسخی با فرمت jSON است؛
- در [5]، همان URL درخواست میشود، اما این بار با POST؛
- در [7]، اطلاعات به شکل [urlencoded] به سرور ارسال میشود؛
- در [6]، پارامتر 'name' به همراه مقدار آن؛
- در [8]، مرورگر به سرور اطلاع میدهد که در حال ارسال اطلاعات [urlencoded] برای آن است؛
- در [9]، پاسخ سرور jSON;
16.3.7. ایجاد یک آرشیو اجرایی
اکنون یک آرشیو قابل اجرا ایجاد خواهیم کرد:
![]() |
![]() |
- در [1]: ما یک هدف Maven را اجرا میکنیم؛
- در [2]: دو هدف وجود دارد: [clean] برای حذف پوشه [target] از پروژه Maven، و [package] برای بازتولید آن؛
- در [3]: پوشهٔ تولیدشدهٔ [target] در این پوشه ایجاد خواهد شد؛
- در [4]: هدف تولید میشود؛
در لاگهای نمایشدادهشده در کنسول، مهم است که پلاگین [spring-boot-maven-plugin] را ببینید. این پلاگین است که آرشیو قابل اجرا را تولید میکند (به [pom.xml] در زیر مراجعه کنید):
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
با استفاده از یک پنجرهٔ فرمان، به پوشهٔ تولیدشده بروید:
D:\Temp\wksSTS\gs-rest-service\target>dir
...
11/06/2014 15:30 <DIR> classes
11/06/2014 15:30 <DIR> generated-sources
11/06/2014 15:30 11 073 572 gs-rest-service-0.1.0.jar
11/06/2014 15:30 3 690 gs-rest-service-0.1.0.jar.original
11/06/2014 15:30 <DIR> maven-archiver
11/06/2014 15:30 <DIR> maven-status
...
- خط ۵: آرشیو تولید شده؛
این آرشیو به صورت زیر اجرا میشود:
D:\Temp\wksSTS\gs-rest-service-complete\target>java -jar gs-rest-service-0.1.0.jar
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.1.0.RELEASE)
2014-06-11 15:32:47.088 INFO 4972 --- [ main] hello.Application
: Starting Application on Gportpers3 with PID 4972 (D:\Temp\wk
sSTS\gs-rest-service-complete\target\gs-rest-service-0.1.0.jar started by ST in
D:\Temp\wksSTS\gs-rest-service-complete\target)
...
اکنون که برنامه وب راهاندازی شده است، میتوانید با استفاده از یک مرورگر به آن دسترسی پیدا کنید:
![]() |
16.3.8. راهاندازی برنامه روی سرور Tomcat
همانند پروژه قبلی، فایل [pom.xml] را به شرح زیر اصلاح میکنیم:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework</groupId>
<artifactId>gs-rest-service</artifactId>
<version>0.1.0</version>
<packaging>war</packaging>
...
</project>
- خط ۹: باید مشخص کنیم که قصد داریم یک آرشیو WAR (وب ARchive) ایجاد کنیم؛
برنامهٔ وب نیز باید پیکربندی شود. در صورت عدم وجود فایل [web.xml]، این کار با استفاده از کلاسی که از [SpringBootServletInitializer] ارث میبرد، انجام میشود:
![]() |
کلاس [ApplicationInitializer] به شرح زیر است:
package hello;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
public class ApplicationInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(Application.class);
}
}
- خط ۶: کلاس [ApplicationInitializer] از کلاس [SpringBootServletInitializer] ارث میبرد؛
- خط ۹: متد [configure] (خط ۸) مجدداً تعریف شده است؛
- خط ۱۰: کلاسی که پروژه را پیکربندی میکند مشخص شده است؛
برای اجرای پروژه، مراحل زیر را دنبال کنید:
![]() |
- در [1-2]، پروژه را روی یکی از سرورهای ثبتشده در Eclipse IDE اجرا کنید؛
پس از انجام این کار، میتوانید URL [http://localhost:8080/gs-rest-service/greeting/?name=Mitchell] را در یک مرورگر درخواست کنید:
![]() |
16.4. Conclusion
ما نوعی پروژه Spring به نام MVC معرفی کردهایم که در آن برنامه وب یک جریان (stream) به نام jSON را به مرورگر ارسال میکند. اکنون یک برنامه وب / jSON توسعه خواهیم داد تا پایگاه داده [dbproduitscategories] را که در فصلهای قبلی مطالعه کردیم، در وب منتشر کنیم.























