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";
}
}