Qui la parte precedente dell’articolo: Creare una web application con Spring Boot, MongoDB, Angular 4 e TypeScript e deployarla in cloud come Microsoft Azure Webapp – Parte 9

CONVERTIRE IL MODEL IN VIEWMODEL

Implementiamo ora la classe che costituirà il nostro converter tra le entità User e i viewmodel UserViewModel. Come sempre, scegliamo un approccio flessibile e sfruttiamo il meccanismo dei Generics per definire una generica interfaccia di conversione tra Model e ViewModel che andremo ad implementare di volta in volta che avremo necessità di convertire le nostre entità in DTO e viceversa.

Aggiungiamo al nostro un progetto un nuovo package che chiamiamo “converters” e, al suo interno, creiamo l’interfaccia IModelViewModelConverter definendola, genericamente, come:

public interface IModelViewModelConverter

All’interno di questa interfaccia una serie di metodi per:

Convertire un oggetto del Model in oggetto del ViewModel

Convertire una lista di oggetti Model in una lista di oggetti ViewModel

Convertire un oggetto ViewModel in un oggetto del Model

Convertire una lista di oggetti ViewModel in una lista di oggetti Model

public interface IModelViewModelConverter { public M fromViewModel(VM vm); public List fromViewModelList(List vmList); public VM toViewModel(M m); public List toViewModelList(List mList); }

L’interfaccia IModelViewModelConverter si presenterà quindi così:



Definita l’interfaccia generics di conversione tra Model e ViewModel, dobbiamo implementare la classe concreta per la conversione del nostro model User nel nostro DTO UserViewModel e viceversa.

Creiamo quindi la classe UserConverter che implementa l’interfaccia IModelViewModelConverter utilizzando come tipi proprio User e UserViewModel

In attesa di implementare il body dei vari metodi, la classe UserConverter si presenterà quindi così:

