Résolution de problèmes MapStruct avec ManyToMany



Bonjour chers lecteurs! Ceux qui développent des applications Web en Java en utilisant le framework Spring, ceux qui commentent ces applications et sont simplement intéressés.

Dans un article précédent, «Résolution des problèmes de Spring Boot avec ManyToMany»

J'ai donné un exemple d'une application de test dans laquelle il existe une relation bidirectionnelle ManyToMany entre deux classes. L'article a donné un exemple de résolution du problème de boucle lors de la réception d'une réponse de repos à l'aide de la classe DTO. Les lecteurs dans les commentaires ont suggéré d'utiliser la bibliothèque MapStruct pour résoudre le problème de boucle.

Après avoir examiné la documentation, j'étais convaincu que c'est vraiment une chose puissante, avec laquelle vous pouvez résoudre des tâches assez complexes de déplacement de données entre des objets. MapStruct résout également le problème de bouclage.

Dans cet article, je vais donner un exemple de résolution du même problème qu'une application Spring Boot à l'aide de la bibliothèque MapStruct. Code source disponible sur Github

Entity People et SongPlayers sont restés inchangés. Getters et setters ont baissé.

@Entity public class People { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String human; //      @ManyToOne(cascade = CascadeType.ALL) private RockGroups rockGroups; //     @ManyToMany(mappedBy = "songInstrumentalist",fetch = FetchType.EAGER) private List<SongPlayers> songItems; public People(){} public People(long id, String human){ this.id = id; this.human = human; } //. . . . . } 

 @Entity public class SongPlayers { @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; private String song; //    private String composer; //     private String poet; //    private String album; //   //     @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<People> songInstrumentalist; //. . . . . } 

Nous créons également des interfaces de référentiel pour les classes People et SongPlayers.

 @Repository public interface PeopleRepository extends JpaRepository<People, Long> { @Query("select h from People h where h.human=?1") List<People> searchByHuman(String human); List<People> findPeopleByHuman(String human); } 

 @Repository public interface SongPlayersRepository extends JpaRepository<SongPlayers, Long> { List<SongPlayers> findSongPlayersBySong(String song); List<SongPlayers> findSongPlayersByComposer(String composer); List<SongPlayers> findSongPlayersByPoet(String poet); } 

Nous créons également des classes DTO pour People et SongPlayers, qui ne sont plus aussi encombrantes. Getters et setters je baisse.

 public class PeopleDTO { private long id; private String human; private RockGroups rockGroups; private List<SongPlayersDTO> songPlayersList; // . . . . . } 

 public class SongPlayersDTO { private long id; private String song; private String composer; private String poet; private String album; // . . . . . } 

Pour décrire la règle de transfert des données de l'objet source vers l'objet DTO et, si nécessaire, nous créons des interfaces de mappage pour chaque classe qui nécessite une protection contre les boucles. Voici le PeopleMapper et SongPlayersMapper

 @Mapper(uses = SongPlayersMapper.class) public interface PeopleMapper { PeopleMapper PEOPLE_MAPPER = Mappers.getMapper(PeopleMapper.class); @Mapping(source = "songItems", target = "songPlayersList") PeopleDTO fromPeople(People people); } 

 @Mapper/*(uses = {PeopleMapper.class})*/ public interface SongPlayersMapper { SongPlayersMapper SONG_PLAYERS_MAPPER = Mappers.getMapper(SongPlayersMapper.class); SongPlayersDTO fromSongPlayers(SongPlayers songPlayers); @InheritInverseConfiguration SongPlayers toSongPlayers(SongPlayersDTO songPlayersDTO); } 

Dans le dossier Service, créez les interfaces et l'implémentation des classes de service, dans lesquelles nous mettons les méthodes de réception des données (je vais les donner pour People).

 public interface PeopleService { List<PeopleDTO> getAllPeople(); PeopleDTO getPeopleById(long id); People addPeople(People people); void delPeople(long id); ResponseEntity<Object> updPeople(People people, long id); List<RockGroups> getByHuman(String human); List<String> getSongByHuman(String human); } 

 @Service("peopleservice") public class PeopleServiceImpl implements PeopleService { @Autowired private PeopleRepository repository; @Override public List<PeopleDTO> getAllPeople() { List<PeopleDTO> peopleDTOList = new ArrayList<>(); List<People> peopleList = repository.findAll(); for (People people : peopleList){ peopleDTOList.add(PeopleMapper.PEOPLE_MAPPER.fromPeople(people)); } return peopleDTOList; } // . . . . . } 

Dans les contrôleurs, nous appliquerons ces méthodes en conséquence (là encore uniquement pour les personnes)

 @RestController @RequestMapping("/people") public class PeopleController { @Autowired private PeopleServiceImpl service; @GetMapping("/all") public List<PeopleDTO> getAllPeople(){ return service.getAllPeople(); } // . . . . . } 

De la solution ci-dessus du problème de boucle pour la relation ManyToMany, je peux dire que l'option avec les classes DTO de l'article précédent et la version avec la bibliothèque MapStruct de cet article fonctionnent également. Par rapport à la version précédente, la classe DTO a été considérablement simplifiée, mais des interfaces Mapper ont été ajoutées. En général, n'importe quelle méthode peut être utilisée, pour des cas simples, je serais enclin à la première option.

Je remercie tous les participants à la discussion. En attente de vos commentaires.

Lien vers l'article précédent .

Lien vers le projet sur Github .

Littérature utilisée:

  • Chaussure Felipe Gutierrez Pro Spring
  • Craig Walls Spring in action 5e édition

Source: https://habr.com/ru/post/fr433270/


All Articles