Avec le développement rapide de la technologie Internet, les besoins d'informatisation du secteur touristique sont de plus en plus importants. Les méthodes traditionnelles d'obtention d'informations touristiques dépendent des recommandations manuelles ou des documents papier, présentant des problèmes tels que l'obsolescence des informations et un manque de personnalisation. Les planificateurs de voyages doivent souvent intégrer des données de plusieurs plateformes, ce qui réduit l'efficacité. Sur la base de ce contexte, le développement d'une plateforme intelligente intégrant la recherche d'informations touristiques, la planification d'itinéraires et les interactions utilisateur revêt une importance considérable. Cette plateforme fournit des services de guide touristique en temps réel et précis aux utilisateurs en intégrant les données des ressources touristiques, améliorant ainsi l'expérience de voyage.
Ce système adopte une architecture de séparation front-end/back-end. Le back-end est basé sur le framework SpringBoot pour un traitement de données efficace et une gestion d'interfaces, tandis que le front-end utilise Vue.js pour construire une interface d'interaction dynmaique. La base de données MySQL est utilisée pour stocker les informations touristiques et les données utilisateur. Les fonctions du système incluent l'inscription et la connexion des utilisateurs, la recherche d'informations sur les attractions, la planification d'itinéraires, les commentaires et interactions, etc., avec un support pour le filtrage multi-critères et les recommandations personnalisées. L'interaction de données entre le front-end et le back-end est réalisée via des API RESTful, combinée à la technologie JWT pour garantir la sécurité des informations utilisateur.
Conception des tables de base de données
Table des informations utilisateur
La table des informations utilisateur stocke les informations de base des utilisateurs inscrits sur la plateforme. L'ID utilisateur est la clé primaire de cette table, et l'heure d'inscription est générée automatiquement par une fonction. La structure est présentée dans le tableau 3-1.
| Nom du champ | Type de données | Description |
|---|---|---|
| utilisateur_id | BIGINT | Identifiant unique de l'utilisateur (clé primaire) |
| pseudo | VARCHAR(50) | Pseudonyme de l'utilisateur |
| VARCHAR(100) | Adresse e-mail de l'utilisateur | |
| mot_de_passe_hash | VARCHAR(255) | Valeur de hachage du mot de passe |
| date_inscription | DATETIME | Date et heure d'inscription |
| derniere_connexion | DATETIME | Date et heure de la dernière connexion |
| url_avatar | VARCHAR(255) | Lien vers l'avatar de l'utilisateur |
Table des informations sur les attractions
La table des informations sur les attractions stocke les données détaillées des sites touristiques. L'ID de l'attraction est la clé primaire de cette table, et l'heure de création est obtenue automatiquement par une fonction. La structure est présentée dans le tableau 3-2.
| Nom du champ | Type de données | Description |
|---|---|---|
| attraction_id | BIGINT | Identifiant unique de l'attraction (clé primaire) |
| nom_attraction | VARCHAR(100) | Nom de l'attraction |
| localisation | VARCHAR(100) | Position géographique |
| description | TEXT | Description de l'attraction |
| prix_billet | DECIMAL(10,2) | Prix du billet d'entrée |
| horaires_ouverture | VARCHAR(50) | Horaires d'ouverture |
| date_creation | DATETIME | Date de création de l'enregistrement |
| image_couverture | VARCHAR(255) | Lien vers l'image de couverture |
Table de planification d'itinéraire
La table de planification d'itinéraire stocke les informations d'itinéraire personnalisées par les utilisateurs. L'ID de l'itinéraire est la clé primaire de cette table, liée à l'ID utilisateur et à l'ID de l'attraction. La structure est présentée dans le tableau 3-3.
| Nom du champ | Type de données | Description |
|---|---|---|
| itineraire_id | BIGINT | Identifiant unique de l'itinéraire (clé primaire) |
| utilisateur_id | BIGINT | ID utilisateur associé |
| attraction_id | BIGINT | ID de l'attraction associée |
| date_visite | DATE | Date prévue pour la visite |
| notes | TEXT | Notes sur l'itinéraire |
| date_creation | DATETIME | Date de création |
| date_maj | DATETIME | Date de la dernière mise à jour |
Introduction au système
Cette plateforme de guide touristique est développée en utilisant SpringBoot pour le back-end, Vue.js pour le front-end, et MySQL pour la base de données. Le système inclut des fonctionnalités complètes telles que l'inscription et la connexion des utilisateurs, la recherche et la visualisation des attractions, la planification personnailsée d'itinéraires, et des fonctionnalités sociales comme les commentaires et les évaluations. L'architecture adoptée permet une séparation claire entre les préoccupations front-end et back-end, facilitant ainsi le développement et la maintenance.
Stack technologique
Technologie back-end : Spring Boot
Spring Boot, en tant que framework central pour le développement d'entreprise moderne en Java, a redéfini le modèle de développement d'applications avec sa philosophie de conception "convention sur configuration".
Caractéristiques principales :
- Démarrage sans configuration : mécanisme d'auto-configuration intégré, réduisant considérablement la rédaction de fichiers de configuration XML
- Serveurs embarqués : intégration de Tomcat/Jetty/Undertow, supportant le déploiement via un fichier JAR autonome
- Prêt pour la production : composant de surveillance Actuator intégré, fournissant des fonctions d'entreprise telles que les vérifications de santé et la collecte de métriques
- Amitié avec les microservices : support naturel de l'architecture distribuée, intégration transparente avec l'écosystème Spring Cloud
Avantages de développement :
Grâce au système de dépendances Starter et à l'assemblage automatique intelligent, les développeurs peuvent se concentrer entièrement sur la réalisation de la logique métier plutôt que sur la mise en place des infrastructures de base. Le mode de déploiement d'un seul fichier JAR exécutable simplifie considérablement les processus d'exploitation et de maintenance.
Technologie front-end : Vue.js
Vue.js, avec son design de framework progressif et son excellent expérience de développement, est devenu la solution de choix pour le développement front-end moderne.
Points forts techniques :
- Flux de données réactif : système réactif basé sur le suivi des dépendances, réalisant des mises à jour de vue efficaces
- Architecture en composants : design de composants en fichier unique (SFC), réalisant une encapsulation parfaite des styles, de la logique et des modèles
- Design progressif flexible : peut s'étendre d'une simple bibliothèque de couche de vue à une solution SPA complète
- Écosystème riche : chaîne d'outils officielle complète avec Vue Router, Vuex/Pinia, Vue CLI, etc.
Efficacité de développement :
La syntaxe de template intuitive combinée à un système d'instructions puissant permet de rendre les interactions utilisateur complexes simples et claires. Un excellent support TypeScript et des outils de développement offrent une fiabilité solide pour les grands projets.
Code principal
package com.application.tourisme;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
@MapperScan(basePackages = {"com.application.tourisme.mapper"})
public class ApplicationTouristique extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(ApplicationTouristique.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
return applicationBuilder.sources(ApplicationTouristique.class);
}
}
package com.application.tourisme.controller;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Date;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import com.application.tourisme.utils.ValidatorUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.annotation.IgnoreAuth;
import com.application.tourisme.entity.UtilisateurEntity;
import com.application.tourisme.entity.view.UtilisateurVue;
import com.application.tourisme.service.UtilisateurService;
import com.application.tourisme.service.ServiceToken;
import com.application.tourisme.utils.PageUtils;
import com.application.tourisme.utils.R;
import com.application.tourisme.utils.MPUtil;
import com.application.tourisme.utils.MapUtils;
import com.application.tourisme.utils.CommonUtil;
import java.io.IOException;
/**
* Contrôleur pour la gestion des utilisateurs
* Interface back-end
* @author
* @email
* @date 2024-04-24 17:59:31
*/
@RestController
@RequestMapping("/utilisateur")
public class UtilisateurController {
@Autowired
private UtilisateurService utilisateurService;
@Autowired
private ServiceToken serviceToken;
/**
* Connexion
*/
@IgnoreAuth
@RequestMapping(value = "/connexion")
public R connexion(String pseudo, String motDePasse, String captcha, HttpServletRequest request) {
UtilisateurEntity u = utilisateurService.selectOne(new EntityWrapper<utilisateurentity>().eq("pseudo", pseudo));
if(u==null || !u.getMotDePasse().equals(motDePasse)) {
return R.error("Pseudo ou mot de passe incorrect");
}
String token = serviceToken.genererToken(u.getId(), pseudo,"utilisateur", "Utilisateur" );
return R.ok().put("token", token);
}
/**
* Inscription
*/
@IgnoreAuth
@RequestMapping("/inscription")
public R inscription(@RequestBody UtilisateurEntity utilisateur){
//ValidatorUtils.validateEntity(utilisateur);
UtilisateurEntity u = utilisateurService.selectOne(new EntityWrapper<utilisateurentity>().eq("pseudo", utilisateur.getPseudo()));
if(u!=null) {
return R.error("Cet utilisateur existe déjà");
}
Long uId = new Date().getTime();
utilisateur.setId(uId);
utilisateurService.insert(utilisateur);
return R.ok();
}
/**
* Déconnexion
*/
@RequestMapping("/deconnexion")
public R deconnexion(HttpServletRequest request) {
request.getSession().invalidate();
return R.ok("Déconnexion réussie");
}
/**
* Obtenir les informations de l'utilisateur de la session
*/
@RequestMapping("/session")
public R getUtilisateurSession(HttpServletRequest request){
Long id = (Long)request.getSession().getAttribute("userId");
UtilisateurEntity u = utilisateurService.selectById(id);
return R.ok().put("data", u);
}
/**
* Réinitialisation du mot de passe
*/
@IgnoreAuth
@RequestMapping(value = "/reinitialiserMotDePasse")
public R reinitialiserMotDePasse(String pseudo, HttpServletRequest request){
UtilisateurEntity u = utilisateurService.selectOne(new EntityWrapper<utilisateurentity>().eq("pseudo", pseudo));
if(u==null) {
return R.error("L'utilisateur n'existe pas");
}
u.setMotDePasse("123456");
utilisateurService.updateById(u);
return R.ok("Le mot de passe a été réinitialisé à : 123456");
}
/**
* Liste en back-office
*/
@RequestMapping("/page")
public R page(@RequestParam Map<string object=""> params,UtilisateurEntity utilisateur,
HttpServletRequest request){
EntityWrapper<utilisateurentity> ew = new EntityWrapper<utilisateurentity>();
PageUtils page = utilisateurService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, utilisateur), params), params));
return R.ok().put("data", page);
}
/**
* Liste en front-office
*/
@IgnoreAuth
@RequestMapping("/liste")
public R liste(@RequestParam Map<string object=""> params,UtilisateurEntity utilisateur,
HttpServletRequest request){
EntityWrapper<utilisateurentity> ew = new EntityWrapper<utilisateurentity>();
PageUtils page = utilisateurService.queryPage(params, MPUtil.sort(MPUtil.between(MPUtil.likeOrEq(ew, utilisateur), params), params));
return R.ok().put("data", page);
}
/**
* Liste simple
*/
@RequestMapping("/listes")
public R listes( UtilisateurEntity utilisateur){
EntityWrapper<utilisateurentity> ew = new EntityWrapper<utilisateurentity>();
ew.allEq(MPUtil.allEQMapPre( utilisateur, "utilisateur"));
return R.ok().put("data", utilisateurService.selectListView(ew));
}
/**
* Recherche
*/
@RequestMapping("/recherche")
public R recherche(UtilisateurEntity utilisateur){
EntityWrapper< UtilisateurEntity> ew = new EntityWrapper< UtilisateurEntity>();
ew.allEq(MPUtil.allEQMapPre( utilisateur, "utilisateur"));
UtilisateurVue utilisateurVue = utilisateurService.selectView(ew);
return R.ok("Recherche d'utilisateur réussie").put("data", utilisateurVue);
}
/**
* Détails en back-office
*/
@RequestMapping("/details/{id}")
public R details(@PathVariable("id") Long id){
UtilisateurEntity utilisateur = utilisateurService.selectById(id);
return R.ok().put("data", utilisateur);
}
/**
* Détails en front-office
*/
@IgnoreAuth
@RequestMapping("/detail/{id}")
public R detail(@PathVariable("id") Long id){
UtilisateurEntity utilisateur = utilisateurService.selectById(id);
return R.ok().put("data", utilisateur);
}
/**
* Sauvegarde en back-office
*/
@RequestMapping("/sauvegarder")
public R sauvegarder(@RequestBody UtilisateurEntity utilisateur, HttpServletRequest request){
if(utilisateurService.selectCount(new EntityWrapper<utilisateurentity>().eq("pseudo", utilisateur.getPseudo()))>0) {
return R.error("Le pseudo existe déjà");
}
utilisateur.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());
//ValidatorUtils.validateEntity(utilisateur);
UtilisateurEntity u = utilisateurService.selectOne(new EntityWrapper<utilisateurentity>().eq("pseudo", utilisateur.getPseudo()));
if(u!=null) {
return R.error("L'utilisateur existe déjà");
}
utilisateur.setId(new Date().getTime());
utilisateurService.insert(utilisateur);
return R.ok();
}
/**
* Sauvegarde en front-office
*/
@RequestMapping("/ajouter")
public R ajouter(@RequestBody UtilisateurEntity utilisateur, HttpServletRequest request){
if(utilisateurService.selectCount(new EntityWrapper<utilisateurentity>().eq("pseudo", utilisateur.getPseudo()))>0) {
return R.error("Le pseudo existe déjà");
}
utilisateur.setId(new Date().getTime()+new Double(Math.floor(Math.random()*1000)).longValue());
//ValidatorUtils.validateEntity(utilisateur);
UtilisateurEntity u = utilisateurService.selectOne(new EntityWrapper<utilisateurentity>().eq("pseudo", utilisateur.getPseudo()));
if(u!=null) {
return R.error("L'utilisateur existe déjà");
}
utilisateur.setId(new Date().getTime());
utilisateurService.insert(utilisateur);
return R.ok();
}
/**
* Modification
*/
@RequestMapping("/modifier")
@Transactional
public R modifier(@RequestBody UtilisateurEntity utilisateur, HttpServletRequest request){
//ValidatorUtils.validateEntity(utilisateur);
if(utilisateurService.selectCount(new EntityWrapper<utilisateurentity>().ne("id", utilisateur.getId()).eq("pseudo", utilisateur.getPseudo()))>0) {
return R.error("Le pseudo existe déjà");
}
utilisateurService.updateById(utilisateur);
return R.ok();
}
/**
* Suppression
*/
@RequestMapping("/supprimer")
public R supprimer(@RequestBody Long[] ids){
utilisateurService.deleteBatchIds(Arrays.asList(ids));
return R.ok();
}
}
</utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></utilisateurentity></string></utilisateurentity></utilisateurentity></string></utilisateurentity></utilisateurentity></utilisateurentity>