Pile Technologique
Backend avec SpringBoot
SpringBoot intègre des serveurs comme Tomcat, Jetty et Undertow, simplifiant le déploiement sans configuration manuelle. Sa fonctionnalité clé est l'auto-configuration, qui ajuste l'application en fonction des dépendances. Il offre aussi des modules pré-construits tels que Spring Data, Spring Security et Spring Cloud, accélérant le développement et facilitant l'intégration.
Frontend avec Vue.js
Vue.js repose sur un DOM virtuel pour des opérations DOM efficaces. Il utilise une liaison de données réactive, le DOM virtuel et une architecture basée sur les composants, offrant un modèle de développement flexible et maintenable. Lorsque les données changent, l'interface se met à jour automatiquement, permettant aux développeurs de se concentrer sur la logique métier.
Persistance avec MyBatis-Plus
MyBatis-Plus est un outil d'amélioration pour MyBatis, réduisant la charge de développement. Il supporte plusieurs bases de données comme MySQL, Oracle, SQL Server et PostgreSQL. Avec ses API riches et annotations, il simplifie les opérations ORM et minimise le code SQL manuel. Il inclut un générateur de code pour créer automatiquement des entités, des interfaces Mapper et des fichiers de mappage XML, tout en supportant des fonctionnalités comme la pagination, les requêtes dynamiques, le verrouillage optimiste et l'analyse des performances.
Test du Système
Objectifs des Tests
Les tests du système visent à identifier les défauts et à valider la conformité aux exigences. Ils garantissent la qualité et la fiabilité en simulant des scénarios d'utiilsation réels, améliorant ainsi l'expérience utilisateur. Les tests doivent se concentrer sur la validation fonctionnelle et la détection des problèmes logiques.
Tests Fonctionnels
Les tests fonctionnels impliquent des interactions utilisateur telles que la saisie de données et la vérification des limites. Des cas de test sont conçus pour couvrir divers scénarios.
Test de Connexion : Vérifie l'authentification avec des combinaisons de nom d'utilisateur, mot de passe et captcha.
| Données Saisies | Résultat Attendu | Résultat Actuel | Analyse |
|---|---|---|---|
| Nom d'utilisateur : admin123, Mot de passe : secret123, Captcha : correct | Connexion réussie | Connexion réussie | Conforme aux attentes |
| Nom d'utilisateur : admin123, Mot de passe : erroné, Captcha : correct | Erreur de mot de passe | Erreur de mot de passe | Conforme aux attentes |
| Nom d'utilisateur : admin123, Mot de passe : secret123, Captcha : incorrect | Erreur de captcha | Erreur de captcha | Conforme aux attentes |
| Nom d'utilisateur : vide, Mot de passe : secret123, Captcha : correct | Nom d'utilisateur requis | Nom d'utilisateur requis | Conforme aux attentes |
Test de Gestion des Utilisateurs : Couvre l'ajout, la modification, la suppression et la recherche d'utilisateurs, avec des vérifications pour les champs obligatoires et les doublons.
| Données Saisies | Résultat Attendu | Résultat Actuel | Analyse |
|---|---|---|---|
| Informations utilisateur complètes | Ajout réussi, affichage dans la liste | Utilisateur ajouté à la liste | Conforme aux attentes |
| Modification des informations utilisateur | Modification réussie | Informations mises à jour | Conforme aux attentes |
| Suppression d'un utilisateur sélectionné | Confirmation de suppression, puis suppression | Utilisateur supprimé après confirmation | Conforme aux attentes |
| Ajout avec nom d'utilisateur vide | Nom d'utilisateur requis | Nom d'utilisateur requis | Conforme aux attentes |
| Ajout avec nom d'utilisateur existant | Échec, nom d'utilisateur en doublon | Échec, nom d'utilisateur en doublon | Conforme aux attentes |
Après les tests, le système est validé pour répondre aux exigences fonctionnelles et de performance.
Exemples de Code
API de Connexion
@IgnoreAuth
@PostMapping(value = "/connexion")
public R seConnecter(String nomUtilisateur, String motDePasse, String captcha, HttpServletRequest requete) {
UtilisateurEntity utilisateur = serviceUtilisateur.selectOne(new EntityWrapper<UtilisateurEntity>().eq("nom_utilisateur", nomUtilisateur));
if(utilisateur == null || !utilisateur.getMotDePasse().equals(motDePasse)) {
return R.error("Identifiants incorrects");
}
String jeton = serviceJeton.genererJeton(utilisateur.getId(), nomUtilisateur, "utilisateurs", utilisateur.getRole());
return R.ok().put("jeton", jeton);
}
@Override
public String genererJeton(Long idUtilisateur, String nomUtilisateur, String nomTable, String role) {
JetonEntity entiteJeton = this.selectOne(new EntityWrapper<JetonEntity>().eq("id_utilisateur", idUtilisateur).eq("role", role));
String jeton = UtilitaireCommun.genererChaineAleatoire(32);
Calendar calendrier = Calendar.getInstance();
calendrier.setTime(new Date());
calendrier.add(Calendar.HOUR_OF_DAY, 1);
if(entiteJeton != null) {
entiteJeton.setJeton(jeton);
entiteJeton.setHeureExpiration(calendrier.getTime());
this.updateById(entiteJeton);
} else {
this.insert(new JetonEntity(idUtilisateur, nomUtilisateur, nomTable, role, jeton, calendrier.getTime()));
}
return jeton;
}
Intercepteur d'Autorisation
@Component
public class IntercepteurAutorisation implements HandlerInterceptor {
public static final String CLE_JETON_LOGIN = "Jeton";
@Autowired
private ServiceJeton serviceJeton;
@Override
public boolean preHandle(HttpServletRequest requete, HttpServletResponse reponse, Object handler) throws Exception {
reponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE");
reponse.setHeader("Access-Control-Max-Age", "3600");
reponse.setHeader("Access-Control-Allow-Credentials", "true");
reponse.setHeader("Access-Control-Allow-Headers", "x-requested-with,request-source,Jeton, Origin,imgType, Content-Type, cache-control,postman-token,Cookie, Accept,authorization");
reponse.setHeader("Access-Control-Allow-Origin", requete.getHeader("Origin"));
if (requete.getMethod().equals(RequestMethod.OPTIONS.name())) {
reponse.setStatus(HttpStatus.OK.value());
return false;
}
IgnoreAuth annotation;
if (handler instanceof HandlerMethod) {
annotation = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAuth.class);
} else {
return true;
}
String jeton = requete.getHeader(CLE_JETON_LOGIN);
if(annotation != null) {
return true;
}
JetonEntity entiteJeton = null;
if(StringUtils.isNotBlank(jeton)) {
entiteJeton = serviceJeton.getEntiteJeton(jeton);
}
if(entiteJeton != null) {
requete.getSession().setAttribute("utilisateurId", entiteJeton.getIdUtilisateur());
requete.getSession().setAttribute("role", entiteJeton.getRole());
requete.getSession().setAttribute("nomTable", entiteJeton.getNomTable());
requete.getSession().setAttribute("nomUtilisateur", entiteJeton.getNomUtilisateur());
return true;
}
PrintWriter ecrivain = null;
reponse.setCharacterEncoding("UTF-8");
reponse.setContentType("application/json; charset=utf-8");
try {
ecrivain = reponse.getWriter();
ecrivain.print(JSONObject.toJSONString(R.error(401, "Veuillez vous connecter d'abord")));
} finally {
if(ecrivain != null) {
ecrivain.close();
}
}
return false;
}
}
Exemple de Base de Données
-- Structure de la table pour les jetons d'authentification
DROP TABLE IF EXISTS `jeton_authentification`;
CREATE TABLE `jeton_authentification` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'Clé primaire',
`id_utilisateur` bigint(20) NOT NULL COMMENT 'Identifiant utilisateur',
`nom_utilisateur` varchar(100) NOT NULL COMMENT 'Nom d''utilisateur',
`nom_table` varchar(100) DEFAULT NULL COMMENT 'Nom de la table',
`role` varchar(100) DEFAULT NULL COMMENT 'Rôle',
`jeton` varchar(200) NOT NULL COMMENT 'Jeton d''authentification',
`heure_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Heure de création',
`heure_expiration` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00' COMMENT 'Heure d''expiration',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT COMMENT='Table des jetons d''authentification';
-- Exemples d'enregistrements
INSERT INTO `jeton_authentification` VALUES ('9', '23', 'utilisateur1', 'etudiants', 'Étudiant', 'abc123xyz', '2023-02-23 21:46:45', '2023-03-15 14:01:36');
INSERT INTO `jeton_authentification` VALUES ('10', '11', 'utilisateur2', 'etudiants', 'Étudiant', 'def456uvw', '2023-02-27 18:33:52', '2023-03-17 18:27:42');
INSERT INTO `jeton_authentification` VALUES ('11', '17', 'utilisateur3', 'etudiants', 'Étudiant', 'ghi789rst', '2023-02-27 18:46:19', '2023-02-27 19:48:58');
INSERT INTO `jeton_authentification` VALUES ('12', '1', 'admin', 'utilisateurs', 'Administrateur', 'jkl012opq', '2023-02-27 19:37:01', '2023-03-17 18:23:02');
INSERT INTO `jeton_authentification` VALUES ('13', '21', 'president_club', 'presidents', 'Président de club', 'mno345lmn', '2023-02-27 19:38:07', '2023-03-17 18:25:20');