Hər kəsə salam, əziz dostlarım və oxucularım! Məqaləni yazmazdan əvvəl bir az məlumat... Bu yaxınlarda burada telegram kanalımda qısaca təsvir etdiyim Mapstruct kitabxanası ilə işləmək problemi ilə qarşılaşdım . Şərhlərdə yazı ilə bağlı problem həll olundu, əvvəlki layihədəki həmkarım bu işdə kömək etdi. Bundan sonra bu mövzuda bir məqalə yazmaq qərarına gəldim, lakin təbii ki, dar bir baxış keçirməyəcəyik və əvvəlcə sürətlənməyə, Mapstruct-un nə olduğunu və nə üçün lazım olduğunu başa düşməyə çalışacağıq və real bir nümunədən istifadə edəcəyik. əvvəllər yaranmış vəziyyəti və onu necə həll edəcəyini təhlil edin. Buna görə də, hər şeyi praktikada yaşamaq üçün məqaləni oxumaqla paralel olaraq bütün hesablamaları etməyi şiddətlə tövsiyə edirəm. Başlamazdan əvvəl telegram kanalıma abunə olun , fəaliyyətlərimi orada toplayıram, Java və ümumiyyətlə İT-də inkişaf haqqında fikirlər yazıram. Abunə oldunuz? Əla! Yaxşı, indi gedək!
Mapstruct, tez-tez sual?
Sürətli növ təhlükəsiz lobya xəritələri üçün kod generatoru. İlk işimiz Mapstruct-un nə olduğunu və ona nə üçün ehtiyacımız olduğunu anlamaqdır. Ümumiyyətlə, bu barədə rəsmi internet saytında oxuya bilərsiniz. Saytın əsas səhifəsində suallara üç cavab var: bu nədir? Nə üçün? Necə? Biz də bunu etməyə çalışacağıq:
Bu nədir?
Mapstruct, interfeyslər vasitəsilə təsvir edilən konfiqurasiyalar əsasında yaradılan koddan istifadə edərək bəzi obyektlərin obyektlərini digər obyektlərin obyektlərinə xəritələşdirməyə (xəritə, ümumiyyətlə, onlar həmişə belə deyirlər: xəritə, xəritə və s.) kömək edən kitabxanadır.
Nə üçün?
Əksər hallarda biz çox qatlı proqramlar (verilənlər bazası ilə işləmək üçün təbəqə, biznes məntiqi təbəqəsi, tətbiqin xarici dünya ilə qarşılıqlı əlaqəsi üçün təbəqə) inkişaf etdiririk və hər bir təbəqənin məlumatların saxlanması və emalı üçün öz obyektləri var. . Və bu məlumatları bir varlıqdan digərinə köçürməklə təbəqədən təbəqəyə köçürmək lazımdır. Bu yanaşma ilə işləməmişlər üçün bu bir az mürəkkəb görünə bilər. Məsələn, Tələbə verilənlər bazası üçün bir qurumumuz var. Bu obyektin məlumatları biznes məntiqi (xidmətlər) səviyyəsinə keçdikdə, məlumatları Student sinfindən StudentModel sinfinə köçürməliyik. Sonra, biznes məntiqi ilə bütün manipulyasiyalardan sonra məlumatların kənarda buraxılması lazımdır. Bunun üçün bizdə StudentDto sinfi var. Əlbəttə ki, biz StudentModel sinfindən məlumatları StudentDto-ya ötürməliyik. Köçürüləcək üsulların hər dəfə əllə yazılması çox əmək tələb edir. Üstəlik bu, kod bazasında saxlanılmalı olan əlavə koddur. Səhv edə bilərsiniz. Mapstruct isə bu cür metodları kompilyasiya mərhələsində yaradır və onları yaradılan mənbələrdə saxlayır.
Necə?
Annotasiyalardan istifadə. Biz sadəcə olaraq kitabxanaya bu interfeysdəki metodların bir obyektdən digərinə tərcümə etmək üçün istifadə oluna biləcəyini bildirən əsas Mapper annotasiyası olan annotasiya yaratmalıyıq. Tələbələr haqqında daha əvvəl dediyim kimi, bizim vəziyyətimizdə bu, məlumatları bir təbəqədən digərinə ötürmək üçün bir neçə üsula malik olan StudentMapper interfeysi olacaq:
Bu yanaşmanın gözəlliyi ondadır ki, əgər müxtəlif siniflərdə sahələrin adları və növləri eynidirsə (bizim vəziyyətimizdə olduğu kimi), onda Mapstruct üçün parametrlər kompilyasiya mərhələsində StudentMapper interfeysi əsasında lazımi tətbiqi yaratmaq üçün kifayətdir. tərcümə edəcək. Beləliklə, artıq aydın oldu, elə deyilmi? Gəlin daha da irəli gedək və Spring Boot proqramında işi təhlil etmək üçün real nümunədən istifadə edək.
Spring Boot və Mapstruct işinin nümunəsi
Bizə lazım olan ilk şey Spring Boot layihəsi yaratmaq və ona Mapstruct əlavə etməkdir. Bu mövzuda GitHub-da depolar üçün şablonları olan bir təşkilatım var və Spring Boot üçün başlanğıc onlardan biridir. Bunun əsasında yeni layihə yaradırıq: Sonra layihəni alırıq . Bəli, dostlar, layihəni faydalı hesab etdinizsə, ona bir ulduz verin, ona görə də biləcəyəm ki, bunu boş yerə etmirəm. Bu layihədə işdə aldığım və Telegram kanalımdakı bir yazıda təsvir etdiyim bir vəziyyəti açıqlayacağıq . Bilməyənlər üçün vəziyyəti qısaca təsvir edəcəyəm: xəritəçilər üçün testlər yazarkən (yəni əvvəllər haqqında danışdığımız interfeys tətbiqləri üçün) testlərin mümkün qədər tez keçməsini istəyirik. Xəritəçəkənlərlə ən sadə seçim testi işləyərkən SpringBootTest annotasiyasından istifadə etməkdir ki, bu da Spring Boot tətbiqinin bütün ApplicationContext-i götürəcək və testin içinə test üçün lazım olan xəritəçini yeridəcək. Ancaq bu seçim resurs tələb edir və daha çox vaxt tələb edir, ona görə də bizim üçün uyğun deyil. Sadəcə olaraq istədiyiniz xəritəçini yaradan və onun metodlarının gözlədiyimiz kimi işlədiyini yoxlayan vahid testi yazmalıyıq. Daha sürətli işləmək üçün niyə testlərə ehtiyacınız var? Testlər uzun müddət çəkirsə, bütün inkişaf prosesini ləngidir. Testlər yeni kodu keçməyincə, bu kod düzgün hesab edilə bilməz və sınaqdan keçirilməyəcək, yəni istehsala qəbul edilməyəcək və bu, tərtibatçının işi tamamlamaması deməkdir. Deyəsən, işləməsi şübhə doğurmayan bir kitabxana üçün niyə test yazmalısınız? Və yenə də bir test yazmalıyıq, çünki xəritəçini necə düzgün təsvir etdiyimizi və onun gözlədiyimizi edib-etmədiyini yoxlayırıq. İlk öncə işimizi asanlaşdırmaq üçün pom.xml-ə başqa bir asılılıq əlavə edərək layihəmizə Lombok əlavə edək:
Layihəmizdə model siniflərdən (biznes məntiqi ilə işləmək üçün istifadə olunan) xarici dünya ilə ünsiyyət üçün istifadə etdiyimiz DTO siniflərinə keçməmiz lazım gələcək. Sadələşdirilmiş versiyamızda sahələrin dəyişmədiyini və xəritəçilərimizin sadə olacağını güman edəcəyik. Amma istək olarsa, Mapstruct ilə necə işləmək, onu necə konfiqurasiya etmək və onun üstünlüklərindən necə yararlanmaq barədə daha ətraflı məqalə yazmaq olardı. Ancaq sonra, çünki bu məqalə olduqca uzun olacaq. Tutaq ki, bir tələbəmiz var, onun iştirak etdiyi mühazirə və mühazirəçilərin siyahısı var. Model paketi yaradaq . Buna əsaslanaraq sadə bir model yaradacağıq:
İndi mühazirə modelləri toplusunu DTO mühazirələri toplusuna çevirəcək mapper yaradaq. Ediləcək ilk şey Mapstruct-u layihəyə əlavə etməkdir. Bunun üçün biz onların rəsmi internet saytından istifadə edəcəyik , orada hər şey təsvir edilmişdir. Yəni yaddaşımıza bir asılılıq və plagin əlavə etməliyik (yaddaşın nə olduğu ilə bağlı sualınız varsa, buyurun, Maddə1 və Maddə2 ):
Ayrı-ayrılıqda qeyd etmək lazımdır ki, xəritəçilərdə biz başqa xəritəçilərə müraciət edirik. Bu , StudentMapper-də olduğu kimi, Mapper annotasiyasındakı istifadə sahəsi vasitəsilə həyata keçirilir :
Burada mühazirələrin siyahısını və mühazirəçilərin siyahısını düzgün xəritələşdirmək üçün iki xəritəçidən istifadə edirik. İndi kodumuzu tərtib etməliyik və orada nə və necə olduğunu görməliyik. Bu, mvn clean compile əmrindən istifadə etməklə edilə bilər . Lakin məlum oldu ki, xəritəçilərimizin Mapstruct tətbiqlərini yaratarkən, xəritəçi tətbiqləri sahələrin üzərinə yazılmayıb. Niyə? Məlum oldu ki, Lombokdan Data annotasiyasını götürmək mümkün deyil. Və nəsə etmək lazım idi... Ona görə də yazıda yeni bölməmiz var.
Lombok və Mapstruct-u birləşdirin
Bir neçə dəqiqəlik axtarışdan sonra məlum oldu ki, Lombok və Mapstruct-u müəyyən bir şəkildə birləşdirməliyik. Mapstruct sənədlərində bu barədə məlumat var . Mapstruct-dan tərtibatçılar tərəfindən təklif olunan nümunəni araşdırdıqdan sonra pom.xml-imizi yeniləyək: Ayrı-ayrı versiyalar əlavə edək:
Bundan sonra hər şey düzəlməlidir. Layihəmizi yenidən tərtib edək. Bəs Mapstruct-un yaratdığı sinifləri haradan tapa bilərsiniz? Onlar yaradılan mənbələrdədir: ${projectDir}/target/generated-sources/annotations/ İndi Mapstruct yazısından məyusluğumu başa düşməyə hazırıq, gəlin xəritəçilər üçün testlər yaratmağa çalışaq.
Xəritəçəkənlərimiz üçün testlər yazırıq
İnteqrasiya testi yaratdığımız halda xəritəçilərdən birini sınaqdan keçirəcək tez və sadə bir test yaradacağam və onun tamamlanma vaxtı barədə narahat olmayın:
Burada SpringBootTest annotasiyasından istifadə edərək biz bütün proqram kontekstini işə salırıq və ondan Autowired annotasiyasından istifadə edərək sınaq üçün lazım olan sinfi çıxarırıq. Test yazmağın sürəti və asanlığı baxımından bu çox yaxşıdır. Test uğurla keçdi, hər şey yaxşıdır. Amma biz başqa yolla gedəcəyik və xəritəçi üçün vahid testi yazacağıq, məsələn, LectureListMapper...
Mapstruct-un yaratdığı tətbiqlər layihəmizlə eyni sinifdə olduğundan, biz onları testlərimizdə asanlıqla istifadə edə bilərik. Hər şey əla görünür - annotasiya yoxdur, biz ən sadə şəkildə ehtiyac duyduğumuz sinfi yaradırıq və budur. Amma testi həyata keçirəndə biz başa düşəcəyik ki, o, qəzaya uğrayacaq və konsolda NullPointerException olacaq... Bunun səbəbi LectureListMapper mapper-in tətbiqi belə görünür:
NPE-ə (NullPointerException üçün qısa) baxsaq, onu lectureMapper dəyişənindən alırıq , bu da işə salınmayıb. Amma bizim tətbiqimizdə dəyişəni işə sala biləcəyimiz konstruktor yoxdur. Mapstruct-un xəritəçini bu şəkildə həyata keçirməsinin səbəbi məhz budur! Baharda siz bir neçə yolla dərslərə lobya əlavə edə bilərsiniz, yuxarıda göstərildiyi kimi onları Autowired annotasiyası ilə birlikdə sahəyə yeridə bilərsiniz və ya konstruktor vasitəsilə yeridə bilərsiniz. Testin icra müddətini optimallaşdırmaq lazım olanda özümü işdə belə problemli vəziyyətdə tapdım. Bununla bağlı heç nə edilə bilməyəcəyini düşündüm və ağrılarımı Telegram kanalımda tökdüm. Və sonra şərhlərdə mənə kömək etdilər və inyeksiya strategiyasını fərdiləşdirməyin mümkün olduğunu söylədilər. Mapper interfeysində iki dəyəri olan InjectionStrategy adını qəbul edən injectionStrategy sahəsi var: FIELD və CONSTRUCTOR . İndi bunu bilərək, gəlin bu parametri xəritəçilərimizə əlavə edək; mən bunu LectureListMapper istifadə edərək nümunə olaraq göstərəcəyəm :
Əlavə etdiyim hissəni qalın hərflərlə vurğuladım. Bütün digərləri üçün bu seçimi əlavə edək və layihəni yenidən kompilyasiya edək ki, xəritəçilər yeni sətirlə yaradılsın. Bunu etdikdən sonra LectureListMapper üçün xəritəçinin tətbiqinin necə dəyişdiyini görək (lazım olan hissə qalın hərflərlə vurğulanır):
İndi Mapstruct konstruktor vasitəsilə mapper inyeksiyasını həyata keçirdi. Məhz buna nail olmağa çalışdıq. İndi testimiz tərtib etməyi dayandıracaq, onu yeniləyək və əldə edək:
İndi testi keçirsək, hər şey gözlənildiyi kimi işləyəcək, çünki LectureListMapperImpl-də biz ona lazım olan LectureMapper-i keçirik... Qələbə! Sizin üçün çətin deyil, amma məmnunam: Dostlar, hər şey həmişəki kimidir, mənim GitHub hesabıma , Telegram hesabıma abunə olun . Orada fəaliyyətimin nəticələrini yerləşdirirəm, həqiqətən faydalı şeylər var) Sizi xüsusilə telegram kanalının müzakirə qrupuna qoşulmağa dəvət edirəm . Elə olur ki, kimin texniki sualı olsa, orada cavab ala bilər. Bu format hamı üçün maraqlıdır, kimin nə bildiyini oxuyub təcrübə qazana bilərsiniz.
Nəticə
Bu yazının bir hissəsi olaraq Mapstruct kimi zəruri və tez-tez istifadə olunan məhsulla tanış olduq. Bunun nə olduğunu, niyə və necə olduğunu anladıq. Həqiqi bir nümunədən istifadə edərək, nəyin edilə biləcəyini və necə dəyişdirilə biləcəyini hiss etdik. Biz həmçinin konstruktor vasitəsilə lobya inyeksiyasının necə qurulacağına baxdıq ki, xəritəçilərin düzgün sınaqdan keçirilməsi mümkün olsun. Mapstruct-dan olan həmkarlar öz məhsullarının istifadəçilərinə xəritəçilərin necə inyeksiya ediləcəyini dəqiq seçmək imkanı verdilər, buna görə biz onlara, şübhəsiz ki, təşəkkür edirik. AMMA, Spring-in konstruktor vasitəsilə lobya yeritməyi tövsiyə etməsinə baxmayaraq, Mapstruct-dan olan uşaqlar standart olaraq sahəyə inyeksiya təyin etdilər. Niyə belədir? Cavab yoxdur. Düşünürəm ki, bizim bilmədiyimiz səbəblər ola bilər və buna görə də bunu belə etdilər. Və onlardan öyrənmək üçün onların rəsmi məhsul deposunda GitHub məsələsi yaratdım .
GO TO FULL VERSION