JavaRush /Java блогы /Random-KK /Mapstruct дегеніміз не және оны SpringBoot қолданбаларынд...
Roman Beekeeper
Деңгей

Mapstruct дегеніміз не және оны SpringBoot қолданбаларында бірлік сынағы үшін қалай дұрыс конфигурациялау керек

Топта жарияланған

Фон

Баршаңызға сәлем, құрметті достарым және оқырмандарым! Мақаланы жазбас бұрын, қысқаша мәлімет... Жақында мен Mapstruct кітапханасымен жұмыс істеу мәселесіне тап болдым, ол туралы телеграм каналымда қысқаша сипаттадым . Түсініктемелерде постқа қатысты мәселе шешілді, бұған алдыңғы жобадағы әріптесім көмектесті. Mapstruct дегеніміз не және оны SpringBoot қолданбаларында бірлік сынағы үшін қалай дұрыс конфигурациялау керек.  1 - 1 бөлімОсыдан кейін мен осы тақырып бойынша мақала жазуды шештім, бірақ біз, әрине, тар көзқарасты қабылдамаймыз және алдымен жылдамдыққа жетуге тырысамыз, Mapstruct деген не және ол не үшін қажет екенін түсінеміз және нақты мысалды қолданамыз. бұрын туындаған жағдайды және оны шешу жолдарын талдау. Сондықтан, мен бәрін тәжірибеде сезіну үшін мақаланы оқумен қатар барлық есептеулерді орындауды ұсынамын. Бастамас бұрын, менің телеграм каналыма жазылыңыз , мен онда өз әрекеттерімді жинаймын, Java және жалпы IT-дағы даму туралы ойлар жазамын. Жазылдыңыз ба? Тамаша! Ал, енді кеттік!

Mapstruct, жиі қойылатын сұрақтар?

Жылдам типті қауіпсіз бұршақ салыстыруларына арналған code генераторы. Біздің бірінші міндетіміз Mapstruct деген не екенін және оның бізге не үшін қажет екенін анықтау. Жалпы, бұл туралы ресми сайттан оқуға болады. Сайттың негізгі бетінде сұрақтарға үш жауап бар: бұл не? Не үшін? Қалай? Біз мұны да жасауға тырысамыз:

Бұл не?

Mapstruct — интерфейстер арқылы сипатталған конфигурациялар негізінде жасалған codeты пайдалана отырып, кейбір нысандардың нысандарын басқа нысандардың an objectілеріне салыстыруға (карта, жалпы алғанда, олар әрқашан осылай дейді: карта, карта және т.б.) көмектесетін кітапхана.

Не үшін?

Көбінесе біз көп деңгейлі қосымшаларды әзірлейміз (деректер қорымен жұмыс істеу қабаты, бизнес-логика қабаты, қолданбаның сыртқы әлеммен әрекеттесу қабаты) және әрбір қабатта деректерді сақтауға және өңдеуге арналған өз нысандары бар. . Және бұл деректерді бір нысаннан екіншісіне тасымалдау арқылы қабаттан қабатқа тасымалдау қажет. Бұл тәсілмен жұмыс істемегендер үшін бұл біршама күрделі болып көрінуі мүмкін. Мысалы, бізде Студенттік дерекқорға арналған нысан бар. Бұл нысанның деректері бизнес логикасы (қызметтері) деңгейіне өткенде, біз Студент сыныбынан StudentModel сыныбына деректерді тасымалдауымыз керек. Әрі қарай, бизнес логикасы бар барлық манипуляциялардан кейін деректерді сыртқа шығару керек. Бұл үшін бізде StudentDto сыныбы бар. Әрине, біз StudentModel сыныбынан StudentDto-ға деректерді беруіміз керек. Ауыстырылатын әдістерді қолмен жазу көп еңбекті қажет етеді. Оған қоса, бұл code базасында сақталуы қажет қосымша code. Сіз қате жібере аласыз. Mapstruct мұндай әдістерді компиляция сатысында жасайды және оларды жасалған көздерде сақтайды.

Қалай?

Аннотацияларды пайдалану. Бізге кітапханаға осы интерфейстегі әдістерді бір нысаннан екіншісіне аудару үшін пайдалануға болатынын айтатын негізгі Mapper annotationсы бар annotation жасау керек. Студенттер туралы бұрын айтқанымдай, біздің жағдайда бұл StudentMapper интерфейсі болады, онда деректерді бір қабаттан екінші қабатқа тасымалдаудың бірнеше әдістері болады:
public class Student {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}

