Ceci est une ancienne révision du document !
TD n°4
SpringBoot - VueJS
Créer la branche td4 à partir de la branche td3 de votre projet (reprenez éventuellement la correction).
Rest controller
Lire APIs web
Configuration
Ajouter la dépendance Rest Data à pom.xml :
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-rest -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
<version>3.0.4</version>
</dependency>
Configurer l'api REST pour qu'elle expose les identifiants de certaines entities en créant une nouvelle classe de configuration :
@Configuration
class RestConfig:RepositoryRestConfigurer {
override fun configureRepositoryRestConfiguration(config: RepositoryRestConfiguration?, cors: CorsRegistry?) {
config?.exposeIdsFor(Master::class.java, Dog::class.java)
}
}
Création des ressources
Créer une nouvelle interface RestMasterResource héritant de JpaRespository, annotée avec @RestResourceController :
@RepositoryRestResource(collectionResourceRel = "masters", path = "masters")
interface RestMasterResource:JpaRepository<Master, Int> {
}
Même chose pour les Dogs :
@RepositoryRestResource(collectionResourceRel = "dogs", path = "dogs")
interface RestDogResource:JpaRepository<Dog, Int> {
}
Mise à jour des entités
- L'annotation @JsonBackReference sur le champ master de la classe Dog évite la sérialisation JSON infinie des objets liés entre eux.
- L'annotation @RestResource relie le champ master à la ressource correspondante, non exportée (non accessible directement par l'URL).
@Entity
open class Dog() {
constructor(name:String):this(){
this.name=name
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@JsonSerialize
open var id = 0
@Column(length = 30, nullable = false)
open var name: String=""
@ManyToOne(optional = true)
@RestResource(exported = false,rel = "master", path = "master")
@JsonBackReference
open var master: Master?=null
@ManyToMany
open val toys= mutableSetOf<Toy>()
}
Tests de l'api
Tester les requêtes suivantes avec Reqbin
| Méthode | URL | Data | Résultat |
|---|---|---|---|
| Get | /dogs | Liste des chiens | |
| POST | /dogs | {“name”:“Rex”} | Ajout d'un chien |
| PUT | /dogs/1 | {“name”:“Rex”, master: {id: 1}} | Modification complète d'un chien |
| PATCH | /dogs/1 | {“name”:“Rexa”} | Modification partielle d'un chien |
| DELETE | /dogs/1 | Suppression d'un chien |
| Méthode | URL | Data | Résultat |
|---|---|---|---|
| Get | /masters | Liste des maîtres | |
| POST | /masters | {“firstname”:“John”, “lastname”: “DOE”} | Ajout d'un maître |
| PUT | /masters/1 | {“firstname”:“John”, “lastname”: “DOE”} | Modification complète d'un maître |
| PATCH | /masters/1 | {“firstname”:“Johnny”} | Modification partielle d'un maître |
| DELETE | /masters/1 | Suppression d'un maître |
SPA VueJS
Intégration
Ajouter la dépendance Springboot-vuejs dans pom.xml :
<dependency>
<groupId>io.github.jeemv.springboot.vuejs</groupId>
<artifactId>springboot-vuejs</artifactId>
<version>1.1.4</version>
</dependency>
Ajouter une classe de configuration pour permettre l'injection des instances de VueJS :
@Configuration
@ComponentScan("io.github.jeemv.springboot.vuejs")
class AppConfig {
}
Ajouter la configuration suivante dans application.properties :
##vuejs
springboot.vuejs.delimiters={!,!}
springboot.vuejs.axios=true
springboot.vuejs.el=#app
springboot.vuejs.vuetify=false
springboot.vuejs.vue-version=3.*
Injection dans un contrôleur
Créer un contrôleur SPAController :
@Controller
class SPAController {
@Autowired
lateinit var vue: VueJS
@ModelAttribute("vue")
fun vue(): VueJS = vue
}
Chargement et affichage de données
Chargement des masters côté client
Les données seront chargées lorsque l'objet vueJs est mounted, par une requête Ajax de type GET, alimentant le tableau this.masters :
@Controller
@RequestMapping("/spa")
class SPAController {
@Autowired
lateinit var vue: VueJS
@ModelAttribute("vue")
fun vue(): VueJS = vue
@GetMapping(path = ["/","","/index"])
fun index(): String {
vue.adddataRaw("masters", "[]")
vue.onMounted(
Http.get("/masters",
JsArray.addAll("this.masters","response.data._embedded.masters"),
"console.log('Erreur sur chargement des données!');"
)
return "/spa/index"
}
}
Template /spa/index.html :
<h1>Maîtres</h1>
<ul>
<li v-for="master in masters">
{!master.firstname!} {!master.lastname!}
</li>
</ul>
Chargement des masters côté côté serveur
- Injecter le repository des masters
- Passer à l'instance de vue la liste des masters
@Controller
@RequestMapping("/spa")
class SPAController {
@Autowired
lateinit var masterRepository: MasterRepository
@Autowired
lateinit var vue: VueJS
@ModelAttribute("vue")
fun vue(): VueJS = vue
@GetMapping(path = ["/","","/index"])
fun index(): String {
vue.addData("masters", masterRepository.findAll())
return "/spa/index"
}
}