Hammaga salom, aziz do'stlarim va o'quvchilarim! Maqolani yozishdan oldin biroz ma'lumot... Yaqinda Mapstruct kutubxonasi bilan ishlashda muammoga duch keldim , bu haqda telegram kanalimda bu yerda qisqacha bayon qildim . Izohlarda post bilan bog'liq muammo hal qilindi, mening oldingi loyihadagi hamkasbim bunga yordam berdi. Shundan so'ng men ushbu mavzu bo'yicha maqola yozishga qaror qildim, lekin, albatta, biz tor nuqtai nazarga ega bo'lmaymiz va birinchi navbatda tezlikni oshirishga, Mapstruct nima ekanligini va nima uchun kerakligini tushunishga harakat qilamiz va haqiqiy misoldan foydalanib, biz buni qilamiz. ilgari yuzaga kelgan vaziyatni va uni qanday hal qilishni tahlil qilish. Shuning uchun men hamma narsani amalda sinab ko'rish uchun maqolani o'qish bilan parallel ravishda barcha hisob-kitoblarni bajarishni qat'iy tavsiya qilaman. Ishni boshlashdan oldin, mening telegram kanalimga obuna bo'ling , men u erda o'z faoliyatimni to'playman, Java va umuman IT-dagi rivojlanish haqida fikrlarni yozaman. Obuna bo'ldingizmi? Ajoyib! Xo'sh, endi ketaylik!
Mapstruct, savol-javob?
Tez turdagi xavfsiz loviya xaritalari uchun kod generatori. Bizning birinchi vazifamiz Mapstruct nima ekanligini va nima uchun bizga kerakligini aniqlashdir. Umuman olganda, siz bu haqda rasmiy veb-saytda o'qishingiz mumkin. Saytning asosiy sahifasida savollarga uchta javob bor: bu nima? Nima uchun? Qanaqasiga? Biz ham buni qilishga harakat qilamiz:
Bu nima?
Mapstruct - bu interfeyslar orqali tasvirlangan konfiguratsiyalar asosida yaratilgan koddan foydalangan holda ba'zi ob'ektlarning ob'ektlarini boshqa ob'ektlarning ob'ektlariga xaritalashda (xarita, umuman olganda, ular doimo shunday deyishadi: xarita, xarita va hokazo) yordam beradigan kutubxona.
Nima uchun?
Ko'pincha biz ko'p qatlamli ilovalarni ishlab chiqamiz (ma'lumotlar bazasi bilan ishlash qatlami, biznes mantig'i qatlami, ilovaning tashqi dunyo bilan o'zaro ta'siri uchun qatlam) va har bir qatlam ma'lumotlarni saqlash va qayta ishlash uchun o'z ob'ektlariga ega. . Va bu ma'lumotlarni bir ob'ektdan ikkinchisiga o'tkazish orqali qatlamdan qatlamga o'tkazish kerak. Ushbu yondashuv bilan ishlamaganlar uchun bu biroz murakkab ko'rinishi mumkin. Masalan, bizda Student ma'lumotlar bazasi uchun ob'ekt mavjud. Ushbu ob'ektning ma'lumotlari biznes mantig'i (xizmatlar) qatlamiga o'tganda, biz ma'lumotlarni Student sinfidan StudentModel sinfiga o'tkazishimiz kerak. Keyinchalik, biznes mantig'i bilan barcha manipulyatsiyalardan so'ng, ma'lumotlar tashqariga chiqarilishi kerak. Buning uchun bizda StudentDto sinfi mavjud. Albatta, biz StudentModel sinfidan StudentDto-ga ma'lumotlarni uzatishimiz kerak. Har safar o'tkaziladigan usullarni qo'lda yozish ko'p mehnat talab qiladi. Bundan tashqari, bu saqlanishi kerak bo'lgan kod bazasida qo'shimcha kod. Siz xato qilishingiz mumkin. Mapstruct kompilyatsiya bosqichida bunday usullarni yaratadi va ularni yaratilgan manbalarda saqlaydi.
Qanaqasiga?
Annotatsiyalardan foydalanish. Biz kutubxonaga ushbu interfeysdagi usullarni bir ob'ektdan ikkinchisiga tarjima qilish uchun foydalanish mumkinligini aytadigan asosiy Mapper annotatsiyasiga ega bo'lgan izohni yaratishimiz kerak. Talabalar haqida yuqorida aytganimdek, bizning holatlarimizda bu StudentMapper interfeysi bo'lib, unda ma'lumotlarni bir qatlamdan ikkinchisiga o'tkazishning bir necha usullari mavjud:
Ushbu yondashuvning go'zalligi shundaki, agar turli sinflarda maydonlarning nomlari va turlari bir xil bo'lsa (bizning holatimizda bo'lgani kabi), Mapstruct sozlamalari kompilyatsiya bosqichida StudentMapper interfeysi asosida kerakli dasturni yaratish uchun etarli bo'ladi. tarjima qiladi. Demak, bu allaqachon aniq bo'ldi, to'g'rimi? Keling, oldinga boraylik va Spring Boot ilovasidagi ishni tahlil qilish uchun haqiqiy misoldan foydalanamiz.
Spring Boot va Mapstruct ishiga misol
Bizga kerak bo'lgan birinchi narsa - Spring Boot loyihasini yaratish va unga Mapstruct qo'shish. Bu borada mening GitHub-da omborlar uchun shablonlarga ega tashkilotim bor va Spring Boot-ning boshlanishi ulardan biri. Unga asoslanib, biz yangi loyiha yaratamiz: Keyinchalik, biz loyihani olamiz . Ha, do'stlar, loyihani foydali deb topsangiz, unga yulduzcha bering , shuning uchun men buni behuda qilmayotganimni bilib olaman. Ushbu loyihada men ish joyida olgan va Telegram kanalimdagi postda tasvirlangan vaziyatni ochib beramiz . Men bilmaganlar uchun vaziyatni qisqacha aytib beraman: biz xaritachilar uchun testlarni yozganimizda (ya'ni, biz ilgari aytib o'tgan interfeyslarni amalga oshirish uchun), biz testlarni iloji boricha tezroq topshirishni xohlaymiz. Xaritachilar bilan eng oddiy variant sinovni o'tkazishda SpringBootTest izohidan foydalanish bo'lib, u Spring Boot ilovasining butun ApplicationContext-ni tanlaydi va test ichidagi test uchun zarur bo'lgan xaritachini kiritadi. Ammo bu variant resurslarni talab qiladi va ko'proq vaqt talab etadi, shuning uchun u biz uchun mos emas. Biz shunchaki kerakli mapperni yaratadigan va uning usullari biz kutgandek ishlashini tekshiradigan birlik testini yozishimiz kerak. Nima uchun tezroq ishlash uchun testlar kerak? Agar testlar uzoq vaqt talab qilsa, u butun rivojlanish jarayonini sekinlashtiradi. Sinovlar yangi kodni o'tkazmaguncha, ushbu kodni to'g'ri deb hisoblash mumkin emas va sinovdan o'tkazilmaydi, ya'ni u ishlab chiqarishga olinmaydi va ishlab chiquvchi ishni tugatmaganligini anglatadi. Ko'rinishidan, nima uchun ishlashi shubhasiz bo'lgan kutubxona uchun test yozish kerak? Va shunga qaramay, biz test yozishimiz kerak, chunki biz xaritachini qanchalik to'g'ri tasvirlaganimizni va u biz kutgan narsani qiladimi yoki yo'qligini sinab ko'rmoqdamiz. Avvalo, ishimizni osonlashtirish uchun, keling, pom.xml ga boshqa qaramlikni qo'shish orqali loyihamizga Lombokni qo'shamiz:
Loyihamizda namunaviy sinflardan (biznes mantig'i bilan ishlash uchun foydalaniladi) tashqi dunyo bilan muloqot qilish uchun foydalaniladigan DTO sinflariga o'tishimiz kerak bo'ladi. Bizning soddalashtirilgan versiyamizda biz maydonlar o'zgarmasligini va xaritachilarimiz oddiy bo'lishini taxmin qilamiz. Ammo, agar istak bo'lsa, Mapstruct bilan qanday ishlash, uni qanday sozlash va uning afzalliklaridan qanday foydalanish haqida batafsilroq maqola yozish mumkin edi. Ammo keyin, chunki bu maqola juda uzoq bo'ladi. Aytaylik, bizda u qatnashadigan ma'ruzalar va ma'ruzachilar ro'yxati bor talaba bor. Keling, model paketini yarataylik . Bunga asoslanib, biz oddiy modelni yaratamiz:
Keling, ma'ruza modellari to'plamini DTO ma'ruzalari to'plamiga aylantiradigan mapper yarataylik. Birinchi narsa Mapstruct-ni loyihaga qo'shishdir. Buning uchun biz ularning rasmiy veb-saytidan foydalanamiz , u erda hamma narsa tasvirlangan. Ya'ni, biz xotiramizga bitta bog'liqlik va plagin qo'shishimiz kerak (agar sizda xotira nima haqida savollaringiz bo'lsa, 1-modda va 2-modda ):
Alohida ta'kidlash kerakki, xaritachilarda biz boshqa xaritachilarga murojaat qilamiz. Bu StudentMapper da qilinganidek, Xaritachi izohidagi uses maydoni orqali amalga oshiriladi :
Bu erda ma'ruzalar ro'yxati va o'qituvchilar ro'yxatini to'g'ri xaritalash uchun ikkita mapperdan foydalanamiz. Endi biz kodimizni kompilyatsiya qilishimiz va u erda nima va qanday ekanligini ko'rishimiz kerak. Buni mvn clean compile buyrug'i yordamida amalga oshirish mumkin . Ammo, ma'lum bo'lishicha, xaritachilarimizning Mapstruct ilovalarini yaratishda, xaritalash ilovalari maydonlarni qayta yozmagan. Nega? Ma'lum bo'lishicha, Lombokdan Data annotatsiyasini olishning iloji bo'lmagan. Va nimadir qilish kerak edi ... Shuning uchun, biz maqolada yangi bo'limga egamiz.
Lombok va Mapstructni ulash
Bir necha daqiqa qidiruvdan so'ng, biz Lombok va Mapstruct-ni ma'lum bir tarzda ulashimiz kerakligi ma'lum bo'ldi. Mapstruct hujjatlarida bu haqda ma'lumot mavjud . Mapstruct-dan ishlab chiquvchilar tomonidan taklif qilingan misolni ko'rib chiqqandan so'ng, keling, pom.xml-ni yangilaymiz: Keling, alohida versiyalarni qo'shamiz:
Shundan so'ng hamma narsa ishlashi kerak. Keling, loyihamizni yana kompilyatsiya qilaylik. Mapstruct tomonidan yaratilgan sinflarni qayerdan topishingiz mumkin? Ular yaratilgan manbalarda: ${projectDir}/target/generated-sources/annotations/ Mapstruct postidan hafsalam pir bo'lganini anglab yetishga tayyormiz, endi xaritachilar uchun testlar yaratishga harakat qilaylik.
Biz xaritachilarimiz uchun testlar yozamiz
Men integratsiya testini yaratayotgan va uning tugash vaqti haqida tashvishlanmasangiz, xaritachilardan birini sinab ko'radigan tez va oddiy test yarataman:
Bu erda, SpringBootTest izohidan foydalanib, biz butun dasturKontekstini ishga tushiramiz va undan Autowired izohidan foydalanib, sinov uchun kerakli sinfni chiqaramiz. Tezlik va test yozish qulayligi nuqtai nazaridan, bu juda yaxshi. Sinov muvaffaqiyatli o'tdi, hamma narsa yaxshi. Ammo biz boshqa yo'ldan boramiz va xaritalash vositasi uchun birlik testini yozamiz, masalan, LectureListMapper...
Mapstruct yaratadigan ilovalar bizning loyihamiz bilan bir xil sinfda bo'lganligi sababli, biz ulardan testlarimizda osongina foydalanishimiz mumkin. Hammasi ajoyib ko'rinadi - izohlar yo'q, biz o'zimizga kerakli sinfni eng oddiy tarzda yaratamiz va tamom. Ammo testni o'tkazganimizda, biz uning ishdan chiqishini va konsolda NullPointerException bo'lishini tushunamiz... Buning sababi, LectureListMapper mapperning amalga oshirilishi quyidagicha ko'rinadi:
Agar biz NPE ga qarasak (NullPointerException so'zining qisqartmasi), biz uni lectureMapper o'zgaruvchisidan olamiz , bu ishga tushirilmagan bo'lib chiqadi. Ammo amalga oshirishda bizda o'zgaruvchini ishga tushirishimiz mumkin bo'lgan konstruktor yo'q. Mapstruct xaritachini shu tarzda amalga oshirganining sababi aynan shu! Bahorda siz fasolni sinflarga bir necha usul bilan qo'shishingiz mumkin, ularni yuqoridagi kabi Autowired izohi bilan birga maydon orqali kiritishingiz mumkin yoki ularni konstruktor orqali kiritishingiz mumkin. Sinovni bajarish vaqtini optimallashtirish kerak bo'lganda, men ishda shunday muammoli vaziyatga tushib qoldim. Hech narsa qilib bo'lmaydi, deb o'yladim va o'z dardimni Telegram kanalimda to'kib tashladim. Va keyin ular menga sharhlarda yordam berishdi va inyeksiya strategiyasini sozlash mumkinligini aytishdi. Mapper interfeysida injectionStrategy maydoni mavjud bo'lib , u faqat InjectionStrategy nomini qabul qiladi , bu ikki qiymatga ega: FIELD va CONSTRUCTOR . Endi buni bilib, ushbu parametrni xaritachilarimizga qo'shamiz; Men uni LectureListMapper yordamida misol sifatida ko'rsataman :
Men qo'shilgan qismni qalin qilib ta'kidladim. Keling, ushbu parametrni boshqalar uchun qo'shamiz va loyihani qayta kompilyatsiya qilamiz, shunda xaritachilar yangi qator bilan yaratiladi. Buni amalga oshirgandan so'ng, keling, LectureListMapper uchun xaritachining amalga oshirilishi qanday o'zgarganini ko'rib chiqamiz (bizga kerak bo'lgan qism qalin qilib belgilangan):
Endi Mapstruct konstruktor orqali mapper inyeksiyasini amalga oshirdi. Aynan shu narsaga erishmoqchi edik. Endi bizning testimiz kompilyatsiya qilishni to'xtatadi, keling, uni yangilaymiz va olamiz:
Endi testni o'tkazsak, hamma narsa kutilganidek ishlaydi, chunki LectureListMapperImpl da biz unga kerak bo'lgan LectureMapper ni topshiramiz... G'alaba! Bu siz uchun qiyin emas, lekin men mamnunman: Do'stlar, hamma narsa odatdagidek, mening GitHub akkauntimga , Telegram akkauntimga obuna bo'ling . U erda men faoliyatim natijalarini joylashtiraman, haqiqatan ham foydali narsalar bor) Men sizni ayniqsa telegram kanalining muhokama guruhiga qo'shilishga taklif qilaman . Shunday bo'ladiki, agar kimdir texnik savolga ega bo'lsa, u erda javob olishi mumkin. Ushbu format hamma uchun qiziqarli, siz kim nimani bilishini o'qib, tajriba orttirishingiz mumkin.
Xulosa
Ushbu maqola doirasida biz Mapstruct kabi zarur va tez-tez ishlatiladigan mahsulot bilan tanishdik. Biz nima ekanligini, nima uchun va qanday ekanligini aniqladik. Haqiqiy misoldan foydalanib, biz nima qilish mumkinligini va uni qanday o'zgartirish mumkinligini his qildik. Biz, shuningdek, konstruktor orqali loviya inyeksiyasini qanday sozlashni ko'rib chiqdik, shunda xaritachilarni to'g'ri sinab ko'rish mumkin edi. Mapstruct hamkasblari o'z mahsulotining foydalanuvchilariga xaritachilarni qanday kiritishni tanlashga imkon berishdi, buning uchun biz ularga minnatdorchilik bildiramiz. LEKIN, Spring loviyani konstruktor orqali in'ektsiya qilishni tavsiya qilganiga qaramay, Mapstruct yigitlari sukut bo'yicha dala orqali in'ektsiyani o'rnatdilar. Nega bunday? Javobsiz. O'ylaymanki, biz bilmagan sabablar bo'lishi mumkin va shuning uchun ular buni shunday qilishdi. Va ulardan bilish uchun men ularning rasmiy mahsulot omborida GitHub muammosini yaratdim.
GO TO FULL VERSION