public class StudentDTO {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}

public class StudentModel {
   private Long id;
   private String firstName;
   private String lastName;
   private Integer age;
}
Бұл сыныптар үшін біз карта жасаушыны жасаймыз (бұдан әрі біз нені және қайда тасымалдағымыз келетінін сипаттайтын интерфейс деп атаймыз):
@Mapper
public interface StudentMapper {
   StudentModel toModel(StudentDTO dto);
   Student toEntity(StudentModel model);
   StudentModel toModel(Student entity);
   StudentDTO toDto(StudentModel model);
}
Бұл тәсілдің сұлулығы мынада, егер өрістердің атаулары мен түрлері әртүрлі класстарда бірдей болса (біздің жағдайымыздағыдай), онда Mapstruct параметрлері компиляция сатысында StudentMapper интерфейсі негізінде қажетті іске асыруды генерациялау үшін жеткілікті, ол аударатын болады. Демек, бұл түсінікті болды, солай ма? Әрі қарай барып, Spring Boot қолданбасындағы жұмысты талдау үшін нақты мысалды қолданайық.

Spring Boot және Mapstruct жұмысының мысалы

Бізге қажет бірінші нәрсе - Spring Boot жобасын жасау және оған Mapstruct қосу. Бұл мәселе бойынша менде GitHub-та репозиторийлерге арналған үлгілері бар ұйым бар және Spring Boot бастауы солардың бірі болып табылады. Оның негізінде біз жаңа жобаны жасаймыз: Келесі, біз жобаныMapstruct дегеніміз не және оны SpringBoot қолданбаларында бірлік сынағы үшін қалай дұрыс конфигурациялау керек.  1-2 бөлім аламыз . Иә, достар, жобаны пайдалы деп тапсаңыз, жұлдызша беріңіз , сондықтан мен мұны бекер жасап жатқан жоқпын. Бұл жобада біз жұмыста алған және Telegram арнамдағы постта сипатталған жағдайды ашамыз . Мен білмейтіндер үшін жағдайды қысқаша сипаттаймын: біз карта жасаушыларға арналған сынақтарды жазғанда (яғни, біз бұрын айтқан интерфейсті іске асыру үшін) сынақтардың мүмкіндігінше тез өткенін қалаймыз. Маперлермен ең қарапайым опция сынақты іске қосу кезінде SpringBootTest annotationсын пайдалану болып табылады, ол Spring Boot қолданбасының барлық ApplicationContext мәтінін таңдайды және сынақ ішінде сынақ үшін қажетті салыстырғышты енгізеді. Бірақ бұл опция ресурсты қажет етеді және әлдеқайда көп уақытты алады, сондықтан ол бізге жарамайды. Біз жай ғана қажетті карта жасаушыны жасайтын және оның әдістері біз күткендей жұмыс істейтінін тексеретін бірлік сынамасын жазуымыз керек. Неліктен жылдамырақ жұмыс істеу үшін сынақтар қажет? Егер сынақтар ұзақ уақытқа созылса, ол бүкіл даму процесін баяулатады. Тесттер жаңа codeты бермейінше, бұл codeты дұрыс деп санауға болмайды және тестілеуге қабылданбайды, яғни ол өндіріске қабылданбайды және әзірлеуші ​​жұмысты аяқтамағанын білдіреді. Жұмысы күмән тудырмайтын кітапханаға тест жазудың қажеті қанша? Дегенмен, біз тест жазуымыз керек, өйткені біз карта жасаушыны қаншалықты дұрыс сипаттағанымызды және оның біз күткенді орындайтынын тексереміз. Ең алдымен, жұмысымызды жеңілдету үшін pom.xml файлына басқа тәуелділікті қосу арқылы жобамызға Lombok қосамыз:
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <scope>provided</scope>
</dependency>
Біздің жобамызда біз модельдік сыныптардан (бизнес логикасымен жұмыс істеу үшін пайдаланылады) сыртқы әлеммен байланысу үшін қолданатын DTO сыныптарына көшуіміз керек. Жеңілдетілген нұсқамызда өрістер өзгермейді және біздің карта жасаушылар қарапайым болады деп есептейміз. Бірақ, егер тілек болса, Mapstruct-пен қалай жұмыс істеу керек, оны қалай конфигурациялау керек және оның артықшылықтарын қалай пайдалану керектігі туралы толығырақ мақала жазуға болады. Бірақ содан кейін, өйткені бұл мақала өте ұзақ болады. Бізде ол қатысатын дәрістер мен лекторлардың тізімі бар студент бар делік. Үлгі пакетін жасайық . Осыған сүйене отырып, біз қарапайым модель жасаймыз:
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

