Application Web de Services Ménagers avec Spring Boot et MySQL

Cette application web de services ménagers est développée en utilisant Spring Boot et MySQL. Elle offre une gamme complète de fonctionnalités pour les utilisateurs et les administrateurs, couvrant la gestion des services, les réservations, les paiements et l'administration du système.

Environnement et Outils de Développement

  • Version Java : Supérieure ou égale à 8
  • Version MySQL : Supérieure ou égale à 5.7
  • IDE : Eclipse, IntelliJ IDEA, MyEclipse, STS, etc.

Technologies Principales

  • Framework Backend : Spring Boot, Spring MVC
  • Persistance : MyBatis
  • Templating Engine : Thymeleaf (ou JSP comme mentionné)
  • Frontend : JavaScript, jQuery, Ajax
  • Gestion de Build : Maven

Fonctionnalités Clés

  • Gestion Utilisateurs : Enregistrement, connexion.
  • Gestion des Services : Affichage, classification, réservation et paiement des sevrices ménagers.
  • Gestion des Commandes : Consultation des informations de commande pour les utilisateurs et les administrateurs.
  • Administration : Gestion des employés, gestion des catégories de services, allocation des commmandes, statistiques, maintenance.

Exemples de Code

Pagination et Navigation

L'extrait de code suivant illustre la logique de pagination personnalisée pour générer les liens de navigation (première page, page précédente, page suivante, dernière page) en fonction du nombre total d'éléments, de la taille de la page et du numéro de page actuel.


   // Logique de génération de la pagination HTML
   StringBuilder paginationHtml = new StringBuilder();
   int totalPages = (totalItems + pageSize - 1) / pageSize; // Calcul du nombre total de pages

   if (currentPage < 1) {
       currentPage = 1; // Assure que la page actuelle est au moins 1
   }

   paginationHtml.append("  Total ").append(totalPages).append(" pages  ").append(totalItems).append(" items  Current page: ").append(currentPage).append("  ");

   // Lien vers la première page
   if (currentPage == 1) {
       paginationHtml.append("First");
   } else {
       paginationHtml.append("<a href="\"#\"" onclick="\"loadPage(0)\"">First</a>"); // Utilisation d'une fonction JavaScript pour charger la page
   }
   paginationHtml.append("  ");

   // Lien vers la page précédente
   if (currentPage == 1) {
       paginationHtml.append("Previous");
   } else {
       paginationHtml.append("<a href="\"#\"" onclick="\"loadPage(").append(currentPage">Previous</a>"); //currentPage - 2 car les pages sont indexées à partir de 0 côté serveur
   }
   paginationHtml.append("  ");

   // Lien vers la page suivante
   if (currentPage == totalPages) {
       paginationHtml.append("Next");
   } else {
       paginationHtml.append("<a href="\"#\"" onclick="\"loadPage(").append(currentPage).append(")\"">Next</a>");
   }
   paginationHtml.append("  ");

   // Lien vers la dernière page
   if (currentPage == totalPages) {
       paginationHtml.append("Last");
   } else {
       paginationHtml.append("<a href="\"#\"" onclick="\"loadPage(").append(totalPages">Last</a>");
   }

   request.setAttribute("paginationLinks", paginationHtml.toString());
   request.setAttribute("currentPageItems", paginatedList); // La liste des éléments pour la page actuelle
   

Gestion des Produits (Exemple d'AdminController)

Ce contrôleur gère les opérations CRUD (Create, Read, Update, Delete) pour les produits dans l'interface d'administration.


   @Controller
   @RequestMapping("/admin/products")
   public class ProductAdminController extends BaseController {

       @Autowired
       private ProductService productService;

       // Afficher le formulaire d'ajout de produit
       @GetMapping("/new")
       public String showNewProductForm() {
           return "admin/products/new_product";
       }

       // Ajouter un nouveau produit
       @PostMapping("/create")
       public String createProduct(@ModelAttribute Product product) {
           // Assigner une date d'ajout si nécessaire
           // product.setAdditionDate(VeDate.getStringDateShort());
           productService.addProduct(product);
           return "redirect:/admin/products"; // Redirection vers la liste des produits
       }

       // Supprimer un produit par son ID
       @GetMapping("/delete/{productId}")
       public String deleteProduct(@PathVariable("productId") String id) {
           productService.removeProduct(id);
           return "redirect:/admin/products";
       }

       // Supprimer plusieurs produits
       @PostMapping("/delete-batch")
       public String deleteProductsInBatch() {
           String[] productIds = request.getParameterValues("productId");
           if (productIds != null) {
               for (String productId : productIds) {
                   productService.removeProduct(productId);
               }
           }
           return "redirect:/admin/products";
       }

       // Mettre à jour un produit existant
       @PostMapping("/update")
       public String updateProduct(@ModelAttribute Product product) {
           productService.modifyProduct(product);
           return "redirect:/admin/products";
       }

       // Afficher la liste de tous les produits avec pagination
       @GetMapping
       public String listAllProducts(@RequestParam(defaultValue="0") int pageNumber) {
           List<Product> allProducts = productService.findAllProducts();
           // Utilisation d'un helper pour la pagination (ex: PageHelper)
           // PageHelper.paginate(allProducts, "product", null, null, 10, pageNumber, request, null);
           request.setAttribute("productsList", allProducts); // Dans un scénario réel, on passerait la page courante
           return "admin/products/product_list";
       }

       // Rechercher des produits par critères
       @GetMapping("/search")
       public String searchProducts(@RequestParam String criteria, @RequestParam String query, @RequestParam(defaultValue="0") int pageNumber) {
           Product productFilter = new Product();
           switch (criteria) {
               case "productName":
                   productFilter.setProductName(query);
                   break;
               case "category":
                   productFilter.setCategoryId(query);
                   break;
               case "price":
                   productFilter.setPrice(query);
                   break;
               // ... autres critères
           }
           List<Product> filteredProducts = productService.findProductsByCriteria(productFilter);
           // Appliquer la pagination sur les résultats filtrés
           // PageHelper.paginate(filteredProducts, "product", List.of(criteria), List.of(query), 10, pageNumber, request, "search");
           request.setAttribute("productsList", filteredProducts);
           return "admin/products/product_search_results";
       }

       // Afficher le formulaire de modification d'un produit
       @GetMapping("/edit/{productId}")
       public String showEditProductForm(@PathVariable("productId") String id) {
           Product product = productService.findProductById(id);
           request.setAttribute("product", product);
           return "admin/products/edit_product";
       }
   }
   

Intégration Alipay (Extrait de Controller)

Cette section montre comment intégrer des paiements via Alipay, en générant un formulaire de paiement et en traitant les notifications de mise à jour de statut.


   @RestController // Utilisation de RestController pour les réponses directes API
   @RequestMapping("/payment/alipay")
   public class AlipayController extends BaseController {

       private static final String CHARSET = "UTF-8";

       // Endpoint pour initier le paiement
       @PostMapping("/initiate")
       public void initiatePayment(HttpServletResponse response) throws Exception {
           // Récupérer les détails de la commande (exemple)
           // Order orderDetails = orderService.getOrderById(orderId);
           Order orderDetails = new Order(); // Placeholder
           orderDetails.setOrderId("ALIPAY_ORDER_12345");
           orderDetails.setTotalAmount(new BigDecimal("99.99"));

           // Configuration du client Alipay (à initialiser une seule fois)
           // AlipayClient alipayClient = new DefaultAlipayClient("URL_GATEWAY", "APP_ID", "APP_PRIVATE_KEY", "JSON", CHARSET, "ALIPAY_PUBLIC_KEY");
           AlipayClient alipayClient = null; // Placeholder pour le client initialisé

           AlipayTradePagePayRequest alipayRequest = new AlipayTradePagePayRequest();
           alipayRequest.setReturnUrl("http://your-app.com/payment/return"); // URL de retour après paiement
           alipayRequest.setNotifyUrl("http://your-app.com/payment/alipay/notify"); // URL de notification asynchrone

           // Construction du corps de la requête de paiement
           String paymentDetails = String.format(
               "{\"out_trade_no\":\"%s\"," +
                "\"total_amount\":\"%s\"," +
                "\"subject\":\"Achat Service Ménager\"," +
                "\"body\":\"Service de nettoyage professionnel\"," +
                "\"product_code\":\"FAST_INSTANT_TRADE_PAY\"}",
               orderDetails.getOrderId(),
               orderDetails.getTotalAmount().toString()
           );
           alipayRequest.setBizContent(paymentDetails);

           String paymentForm = "";
           try {
               // Génération du formulaire de paiement HTML
               AlipayTradePagePayResponse alipayResponse = alipayClient.pageExecute(alipayRequest);
               if (alipayResponse.isSuccess()) {
                   paymentForm = alipayResponse.getBody();
               } else {
                   // Gérer l'erreur de génération du formulaire
                   System.err.println("Erreur lors de la génération du formulaire Alipay : " + alipayResponse.getMsg());
                   response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
                   return;
               }
           } catch (AlipayApiException e) {
               e.printStackTrace();
               response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
               return;
           }

           // Envoyer le formulaire HTML à l'utilisateur
           response.setContentType("text/html;charset=" + CHARSET);
           response.getWriter().write(paymentForm);
           response.getWriter().flush();
       }

       // Endpoint pour recevoir les notifications de mise à jour de statut d'Alipay
       @PostMapping("/notify")
       public void handleAlipayNotification(HttpServletRequest request, HttpServletResponse response) throws AlipayApiException, IOException {
           System.out.println("Notification Alipay reçue.");

           // 1. Obtenir tous les paramètres de la requête
           Map<String, String[]> parameterMap = request.getParameterMap();

           // 2. Convertir les paramètres en Map<String, String>
           Map<String, String> params = new HashMap<>();
           for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
               if (entry.getValue() != null && entry.getValue().length > 0) {
                   params.put(entry.getKey(), entry.getValue()[0]);
               }
           }

           // 3. Vérifier la signature de la notification pour s'assurer qu'elle provient bien d'Alipay
           // boolean isValidSignature = AlipaySignature.rsaCheckV1(params, ALIPAY_PUBLIC_KEY, CHARSET, SIGN_TYPE);
           boolean isValidSignature = true; // Placeholder pour la vérification de signature

           if (isValidSignature) {
               // 4. Traiter la notification (mettre à jour le statut de la commande, etc.)
               String tradeStatus = params.get("trade_status");
               String orderId = params.get("out_trade_no");

               if ("TRADE_SUCCESS".equals(tradeStatus) || "TRADE_FINISHED".equals(tradeStatus)) {
                   // Mettre à jour le statut de la commande dans la base de données
                   // orderService.updateOrderStatus(orderId, "Paid");
                   System.out.println("Paiement réussi pour la commande : " + orderId);
               } else {
                   System.out.println("Statut de transaction Alipay : " + tradeStatus + " pour la commande " + orderId);
               }

               // Répondre à Alipay avec "success" pour accuser réception
               response.getWriter().write("success");
           } else {
               System.err.println("Signature Alipay invalide.");
               response.getWriter().write("fail");
           }
           response.getWriter().flush();
       }
   }
   

Gestion des Allocations (Extrait de AllotController)

Ce contrôleur gère l'attribution des commandes aux employés disponibles.


   @Controller
   @RequestMapping("/allocations") // Route plus générique
   public class AllocationController extends BaseController {

       @Autowired
       private AllocationService allocationService;
       @Autowired
       private OrderService orderService;
       @Autowired
       private EmployeeService employeeService;

       // Préparer l'interface d'ajout d'allocation
       @GetMapping("/new")
       public String prepareNewAllocation() {
           // Récupérer les commandes en attente de paiement ou non attribuées
           Order orderCriteria = new Order();
           orderCriteria.setStatus("Paid"); // Ou un statut indiquant "Prêt à être alloué"
           List<Order> pendingOrders = orderService.findOrdersByCriteria(orderCriteria);
           request.setAttribute("pendingOrders", pendingOrders);

           // Récupérer la liste des employés disponibles
           List<Employee> availableEmployees = employeeService.findAllEmployees();
           request.setAttribute("availableEmployees", availableEmployees);

           return "admin/allocations/new_allocation";
       }

       // Créer une nouvelle allocation
       @PostMapping("/create")
       public String createAllocation(@ModelAttribute Allocation allocation) {
           allocation.setAssignmentDate(VeDate.getStringDateShort());
           allocation.setStatus("In Progress"); // Statut initial de l'allocation
           allocationService.addAllocation(allocation);

           // Mettre à jour le statut de la commande correspondante
           Order relatedOrder = orderService.findOrderById(allocation.getOrderId());
           if (relatedOrder != null) {
               relatedOrder.setStatus("Assigned"); // Mettre à jour le statut de la commande
               orderService.updateOrder(relatedOrder);
           }
           return "redirect:/allocations"; // Redirection vers la liste des allocations
       }

       // Supprimer une allocation par ID
       @GetMapping("/delete/{allocationId}")
       public String deleteAllocation(@PathVariable("allocationId") String id) {
           allocationService.removeAllocation(id);
           // Peut-être besoin de réinitialiser le statut de la commande ici
           return "redirect:/allocations";
       }

       // Supprimer plusieurs allocations en lot
       @PostMapping("/delete-batch")
       public String deleteAllocationsInBatch() {
           String[] allocationIds = request.getParameterValues("allocationId");
           if (allocationIds != null) {
               for (String id : allocationIds) {
                   allocationService.removeAllocation(id);
               }
           }
           return "redirect:/allocations";
       }

       // Mettre à jour une allocation existante
       @PostMapping("/update")
       public String updateAllocation(@ModelAttribute Allocation allocation) {
           allocationService.modifyAllocation(allocation);
           return "redirect:/allocations";
       }

       // Afficher la liste de toutes les allocations
       @GetMapping
       public String listAllAllocations(@RequestParam(defaultValue="0") int pageNumber) {
           List<Allocation> allAllocations = allocationService.findAllAllocations();
           // Appliquer la pagination
           // PageHelper.paginate(allAllocations, "allocation", null, null, 10, pageNumber, request, null);
           request.setAttribute("allocationsList", allAllocations);
           return "admin/allocations/allocation_list";
       }
   }
   

Étiquettes: Java SpringBoot MySQL mvc MyBatis

Publié le 4 août à 04h41