public class UserConverter implements IModelViewModelConverter { @Override public User fromViewModel(UserViewModel vm) { // TODO Auto-generated method stub return null; } @Override public List fromViewModelList(List vmList) { // TODO Auto-generated method stub return null; } @Override public UserViewModel toViewModel(User m) { // TODO Auto-generated method stub return null; } @Override public List toViewModelList(List mList) { // TODO Auto-generated method stub return null; } }



Iniziamo ad implementare il metodo che ci serve, ovvero quello per la conversione di una lista di User in una lista di UserViewModel. Questo metodo, in realtà, non farà altro che eseguire ciclicamente su ogni oggetto della lista di User il metodo per la conversione del singolo oggetto.

Partiamo quindi da quest’ultimo, che non dovrà far altro che settare le variabili d’istanza dell’oggetto ViewModel a partire da quelle dell’oggetto del Model. Per ora, invochiamo esplicitamente i vari setter; in seguito introdurremo una libreria che ci permetterà di fare questa operazione in automatico, riducendo ancora una volta la necessità di scrivere boilerplate code.

Per il metodo sarà implementato come segue:

@Override public UserViewModel toViewModel(User m) { UserViewModel uvm = new UserViewModel(); uvm.setFirstname(m.getFirstname()); uvm.setLastname(m.getLastname()); uvm.setCountry(m.getCountry()); uvm.setAge(m.getAge()); return uvm; }

A partire da questo, implementiamo facilmente l’analogo metodo che lavora sulle liste di oggetti:

@Override public List toViewModelList(List mList) { List users = new ArrayList<>(); for( User u : mList) users.add(this.toViewModel(u)); return users; }

Ora che abbiamo implementato i nostri converter possiamo tornare al Service e utilizzarli per soddisfare il secondo punto tra le operazioni in carico al metodo getAllUsers().

Per prima cosa, dobbiamo aggiungere un oggetto UserConverter all’interno del nostro UserService, delegandone sempre la gestione via Dependency Injection a Spring, tramite l’annotazione @Autowired.

Per poterlo fare però, dobbiamo prima fare un’ultima modifica alla classe e cioè annotarla con @Component, lo stereotype che indica che la classe rappresenta un bean gestito da Spring.

Modifichiamo quindi la definizione della classe come segue:

@Component public class UserConverter implements IModelViewModelConverter

Purtroppo, non è sufficiente annotare l’interfaccia IModelViewModelConverter per fare ereditare l’annotazione @Component a UserConverter e alle eventuali altre implementazioni concrete, in quanto le annotazioni non si propagano lungo la gerarchia alle sottoclassi o alle implementazioni delle interfacce.

Per poter sfruttare l’ereditarietà dobbiamo definire noi stessi un’annotazione custom, a sua volta annotata con @Component, con cui annotare IModelViewModelConverter. Ci torneremo più avanti e lo faremo, così da vedere anche questo meccanismo, ma non ora.

Ora torniamo a noi e inseriamo la chiamata al metodo toViewModelList() del nostro UserConverter, passandogli come parametro la Lista di User recuperata dal database MongoDB tramite il repository e assegnando il risultato alla lista di ViewModel da ritornare.

Il codice della classe UserService diventa:

@Service public class UserService { @Autowired UserRepository userRepo; @Autowired UserConverter userConv; public List getAllUsers() { List userList = userRepo.findAll(); List users = userConv.toViewModelList(userList); return users; } }

RICHIAMARE IL SERVICE DAL CONTROLLER

Ora che abbiamo implementato il Repository e il Service, non ci resta che richiamare quest’ultimo dal Controller REST che abbiamo implementato in precedenza, in modo che esso possa poi restituire i dati all’applicazione Angular di front-end per la loro visualizzazione in pagina tramite l’opportuno Component (Angular, non Spring).

Torniamo quindi nella classe UserController, dove dichiariamo un oggetto UserService in @Autowired ed eliminiamo la lista di oggetti User che avevamo precedentemente istanziato “a mano” direttamente nel codice.

Sostituiamo la creazione manuale degli oggetti User con la chiamata al metodo getAllUsers() del nostro UserService.

List userList = userService.getAllUsers();

Il contenuto della classe UserController diventa quindi il seguente:

@RestController public class UserController { @Autowired UserService userService; @CrossOrigin(origins = "http://localhost:4200") @RequestMapping(value = "/users", method = { RequestMethod.GET }) public List listAllUsers() { List userList = userService.getAllUsers(); return userList; } }

A questo punto dobbiamo testare la nuova versione della nostra applicazione che continua a mostrare in pagina la lista degli utenti, recuperandoli però ora da un database MongoDB. Prima di eseguire l’applicazione però, dobbiamo alimentare il nostro database che al momento è ancora vuoto.

Non avendo ancora creato una pagina con un form per la sottomissione dei dati relativi ad un nuovo User né, tantomeno, un servizio di back-end per il suo inserimento a database, popoliamo per ora a mano il database MongoDB. Più avanti, creeremo anche la pagina e i servizi per l’inserimento di un nuovo utente.

Per ora, recuperiamo il JSON con la lista di utenti che avevamo ricevuto come risultato dalla chiamata di test precedente, quando il controller ci restituiva i dati “schiantati” al suo interno, e lo utilizziamo per inserire questi oggetti come documenti su MongoDB utilizzando il tool MongoChef (Studio 3T).

Il JSON restituito era il seguente:

[ { firstname: "Davis", lastname: "Molinari", country: "Italy", age: 34 }, { firstname: "Lionel", lastname: "Messi", country: "Argentina", age: 30 }, { firstname: "Jason", lastname: "Bourne", country: "US", age: 30 } ]

Apriamo MongoChef, e connettiamoci all’istanza di MongoDB che stiamo utilizzando tramite la connection configurata e salvata in precedenza. A questo punto dobbiamo creare il database e la collection in cui inserire i nostri oggetti User di test.

Vai alla parte successiva dell’articolo: Creare una web application con Spring Boot, MongoDB, Angular 4 e TypeScript e deployarla in cloud come Microsoft Azure Webapp – Parte 11