import java.util.List;

@Data
public class StudentDTO {

   private Long id;

   private String name;

   private List<LectureDTO> lectures;

   private List<LecturerDTO> lecturers;
}
оның лекциялары
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LectureDTO {

   private Long id;

   private String name;
}
және лекторлар
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LecturerDTO {

   private Long id;

   private String name;
}
Үлгі бумасының жанында dto бумасын жасаңыз :
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

import java.util.List;

@Data
public class StudentDTO {

   private Long id;

   private String name;

   private List<LectureDTO> lectures;

   private List<LecturerDTO> lecturers;
}
дәрістер
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LectureDTO {

   private Long id;

   private String name;
}
және лекторлар
package com.github.romankh3.templaterepository.springboot.dto;

import lombok.Data;

@Data
public class LecturerDTO {

   private Long id;

   private String name;
}
Енді лекция үлгілерінің жинағын DTO лекцияларының жинағына аударатын карта жасаушыны жасайық. Ең алдымен жобаға Mapstruct қосу керек. Мұны істеу үшін біз олардың ресми сайтын қолданамыз , бәрі сонда сипатталған. Яғни, біз жадымызға бір тәуелділік пен плагинді қосуымыз керек (егер жад деген не туралы сұрақтарыңыз болса, 1-бап және 2-бап ):
<dependency>
   <groupId>org.mapstruct</groupId>
   <artifactId>mapstruct</artifactId>
   <version>1.4.2.Final</version>
</dependency>
және <Build/> блогындағы жадта. бізде әлі болмаған:
<build>
   <plugins>
       <plugin>
           <groupId>org.apache.maven.plugins</groupId>
           <artifactId>maven-compiler-plugin</artifactId>
           <version>3.5.1</version>
           <configuration>
               <source>1.8</source>
               <target>1.8</target>
               <annotationProcessorPaths>
                   <path>
                       <groupId>org.mapstruct</groupId>
                       <artifactId>mapstruct-processor</artifactId>
                       <version>1.4.2.Final</version>
                   </path>
               </annotationProcessorPaths>
           </configuration>
       </plugin>
   </plugins>
</build>
Әрі қарай, dto және model жанынан карташы бумасын жасайық . Біз бұрын көрсеткен сыныптарға сүйене отырып, сізге тағы бес карта жасаушы қажет болады:
  • Mapper LectureModel <-> LectureDTO
  • Mapper List<LectureModel> <-> List<LectureDTO>
  • Маппер Дәріс берушіМодель <-> ДТО оқытушысы
  • Mapper List<LecturerModel> <-> List<LecturerDTO>
  • Mapper StudentModel <-> StudentDTO
Бару:

LectureMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface LectureMapper {
   LectureDTO toDTO(LectureModel model);

   LectureModel toModel(LecturerDTO dto);
}

LectureListMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

import java.util.List;

@Mapper(componentModel = "spring", uses = LectureMapper.class)
public interface LectureListMapper {
   List<LectureModel> toModelList(List<LectureDTO> dtos);
   List<LectureDTO> toDTOList(List<LectureModel> models);
}

Дәріс беруші

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring")
public interface LectureMapper {
   LectureDTO toDTO(LectureModel model);

   LectureModel toModel(LectureDTO dto);
}

LecturerListMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LecturerDTO;
import com.github.romankh3.templaterepository.springboot.model.LecturerModel;
import org.mapstruct.Mapper;

import java.util.List;

@Mapper(componentModel = "spring", uses = LecturerMapper.class)
public interface LecturerListMapper {
   List<LecturerModel> toModelList(List<LecturerDTO> dloList);
   List<LecturerDTO> toDTOList(List<LecturerModel> modelList);
}

StudentMapper

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.StudentDTO;
import com.github.romankh3.templaterepository.springboot.model.StudentModel;
import org.mapstruct.Mapper;

