محتوا:
معرفی
من با مطالعه نمونههای مختلفی که در آنها استفاده شدهاند، با فنآوریها و چارچوبهایی آشنا شدم که برایم جدید بودند، زیرا معمولاً وقتی چیزی را در عمل با استفاده از نمونهای از یک برنامه کاربردی کامل میبینم، بهتر میفهمم. به طور معمول، چنین نمونه هایی برنامه های CRUD ( C reate، Read ، U pdate، D elete) هستند ، اینترنت پر از چنین نمونه هایی با درجات مختلف پیچیدگی است. مشکل این است که آنها معمولاً توضیح نمی دهند که چگونه، چه چیزی و چرا در آنجا انجام شده است، چرا فلان وابستگی اضافه شده است، چرا فلان کلاس مورد نیاز است و غیره. در بیشتر موارد، آنها یک برنامه کاملاً تمام شده، با یک فایل POM نهایی، با نسخههای نهایی کلاسها را میگیرند و به سادگی هر کدام را بدون تمرکز روی چیزهای کوچکی که احتمالاً برای یک فرد با تجربه بدیهی به نظر میرسند، اجرا میکنند. من به نمونههای زیادی از این دست نگاه کردهام و معمولاً روشن است که همه چیز چگونه کار میکند، اما اینکه چگونه به این موضوع رسیدهاند کاملاً مشخص نیست. بنابراین، تصمیم گرفتم که چنین مثالی مفید باشد، نه از موضع یک توسعه دهنده با تجربه، بلکه از موقعیت یک مبتدی که هرگز با Spring، Hibernate و موارد دیگر سروکار نداشته است.ایجاد یک پروژه
بنابراین، از آنجایی که من تازه کار هستم، از هیچ کهن الگوی مبهمی استفاده نخواهیم کرد. Spring fillestar هنوز هم خیلی ترسناک به نظر می رسد. بنابراین، ما معمولی ترین پروژه Maven ساده را ایجاد خواهیم کرد. من نام دامنه ندارم، بنابراین در groupid فقط می نویسمtestgroup
، و برای مثال در artifactid نام را می نویسم filmography
(این لیستی از فیلم ها خواهد بود). ما یک پروژه ایجاد می کنیم و Enable auto-import
زمانی که ایده آن را پیشنهاد می کند، انتخاب می کنیم. به لطف این، هر بار که ما هر تغییری در فایل POM ایجاد می کنیم (مدل شیء پروژه، این فایل کل ساختار پروژه Maven را توصیف می کند)، همه چیز بلافاصله به طور خودکار در پروژه اعمال می شود. کتابخانهها از مخزن محلی ما گرفته میشوند، اگر قبلاً آنها را داشته باشیم، یا اگر از وابستگیهای جدیدی استفاده کنیم که قبلاً با آنها سروکار نداشتهایم، Maven آنها را به سادگی از طریق اینترنت از مخزن مرکزی دانلود میکند. Maven همچنین عملکردی برای بارگیری منابع و اسناد (دانلود منابع و/یا مستندات) دارد. همچنین بسیار راحت است، اگر چیزی با کلاس یا روش مشخص نیست، می توانید به کد منبع بروید و ببینید که چگونه همه چیز در داخل کار می کند. بیایید یکی دو جزئیات اضافه کنیم. این یک برنامه وب خواهد بود و ما از Tomcat استفاده خواهیم کرد . برای استقرار یک برنامه در تامکت، باید آن را در قالب یک آرشیو جنگ به آنجا منتقل کنید (منبع برنامه وب، فرمت ویژه برنامه های کاربردی وب). برای انجام این کار، خط زیر را به فایل POM اضافه کنید تا برنامه در یک آرشیو جنگ کامپایل شود:
<packaging>war</packaging>
خوب، شما همچنین به یک فهرست ویژه برای منابع وب نیاز خواهید داشت، در مورد ما صفحات jsp و برخی منابع وب وجود خواهد داشت . بیایید یک main
دایرکتوری ایجاد کنیم webapp
. باید دقیقاً آن نامیده شود و دقیقاً به main
همان شکل قرار گیرد java
، resources
زیرا این ساختار دایرکتوری استاندارد Maven است. هنگامی که بسته را در آن نصب کردیم war
و به این ترتیب تشخیص دادیم که این یک پروژه وب است، دایرکتوری webapp
به طور خودکار به عنوان منابع برنامه وب علامت گذاری می شود (نقطه آبی روی آن وجود دارد) و هر چیزی که مربوط به وب است در این پوشه جستجو می شود. و یک لحظه به طور پیش فرض، Maven از زبان نسخه 1.5 استفاده می کند، اما من می خواهم برای مثال از نسخه 1.8 - جاوا 8 استفاده کنم (می توانید 10 یا 11 را بگیرید، اما هنوز برنامه ای برای استفاده از هیچ ویژگی از آنجا وجود ندارد، بنابراین بگذارید 8 باشد. ). این را می توان خیلی ساده حل کرد، ما در گوگل چیزی مانند Maven java 8 می نویسیم و می بینیم که چه چیزی باید به فایل POM اضافه شود تا Maven کلاس های ما را برای نسخه مورد نیاز کامپایل کند. در نتیجه موارد زیر را داریم:
اتصال فنری MVC
تو باید از یک جایی شروع کنی. طبق برنامه، ما پایگاه داده را متصل خواهیم کرد و از Hibernate استفاده خواهیم کرد، اما همه اینها در حال حاضر کمی ترسناک به نظر می رسد. ابتدا باید کار ساده تری انجام دهیم. فنری MVC، این از قبل بهتر است، ما مدتها با الگوی MVC آشنا بودیم، در نیمی از کارهای بزرگ دوره استفاده می شد. از اینجا شروع می کنیم به رقصیدن. برای ایجاد یک برنامه وب با Spring MVC، به یک Servlet-API نیز نیاز داریم، یعنی. چیزی که به کمک آن تعامل درخواست و پاسخ صورت می گیرد. بیایید سعی کنیم این را به هم وصل کنیم. به گوگل میرویم، وابستگیهای لازم را در مخزن Maven جستجو میکنیم و آنها را به آن اضافه میکنیمpom.xml
. در بخش External Libraries می توانید ببینید که نه تنها Spring-webmvc بارگذاری شده است ، بلکه یک سری چیزهای دیگر نیز بارگذاری شده است. آن ها ما نیازی به اضافه کردن وابستگی برای هسته فنری ، زمینه ، لوبیا و غیره نداریم. که ما نیاز داریم، هر چیزی که نیاز داشتیم همراه با فنر-webmvc جمع آوری شد .
ما باید یک سلب مسئولیت کوچک کنیم. معمولاً توصیه میشود برای هر کتابخانه استفادهشده بهطور جداگانه یک وابستگی اضافه کنید، حتی اگر آنها قبلاً با کتابخانههایی که قبلاً اضافه شدهاند همراه شده باشند، زیرا این می تواند به جلوگیری از برخی مشکلات و اشکالات کمک کند. یک مثال ساده فرض کنید یک وابستگی اضافه کرده ایم که از برخی API استفاده می کند و در همان زمان نوعی پیاده سازی برای این API ایجاد می کند. و سپس وابستگی دیگری را اضافه کردیم که از همان API استفاده می کند و همچنین برخی از پیاده سازی آن را برای این کار انجام می دهد، اما این بار متفاوت است. بنابراین، ما 2 پیاده سازی متفاوت از یک API یکسان خواهیم داشت. و اگر خودمان بخواهیم از برخی روشهای این API در جایی استفاده کنیم، مشکلی پیش میآید، زیرا سیستم نمیداند از کدام پیادهسازی استفاده کند، بهطور تصادفی انتخاب میکند، شاید آن چیزی که انتظار داشتیم نباشد. و اگر به صراحت برای یکی از پیاده سازی ها وابستگی مشخص کنید، اولویت با آن خواهد بود. با این حال، این یک توصیه سختگیرانه نیست؛ این به طور عمده برای پروژه های بزرگ که در آن کتابخانه های مختلف از شرکت های مختلف استفاده می شود، اعمال می شود. ما این کار را در اینجا انجام نمی دهیم، تا فایل POM بیش از حد بارگیری نشود؛ هیچ مشکلی پیش بینی نمی شود. اما با این وجود، هنوز هم ارزش این را دارد که این را در نظر داشته باشید. |
provided
وابستگی یعنی چی javax.servlet-api
؟ Scope محدوده وابستگی است، provided
به این معنی که وابستگی در مرحله کامپایل و آزمایش برنامه در دسترس خواهد بود، اما بایگانی نمی شود. واقعیت این است که برای استقرار برنامه از یک کانتینر servlet به نام Tomcat استفاده می کنیم و قبلاً چنین کتابخانه هایی در داخل آن وجود دارد، بنابراین نیازی به انتقال آنها به آنجا نیست و بایگانی را با بار غیرضروری بارگذاری می کند. با نگاهی به آینده، به همان دلیلی که بدون روش معمول انجام خواهیم داد main
، زیرا از قبل در داخل تامکت وجود دارد.
ایجاد صفحات و کنترلر
حالا بیایید سعی کنیم چیز ساده ای درست کنیم. ابتدا، اجازه دهید یکwebapp
دایرکتوری اضافی ایجاد کنیم، به عنوان مثال pages
، که نماهای ما در آن ذخیره می شوند، به عنوان مثال. صفحات jsp، و چند صفحه ایجاد کنید. ما به صفحه ای نیاز داریم که در آینده مثلاً لیستی از فیلم ها در آن نمایش داده شود films.jsp
و شاید بتوانیم یک صفحه جداگانه برای ویرایش درست کنیم editPage.jsp
. ما در حال حاضر آنها را با هیچ چیز جدی پر نمی کنیم؛ فقط برای آزمایش، پیوندی را در یک صفحه به صفحه دیگر ایجاد می کنیم. اکنون ما به کلاسی نیاز داریم که درخواست ها را پردازش کند، i.e. کنترل کننده بیایید یک بسته جدید اضافه کنیم controller
و یک کلاس در آن ایجاد کنیم FilmController
(به طور کلی لازم نیست همه چیز را در بسته های مختلف بسته بندی کنیم، این برنامه بسیار کوچک و ساده خواهد بود، اما در یک پروژه معمولی می تواند کنترلرها، کلاس های پیکربندی، مدل های زیادی وجود داشته باشد. و غیره، بنابراین حتی با شروع پروژه های کوچک، بهتر است فوراً عادت کنید که همه چیز را به صورت منظم و ساختارمند انجام دهید تا به هم ریختگی وجود نداشته باشد). در این کلاس ما متدهایی ایجاد خواهیم کرد که دیدگاه های ما را در پاسخ به درخواست ها برمی گرداند.
package testgroup.filmography.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class FilmController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
return modelAndView;
}
@RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView editPage() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("editPage");
return modelAndView;
}
}
چه فایده ای دارد؟ Spring MVC چیزی به نام دارد DispatcherServlet
. این مانند کنترل کننده اصلی است، تمام درخواست های دریافتی از آن عبور می کند و سپس آنها را به یک کنترلر خاص ارسال می کند. حاشیهنویسی @Controller
فقط به Spring MVC میگوید که این کلاس یک کنترلکننده است (خوب، به طور کلی منطقی است)، توزیعکننده یادداشتها را بررسی میکند @RequestMapping
تا متد مناسب را فراخوانی کند. حاشیه نویسی @RequestMapping
به شما امکان می دهد تا آدرس هایی را برای روش های کنترلر تنظیم کنید، که توسط آنها در مشتری (مرورگر) در دسترس خواهند بود. همچنین می توان آن را به کلاس کنترلر اعمال کرد تا به اصطلاح آدرس ریشه را برای همه متدها تنظیم کند. allFilms()
پارامتر متد value
روی " " تنظیم شده است ، بنابراین هنگامی که ترکیب http://host:port//
در مرورگر وارد شود بلافاصله فراخوانی می شود (یعنی به طور پیش فرض http://localhost:8080/ یا http است. ://127.0 .0.1:8080/ ). پارامتر مشخص می کند که چه نوع درخواستی پشتیبانی می شود (GET، POST، PUT و غیره). از آنجایی که در اینجا ما فقط داده ها را دریافت می کنیم، از GET استفاده می شود. بعداً وقتی روشهایی برای افزودن و ویرایش ظاهر میشوند، از قبل درخواستهای POST وجود خواهد داشت. (به هر حال، به جای حاشیه نویسی که یک روش را نشان می دهد، می توانید از حاشیه نویسی و غیره به طور معادل استفاده کنید ) ) . در متدهای خود، یک شی ایجاد می کنیم و نام view را که باید برگردانده شود، تنظیم می کنیم. method
@RequestMapping
@GetMapping
@PostMapping
@GetMapping
@RequestMapping(method = RequestMethod.GET
ModelAndView
پیکربندی
بیایید به تنظیم پیکربندی ادامه دهیم.config
بیایید یک کلاس در بسته ایجاد کنیم WebConfig
. فقط یک متد خواهد داشت که یک شی از نوع را برمی گرداند ViewResolver
، این رابطی است که برای یافتن یک نمایش با نام ضروری است.
package testgroup.filmography.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "testgroup.filmography")
public class WebConfig {
@Bean
ViewResolver viewResolver() {
InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
viewResolver.setPrefix("/pages/");
viewResolver.setSuffix(".jsp");
return viewResolver;
}
}
@Configuration
به Spring می گوید که این کلاس یک کلاس پیکربندی است و شامل تعاریف و وابستگی های bean
اجزا است. لوبیا اشیایی هستند که توسط Spring مدیریت می شوند. حاشیه نویسی برای تعریف یک لوبیا استفاده می شود @Bean
. @EnableWebMvc
به شما امکان می دهد پیکربندی Spring MVC را از قسمت وارد کنید WebMvcConfigurationSupport
. همچنین میتوانید، برای مثال، رابطی را پیادهسازی کنید WebMvcConfigurer
که مجموعهای از روشها دارد، و همه چیز را مطابق میل خود سفارشی کنید، اما ما هنوز نیازی به ورود به آن نداریم، تنظیمات استاندارد کافی است. @ComponentScan
به Spring می گوید کجا باید اجزایی را که باید مدیریت کند جستجو کند، i.e. کلاس هایی که با حاشیه نویسی @Component
یا مشتقات آن مانند @Controller
،،، @Repository
مشخص شده اند @Service
. این حاشیه نویسی به طور خودکار کلاس bean را تعریف می کند. در روش، viewResolver()
پیاده سازی آن را ایجاد می کنیم و تعیین می کنیم که دقیقاً در کجا به دنبال نمایش باشیم webapp
. بنابراین، هنگامی که در متد کنترلر نام " films
" را تنظیم می کنیم، view به صورت " /pages/films.jsp
" پیدا می شود، بنابراین، ما یک کلاس پیکربندی داریم، اما در حال حاضر فقط نوعی کلاس جداگانه است، به هیچ وجه بر برنامه ما تأثیر نمی گذارد. . ما باید این پیکربندی را در زمینه Spring ثبت کنیم. برای این به یک کلاس نیاز دارید AbstractAnnotationConfigDispatcherServletInitializer
. در بسته، config
جانشین آن را ایجاد می کنیم، می گوییم AppInitializer ، و روش های آن را پیاده سازی می کنیم.
package testgroup.filmography.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[0];
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{WebConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
}
آخرین روش آدرس ها را ثبت می کند و 2 روش دیگر برای ثبت کلاس های پیکربندی وجود دارد. پیکربندی های وب، جایی که ViewResolver
'ها و موارد مشابه تعریف شده اند، در قرار می گیرند getServletConfigClasses()
. بهتر است در مورد همه اینها در اسناد و راهنماهای مختلف بخوانید ، اما در مورد ما هنوز نیازی به کاوش در این نیست ، ما در اصل می توانیم WebConfig
در RootClasses
هر دو تعریف کنیم ، حتی می توانید هر دو را به طور همزمان تعریف کنید ، هنوز هم کار می کند . یک چیز دیگر. ممکن است هنگام ارسال مقادیر با کاراکترهای روسی از فرم، مشکلاتی در رمزگذاری وجود داشته باشد که نتیجه آن خط خطی باشد. برای حل این مشکل، فیلتری اضافه می کنیم که درخواست ها را پیش پردازش می کند. ما به کلاس AppInitializer می رویم و متد را باطل می کنیم getServletFilters
که در آن کدگذاری مورد نظر را نشان می دهیم، البته باید مانند همه جاهای دیگر باشد، مانند صفحات و در پایگاه داده:
protected Filter[] getServletFilters() {
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return new Filter[] {characterEncodingFilter};
}
خب، به نظر می رسد همه چیز تنظیم شده است، می توانید آن را اجرا کنید و ببینید چه اتفاقی می افتد. Run -> Run -> Edit Configurations -> Add New Configuration -> Tomcat Server -> Local Next، باید یک مصنوع را برای استقرار انتخاب کنید. این ایده به خودی خود یک نکته را ارائه می دهد. هشدار: هیچ اثری برای استقرار علامت گذاری نشده است . روی دکمه fix کلیک کنید و ...: war exploded را انتخاب کنید . یا می توانید به Deployment -> add -> Artifact -> ...: war exploded بروید . و همچنین باید به Deployment بروید و فیلد زمینه Applecation (این بخشی از آدرس url است که برنامه در مرورگر در دسترس خواهد بود) را روی " /
" تنظیم کنید. سپس برنامه ما بلافاصله در http://localhost:8080/ در دسترس خواهد بود (اما شما همچنین می توانید چیزی را در آنجا مشخص کنید، برای مثال " "، و سپس فقط باید آن را به همه آدرس ها اضافه کنید، به عنوان مثال، هیچ آدرسی وجود نخواهد داشت. "http://localhost:8080/edit" ، اما "http://localhost:8080/filmography/edit" خواهد بود ). روی Run کلیک کنید و منتظر بمانید تا شروع شود. این چیزی است که من دریافت کردم: به نظر می رسد همه چیز خوب است، اما یک هشدار وجود دارد. واقعیت این است که صفحات ما اکنون در دسترس عموم هستند و با نوشتن مسیر در نوار آدرس می توان مستقیماً به آنها دسترسی داشت. ما وارد http://localhost:8080/pages/films.jsp می شویم و اکنون صفحه خود را بدون اطلاع کنترل کننده دریافت کرده ایم. به نوعی این خیلی درست نیست، بنابراین ما یک دایرکتوری ویژه ایجاد خواهیم کرد . آنچه در داخل است از دید عموم پنهان می شود و فقط از طریق یک کنترلر قابل دسترسی است. دایرکتوری را با view های خود ( ) در قرار می دهیم و بر این اساس آن را به پیشوند اضافه می کنیم: /filmography
webapp
WEB-INF
pages
WEB-INF
ViewResolver
viewResolver.setPrefix("/WEB-INF/pages/");
اکنون صفحه خود را در http://localhost:8080 دریافت می کنیم ، اما اگر مستقیماً به http://localhost:8080/WEB-INF/pages/films.jsp امتحان کنیم ، یک خطای 404 دریافت می کنیم. خوب، عالی، ما این خطا را داریم. ساده ترین وب اپلیکیشن، Hello World همانطور که می گویند. ساختار پروژه در حال حاضر به شکل زیر است:
مدل
ما قبلا نماها و یک کنترلر داریم، اما در MVC یک حرف 3 نیز وجود دارد، بنابراین برای تکمیل تصویر یک مدل نیز اضافه می کنیم. در بسته،model
بیایید یک کلاس ایجاد کنیم Film
، به عنوان مثال، با فیلدهای زیر: int id
, String title
(عنوان)، int year
(سال انتشار)، String genre
(ژانر) و boolean watched
(یعنی آیا قبلاً این فیلم را تماشا کرده اید یا خیر).
package testgroup.filmography.model;
public class Film {
private int id;
private String title;
private int year;
private String genre;
private boolean watched;
// + Getters and setters
}
هیچ چیز خاصی نیست، فقط یک کلاس معمولی، فیلدهای خصوصی، گیرنده ها و ستترها. به اشیاء چنین کلاس هایی POJO
(Plain Old Java Object) نیز گفته می شود، خوب، i.e. "شیء جاوا ساده". بیایید اکنون سعی کنیم چنین شی ای ایجاد کنیم و آن را در صفحه نمایش دهیم. در حال حاضر، ما زیاد نگران نحوه ایجاد و مقداردهی اولیه آن نخواهیم بود. برای امتحان کردن، اجازه دهید به طور احمقانه آن را مستقیماً در کنترلر ایجاد کنیم، به عنوان مثال، مانند این:
public class FilmController {
private static Film film;
static {
film = new Film();
film.setTitle("Inception");
film.setYear(2010);
film.setGenre("sci-fi");
film.setWatched(true);
}
و ModelAndView
با استفاده از روش این شی را به شیء ما اضافه کنید addObject
:
@RequestMapping(method = RequestMethod.GET)
public ModelAndView allFilms() {
ModelAndView modelAndView = new ModelAndView();
modelAndView.setViewName("films");
modelAndView.addObject("film", film);
return modelAndView;
}
اکنون می توانیم این شی را در صفحه خود نمایش دهیم. به films.jsp
جای Hello World می نویسیم ${film}
و شی مربوط به نام ویژگی " film
" در اینجا جایگزین می شود. بیایید آن را اجرا کنیم و ببینیم چه اتفاقی افتاده است (برای خروجی واضح شی، کلاس Film
دوباره تعریف شد toString()
):
Model-View-Controller
در این مرحله، به نظر می رسد که ما قبلاً یک برنامه کامل Spring MVC داریم. قبل از حرکت، خوب است دوباره به همه چیز نگاهی بیندازید و بفهمید که چگونه همه چیز کار می کند. در اینترنت می توانید تصاویر و نمودارهای زیادی در این مورد پیدا کنید، من این یکی را دوست دارم:Dispatcher Servlet
، سپس کنترلکننده مناسبی برای پردازش این درخواست با استفاده از آن پیدا میکند HandlerMapping
(این یک رابط برای انتخاب یک کنترلکننده است، بررسی میکند که کدام یک از کنترلکنندههای موجود روشی دارد که چنین آدرسی را میپذیرد) ، یک متد مناسب را فراخوانی می کند و Controller
اطلاعات مربوط به view را برمی گرداند، سپس Dispatcher با استفاده از ViewResolver
'a نمای مورد نظر را با نام پیدا می کند و پس از آن داده های مدل به این view منتقل می شود و صفحه خود را به عنوان خروجی می گیریم. چیزی شبیه به این. ادامه دارد... معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 1) معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 2) معرفی Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 3) مقدمه ای بر Maven، Spring، MySQL، Hibernate و اولین برنامه CRUD (قسمت 4)
GO TO FULL VERSION