@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
public interface StudentMapper {
   StudentDTO toDTO(StudentModel model);
   StudentModel toModel(StudentDTO dto);
}
Мапперлерде біз басқа бейнелеушілерге сілтеме жасайтынымызды бөлек атап өту керек. Бұл StudentMapper қолданбасында орындалғандай, Mapper annotationсындағы uses өрісі арқылы орындалады:
@Mapper(componentModel = "spring", uses = {LectureListMapper.class, LecturerListMapper.class})
Мұнда лекциялар тізімі мен лекторлар тізімін дұрыс картаға түсіру үшін екі мапперді қолданамыз. Енді біз codeты құрастырып, не және қалай бар екенін көруіміз керек. Мұны mvn clean compile командасы арқылы жасауға болады . Бірақ, белгілі болғандай, біздің карта жасаушылардың Mapstruct іске асыруларын жасаған кезде, картаның іске асырулары өрістерді қайта жазбаған. Неліктен? Ломбоктан Data annotationсын алу мүмкін емес екені белгілі болды. Және бірдеңе істеу керек еді... Сондықтан мақалада жаңа бөлім бар.

Lombok және Mapstruct байланыстыру

Бірнеше minutesтық іздеулерден кейін бізге Lombok пен Mapstruct-ті белгілі бір жолмен қосу керек болды. Бұл туралы ақпарат Mapstruct құжаттамасында бар . Mapstruct әзірлеушілері ұсынған мысалды зерттегеннен кейін, pom.xml файлын жаңартайық: Бөлек нұсқаларды қосамыз:
​​<properties>
   <org.mapstruct.version>1.4.2.Final</org.mapstruct.version>
   <lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
Жетіспейтін тәуелділікті қосамыз:
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok-mapstruct-binding</artifactId>
   <version>${lombok-mapstruct-binding.version}</version>
</dependency>
Lombok пен Mapstruct-ті қоса алатындай етіп компилятор плагинін жаңартайық:
<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-compiler-plugin</artifactId>
   <version>3.5.1</version>
   <configuration>
       <source>1.8</source>
       <target>1.8</target>
       <annotationProcessorPaths>
           <path>
               <groupId>org.mapstruct</groupId>
               <artifactId>mapstruct-processor</artifactId>
               <version>${org.mapstruct.version}</version>
           </path>
           <path>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <version>${lombok.version}</version>
           </path>
           <path>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok-mapstruct-binding</artifactId>
               <version>${lombok-mapstruct-binding.version}</version>
           </path>
       </annotationProcessorPaths>
   </configuration>
</plugin>
Осыдан кейін бәрі ойдағыдай болуы керек. Жобамызды қайтадан құрастырайық. Бірақ Mapstruct жасаған сыныптарды қайдан табуға болады? Олар генерацияланған көздерде: ${projectDir}/target/generated-sources/annotations/ Mapstruct дегеніміз не және оны SpringBoot қолданбаларында бірлік сынағы үшін қалай дұрыс конфигурациялау керек.  1 - 3 бөлім Mapstruct жазбасынан көңілі қалғанымды түсінуге дайынбыз, енді карта жасаушылар үшін сынақтар жасап көрейік.

Біз карта жасаушыларымызға тест жазамыз

Мен интеграциялық тест жасап жатқан жағдайда карта жасаушылардың бірін сынайтын жылдам және қарапайым сынақ жасаймын және оның аяқталу уақыты туралы алаңдамаңыз:

LectureMapperTest

package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class LectureMapperTest {

   @Autowired
   private LectureMapper mapperUnderTest;

   @Test
   void shouldProperlyMapModelToDto() {
       //given
       LectureModel model = new LectureModel();
       model.setId(11L);
       model.setName("lecture name");

       //when
       LectureDTO dto = mapperUnderTest.toDTO(model);

       //then
       Assertions.assertNotNull(dto);
       Assertions.assertEquals(model.getId(), dto.getId());
       Assertions.assertEquals(model.getName(), dto.getName());
   }

   @Test
   void shouldProperlyMapDtoToModel() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(11L);
       dto.setName("lecture name");

       //when
       LectureModel model = mapperUnderTest.toModel(dto);

       //then
       Assertions.assertNotNull(model);
       Assertions.assertEquals(dto.getId(), model.getId());
       Assertions.assertEquals(dto.getName(), model.getName());
   }
}
Мұнда SpringBootTest annotationсын қолдана отырып, біз бүкіл applicationContext бағдарламасын іске қосамыз және одан Autowired annotationсын пайдаланып, тестілеуге қажетті классты шығарамыз. Тест жазудың жылдамдығы мен жеңілдігі тұрғысынан бұл өте жақсы. Сынақ сәтті өтті, бәрі жақсы. Бірақ біз басқа жолмен жүреміз және карта жасаушы үшін бірлік сынағын жазамыз, мысалы, LectureListMapper...
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;

class LectureListMapperTest {

   private final LectureListMapper lectureListMapper = new LectureListMapperImpl();

   @Test
   void shouldProperlyMapListDtosToListModels() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(12L);
       dto.setName("I'm BATMAN!");

       List<LectureDTO> dtos = Collections.singletonList(dto);

       //when
       List<LectureModel> models = lectureListMapper.toModelList(dtos);

       //then
       Assertions.assertNotNull(models);
       Assertions.assertEquals(1, models.size());
       Assertions.assertEquals(dto.getId(), models.get(0).getId());
       Assertions.assertEquals(dto.getName(), models.get(0).getName());
   }
}
Mapstruct жасайтын іске асырулар жобамызбен бір сыныпта болғандықтан, біз оларды сынақтарымызда оңай пайдалана аламыз. Барлығы керемет көрінеді - annotationлар жоқ, біз ең қарапайым түрде қажет классты жасаймыз және солай. Бірақ сынақты орындаған кезде біз оның бұзылатынын және консольде NullPointerException болатынын түсінеміз... Себебі LectureListMapper салыстырушысының іске асырылуы келесідей көрінеді:
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Generated(
   value = "org.mapstruct.ap.MappingProcessor",
   date = "2021-12-09T21:46:12+0300",
   comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {

   @Autowired
   private LectureMapper lectureMapper;

   @Override
   public List<LectureModel> toModelList(List<LectureDTO> dtos) {
       if ( dtos == null ) {
           return null;
       }

       List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
       for ( LectureDTO lectureDTO : dtos ) {
           list.add( lectureMapper.toModel( lectureDTO ) );
       }

       return list;
   }

   @Override
   public List<LectureDTO> toDTOList(List<LectureModel> models) {
       if ( models == null ) {
           return null;
       }

       List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
       for ( LectureModel lectureModel : models ) {
           list.add( lectureMapper.toDTO( lectureModel ) );
       }

       return list;
   }
}
Егер NPE (NullPointerException сөзінің қысқасы) қарасақ, біз оны lectureMapper айнымалысынан аламыз , ол инициализацияланбаған болып шығады. Бірақ біздің іске асыруда бізде айнымалыны инициализациялай алатын конструктор жоқ. Mapstruct карта жасаушыны осылай іске асырғанының себебі осы! Көктемде сабақтарға бұршақтарды бірнеше жолмен қосуға болады, оларды жоғарыда орындалғандай Autowired annotationсымен бірге өріс арқылы енгізуге болады немесе конструктор арқылы енгізуге болады. Тестті орындау уақытын оңтайландыру қажет болғанда мен жұмыста осындай проблемалық жағдайға тап болдым. Мен мұнымен ештеңе істей алмаймын деп ойлап, Telegram каналыма мұңымды төгіп тастадым. Содан кейін олар маған түсініктемелерде көмектесті және инъекция стратегиясын теңшеуге болатынын айтты. Mapper интерфейсінде екі мәні бар InjectionStrategy атауын қабылдайтын injectionStrategy өрісі бар: FIELD және CONSTRUCTOR . Енді, мұны біле отырып, бұл параметрді карташыларға қосамыз; мен оны мысал ретінде LectureListMapper арқылы көрсетемін :
@Mapper(componentModel = "spring", uses = LectureMapper.class, injectionStrategy = InjectionStrategy.CONSTRUCTOR)
public interface LectureListMapper {
   List<LectureModel> toModelList(List<LectureDTO> dtos);
   List<LectureDTO> toDTOList(List<LectureModel> models);
}
Мен қосылған бөлікті қою қаріппен белгіледім. Осы опцияны барлық қалғандары үшін қосып, жобаны қайта құрастырайық, осылайша карта жасаушылар жаңа жолмен жасалады. Бұл әрекетті орындағаннан кейін, LectureListMapper үшін картаны іске асырудың қалай өзгергенін көрейік (бізге қажет бөлік қою қаріппен белгіленген):
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.Generated;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Generated(
   value = "org.mapstruct.ap.MappingProcessor",
   date = "2021-12-09T22:25:37+0300",
   comments = "version: 1.4.2.Final, compiler: javac, environment: Java 15.0.2 (N/A)"
)
@Component
public class LectureListMapperImpl implements LectureListMapper {

   private final LectureMapper lectureMapper;

   @Autowired
   public LectureListMapperImpl(LectureMapper lectureMapper) {

       this.lectureMapper = lectureMapper;
   }

   @Override
   public List<LectureModel> toModelList(List<LectureDTO> dtos) {
       if ( dtos == null ) {
           return null;
       }

       List<LectureModel> list = new ArrayList<LectureModel>( dtos.size() );
       for ( LectureDTO lectureDTO : dtos ) {
           list.add( lectureMapper.toModel( lectureDTO ) );
       }

       return list;
   }

   @Override
   public List<LectureDTO> toDTOList(List<LectureModel> models) {
       if ( models == null ) {
           return null;
       }

       List<LectureDTO> list = new ArrayList<LectureDTO>( models.size() );
       for ( LectureModel lectureModel : models ) {
           list.add( lectureMapper.toDTO( lectureModel ) );
       }

       return list;
   }
}
Енді Mapstruct конструктор арқылы маппер инъекциясын жүзеге асырды. Біз дәл осы мақсатқа жетуге тырыстық. Енді біздің тест құрастыруды тоқтатады, оны жаңартып, алайық:
package com.github.romankh3.templaterepository.springboot.mapper;

import com.github.romankh3.templaterepository.springboot.dto.LectureDTO;
import com.github.romankh3.templaterepository.springboot.model.LectureModel;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.util.Collections;
import java.util.List;

class LectureListMapperTest {

   private final LectureListMapper lectureListMapper = new LectureListMapperImpl(new LectureMapperImpl());

   @Test
   void shouldProperlyMapListDtosToListModels() {
       //given
       LectureDTO dto = new LectureDTO();
       dto.setId(12L);
       dto.setName("I'm BATMAN!");

       List<LectureDTO> dtos = Collections.singletonList(dto);

       //when
       List<LectureModel> models = lectureListMapper.toModelList(dtos);

       //then
       Assertions.assertNotNull(models);
       Assertions.assertEquals(1, models.size());
       Assertions.assertEquals(dto.getId(), models.get(0).getId());
       Assertions.assertEquals(dto.getName(), models.get(0).getName());
   }
}
Енді тестті орындасақ, бәрі күткендей жұмыс істейді, өйткені LectureListMapperImpl бағдарламасында біз оған қажет LectureMapper тапсырамыз... Жеңіс! Бұл сізге қиын емес, бірақ мен ризамын: Достар, бәрі әдеттегідей, менің GitHub аккаунтыма , Telegram аккаунтыма жазылыңыз . Онда мен өз іс-әрекеттерімнің нәтижелерін жариялаймын, шынымен де пайдалы нәрселер бар) Мен сізді әсіресе телеграм каналының пікірталас тобына қосылуға шақырамын . Егер біреудің техникалық сұрағы болса, сол жерден жауап ала алатындай болады. Бұл формат барлығына қызық, кім не білетінін оқып, тәжірибе жинақтай аласыз.

Қорытынды

Осы мақаланың аясында біз Mapstruct сияқты қажетті және жиі қолданылатын өніммен таныстық. Біз оның не екенін, неге және қалай екенін анықтадық. Нақты мысалды қолдана отырып, біз не істеуге болатынын және оны қалай өзгертуге болатынын сезіндік. Біз сондай-ақ конструктор арқылы бұршақты инъекциялауды қалай орнату керектігін қарастырдық, осылайша карта жасаушыларды дұрыс сынауға болады. Mapstruct әріптестері өз өнімін пайдаланушыларға карта жасаушыларды қалай енгізу керектігін таңдауға мүмкіндік берді, бұл үшін біз оларға алғысымыз шексіз. БІРАҚ, Spring конструктор арқылы бұршақтарды инъекциялауды ұсынғанына қарамастан, Mapstruct жігіттері әдепкі бойынша өріс арқылы инъекцияны орнатқан. Неге бұлай? Жауап жоқ. Менің ойымша, біз білмейтін себептер болуы мүмкін, сондықтан олар осылай жасады. Олардан білу үшін мен олардың ресми өнім репозиторийінде GitHub мәселесін жасадым.
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION