[JAVA EE] Liste Déroulantes Liées Servlet

Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
- - Dernière réponse : KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
- 18 oct. 2017 à 19:20
Bonjour à tous !
Je sais que de nombreux sujet traite déjà de ma question, mais beaucoup sont en php et en java je ne trouve pas ma réponse.

J'ai déjà une partie de code construit. Et je pense que le problème vient de ma servlet car lorsque je rentre idSelect = (long) 1, il me ressort bien la zone 1 de ma liste. Mais du coup j'ai pas vraiment d'idée !
Je vous montre mon code : (j'ai enlever des grosses partie de mon code qui ne sont pas utile dans mon problème donc ne soyez pas étonné de certaines choses! Cela rend la lecture plus simple)

stationForm.jsp

<%@ page pageEncoding="UTF-8" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
	<head>
		<c:import url="/WEB-INF/includePart/header.jsp">
    		<c:param name="title" value="Nouvelle Station"></c:param>
    	</c:import>
	</head>
	<body>
	  	<div class="menuPerso">
    		<c:import url="/WEB-INF/includePart/menu.jsp"></c:import>
    	</div>
		 <form class="form-signin" method="post" action="<c:url value="/station" />">
        
                <h2 class="form-signin-heading">Nouvelle Station</h2>

				<label for="chantier" class="sr-only">Nom du Chantier</label>
                <select class="form-control" id="chantier_id" name="chantier_id" onchange = "listZone();" required autofocus >
                	<option id="chantier_id" value="">Chantier</option>
                	<c:forEach items="${arrayChantier}" var="chantier">
                		<option value="${chantier['chantier_id']}, ${chantier['chantier_name']}">${chantier['chantier_name']}</option>
					</c:forEach>
				</select>
				
				<span class="error">${form.errors['chantier_name']}</span>
				<br><br>
				
				<label for="zone" class="sr-only">Nom de la Zone</label>
           		<select class="form-control" id="zone_id" name="zone_id" required autofocus>
           		<option  id="zone_id" value="" >Zone</option>
            		<c:forEach items="${arrayZone}" var="zone">
                		<option value="${zone['zone_id']}">${zone['zone_name']}</option>
					</c:forEach>
				</select>			
				<span class="error">${form.errors['zone_name']}</span>
				<br><br>
                
                <p class="${empty form.errors ? 'succes' : 'error'}">${form.resultat}</p>
        </form>
        
	<script src="<c:url value="/JS/dynamicListForm.js" />"></script>
	</body>
</html>


dynamicListForm.js
function getXhr()
{
	 var xhr = null;
     
	 if(window.XMLHttpRequest) {
		 xhr = new XMLHttpRequest();
	 }
     else if(window.ActiveXObject) { 
    	 try {
    		 xhr = new ActiveXObject("Msxml2.XMLHTTP");
         } catch (e) {
         xhr = new ActiveXObject("Microsoft.XMLHTTP");
         }
     }
     else {
    	 alert("Votre navigateur ne supporte pas les objets XMLHTTPRequest");
         xhr = false;
     }
     return xhr;
}
  

function listZone()
{
	var xhr = getXhr();

	xhr.onreadystatechange = function() {	
		if(xhr.readyState == 4){
			if (xhr.status == 200 || xhr.status == 0) {
				select = xhr.responseText;
		        document.getElementById('zone_id').innerHTML = select;
		    }
			else {
				alert('Erreur :' +xhr.status + ' '+xhr.statusText);
			}
		}
	};
	
	xhr.open("GET","/Auscultation/station",true);
	xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
	chantierSelect = document.getElementById('chantier_id');
	idParent = chantierSelect.options[chantierSelect.selectedIndex].value;	
	xhr.send(null);
}


AddStationServlet.java
package com.auscult.servlets;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.auscult.beans.Chantier;
import com.auscult.beans.Zone;
import com.auscult.forms.StationForm;
import com.auscult.forms.ZoneForm;
import com.auscult.dao.DaoChantier;
import com.auscult.dao.DaoUser;
import com.auscult.dao.DaoStation;
import com.auscult.dao.DAOFactory;
import com.auscult.dao.DaoZone;
import com.google.gson.Gson;

public class AddStationServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	
	public static final String ATT_USER 		 = "user";
    public static final String ATT_FORM 		 = "form";
    public static final String CONF_DAO_FACTORY  = "daofactory";
    public static final String ATT_SESSION_USER  = "userSession";
    public static final String COOKIE_CONNECTION = "cookieConnection";
    
   
    public static final String VUE         = "/WEB-INF/admin/create/stationForm.jsp";
    public static final String HOME		   = "/station";
    
    public String chemin;
    public String station_dir;
    
    public String host;
	public String username;
	public String password;
	
	public String[] FTPtab  = new String [5];
	
    private DaoUser			daoUser;
    private DaoStation      daoStation;
    private DaoZone			daoZone;
    private DaoChantier		daoChantier;
    
    public void init() throws ServletException { 
    	
        this.daoStation = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getStationDao();
        this.daoChantier = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getChantierDao();
        this.daoZone = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getZoneDao();
        this.daoUser = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getUserDao();
    }
	
    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException{
    	HttpSession session = request.getSession();
    	
    	Long idSelect = null;
    	if (request.getParameter("select")!= null){
			idSelect = Long.parseLong(request.getParameter( "select" ));
		}
    	
    	ArrayList<Chantier> arrayChantier = daoChantier.findAllChantier();
    	ArrayList<Zone> arrayZone = daoZone.findByChantier(idSelect);    	  	
		
		request.setAttribute("arrayChantier", arrayChantier);
		request.setAttribute("arrayZone", arrayZone);
    	
    	
        if ( session.getAttribute( ATT_SESSION_USER ) == null && getCookieValue(request, COOKIE_CONNECTION) == null) {
            response.sendRedirect( request.getContextPath() + HOME );
        } else {
        	if(session.getAttribute( ATT_SESSION_USER ) == null)
        	{
        		session.setAttribute(ATT_SESSION_USER, daoUser.find(Long.parseLong(getCookieValue(request, COOKIE_CONNECTION))));
        	}
        	
            this.getServletContext().getRequestDispatcher( VUE ).forward( request, response );
            
        }
      }
    
    
    private static String getCookieValue( HttpServletRequest request, String nom ) {
        Cookie[] cookies = request.getCookies();
        if ( cookies != null ) {
            for ( Cookie cookie : cookies ) {
                if ( cookie != null && nom.equals( cookie.getName() ) ) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }
  
}


DaoImplZone.java (si ca peut etre utile!)
package com.auscult.dao;

import java.sql.*;
import java.util.ArrayList;

import com.auscult.beans.Station;
import com.auscult.beans.Zone;

import static com.auscult.dao.DaoTools.*;

public class DaoImplZone implements DaoZone{
	private static final String SQL_SELECT_WHERE_CHANTIER_ID ="SELECT zone_id, zone_name, x1, y1, x2, y2, x3, y3, chantier_name, last_name "
																+ "FROM zone "
																+ "INNER JOIN chantier ON zone.FK_chantier_id = chantier.chantier_id "
																+ "INNER JOIN user ON chantier.FK_user_id = user.user_id WHERE chantier_id = ?";
	
	
	
	private DAOFactory          daoFactory;

    DaoImplZone( DAOFactory daoFactory ) {
        this.daoFactory = daoFactory;
    }
    
    
    @Override
    public ArrayList<Zone> findByChantier ( Long chantier_id ) throws DAOException {
    	System.out.println("verifie DaoImplZone findChantier");
    	Connection connexion = null;
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        ArrayList<Zone> listZone = new ArrayList<Zone>();

        try {
           
            connexion = daoFactory.getConnection();
            preparedStatement = initPreparedRequest( connexion, SQL_SELECT_WHERE_CHANTIER_ID, false, chantier_id );
            resultSet = preparedStatement.executeQuery();
            while ( resultSet.next() ) {
            	listZone.add(map(resultSet));
            }
        } catch ( SQLException e ) {
        	System.out.println("error sql exception = " + e.getMessage());
            throw new DAOException( e );
        } finally {
            silentClose( resultSet, preparedStatement, connexion );
        }
        
        System.out.println("size"+listZone.size());
        return listZone;

    }
  
}



Lorsque je select un élément de ma liste, il ne retourne rien dans ma deuxieme list (à vrai dire je me suis inspiré de ce forum https://www.developpez.net/forums/d1371530/java/developpement-web-java/servlets-jsp/listes-deroulantes-liees/ surtout pour la servlet ^^)

Je vous remercie d'avance
Ca fait vraiment un moment que je suis bloqué et je manque de connaissance pour trouvé, so .. HELP MEEE, PLEASE !! ^^
(désolé pour les fautes d'orthographes, on me le reproche souvent!)
Afficher la suite 

3 réponses

Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
88
0
Merci
Bonjour,

Je n'ai pas tout regardé, mais dans le JavaScript tu as :

xhr.open("GET","/Auscultation/station",true);
xhr.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
chantierSelect = document.getElementById('chantier_id');
idParent = chantierSelect.options[chantierSelect.selectedIndex].value;	
xhr.send(null);

Comment se fait-il que tu ne te serves pas de idParent ?
C'est pourtant ça qui devrait permettre d'appeler le deuxième select...

Dans le code source de la page dont tu t'es inspiré tu avais :
sel = document.getElementById(parentSelect);
idParent = sel.options[sel.selectedIndex].value;
xhr.open("GET","/GTP/tache?action=ajouter&remplir="+enfantSelect+"&select="+idParent,true);
xhr.send(null);

Il y avait donc bien dans le GET une référence à l'idParent pour que le serveur s'y retrouve...
Commenter la réponse de KX
Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
0
Merci
Bonjour KX,

En effet, tes indications m'ont aidé cela a résolu le problème (il y avait aussi un autre soucis mais que j'ai pu résoudre rapidement)

Cela marche beaucoup mieux même si lent je trouve, peut-être une histoire de cache.
J'ai juste une dernière question, dans ma deuxième liste, ma première liste se réaffiche en plus. Une idée ?
C'est à dire :
Liste 2 -> Elements Liste1 + Elements Liste2
Je voudrai pouvoir enlever les éléments de la liste 1.

Voici le code modifié de ma JSP et mon JS

JSP
				
<label for="chantier" class="sr-only">Nom du Chantier</label>
                <select class="form-control" id="chantier_id" name="chantier_id" onchange = "listZone('chantier_id','zone_id')" required autofocus >
                	<option id="chantier_id" value="">Chantier</option>
                	<c:forEach items="${arrayChantier}" var="chantier">
                		<option value="${chantier['chantier_id']}">${chantier['chantier_name']}</option>
					</c:forEach> 
				</select>
				
				<span class="error">${form.errors['chantier_name']}</span>
				<br><br>
				
				<label for="zone" class="sr-only">Nom de la Zone</label>
           		<select class="form-control" id="zone_id" name="zone_id" required autofocus>
           		<option  id="zone_id" value="" >Zone</option>
           		<c:forEach items="${arrayZone}" var="zone">
                		<option value="${zone['zone_id']}">${zone['zone_name']}</option>
				</c:forEach>
				</select>			
				<span class="error">${form.errors['zone_name']}</span>
				<br><br>


JS
function listZone(parentSelect, childSelect)
{
	var xhr = getXhr();

	xhr.onreadystatechange = function() {	
		if(xhr.readyState == 4){
			if (xhr.status == 200 || xhr.status == 0) {
				select = xhr.responseText;
		        document.getElementById(childSelect).innerHTML = select;
		    }
			else {
				alert('Erreur :' +xhr.status + ' '+xhr.statusText);
			}
		}
	};
	
	chantierSelect = document.getElementById(parentSelect);
	idParent = chantierSelect.options[chantierSelect.selectedIndex].value;	
	xhr.open("GET","/Auscultation/station?action=ajouter&listZone="+childSelect+"&select="+idParent,true);
	xhr.send(null);
}


Merci d'avance
KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
88 -
"même si lent je trouve, peut-être une histoire de cache"
J'ai surtout l'impression que tu ne fais pas suffisamment la distinction entre les deux cas d'utilisations, notamment tu fais :

ArrayList<Chantier> arrayChantier = daoChantier.findAllChantier();
ArrayList<Zone> arrayZone = daoZone.findByChantier(idSelect);   

Or un seul des deux chargements est nécessaire, soit tu récupères tout, soit un seul, mais il n'y a pas de raison de faire les deux actions à chaque fois, ce qui explique pourquoi c'est plus long que ça ne devrait.

En plus ici tu récupères une nouvelle page à chaque fois que tu changes une valeur, alors que la partie AJAX devrait juste récupérer la liste des valeurs et ne modifier (en JS) que cette partie là dans la page sans recharger tout le reste.

Je pense qu'au final tu devrais avoir deux servlets :
  • celle que tu as déjà et qui charge la JSP entière la première fois
  • une nouvelle servlet qui prends le paramètre de recherche spécifique et renvoie juste la liste des valeurs de la combobox.
Killkala
Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
> KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
-
Bonjour KX,

Merci de ton aide, je pense avoir beaucoup avancé avec tes indications. J'ai crée ma 2e servlet comme tu me l'a conseillé mais je pense que je ne dois pas bien renvoyer les valeurs.

Voici ma 2e servlet :

ListServket.java
package com.auscult.servlets;

import java.io.IOException;
import java.util.ArrayList;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.auscult.beans.Zone;
import com.auscult.dao.DAOFactory;
import com.auscult.dao.DaoZone;

public class ListServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	public static final String CONF_DAO_FACTORY  = "daofactory";
    
    private DaoZone			daoZone;
    
    public void init() throws ServletException {    	
        this.daoZone = ( (DAOFactory) getServletContext().getAttribute( CONF_DAO_FACTORY ) ).getZoneDao();     
    }
	
    public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
    	
    	Long idSelect = null;
    	if (request.getParameter("select")!= null) {
			idSelect = Long.parseLong(request.getParameter( "select" ));
		}
    		
    	ArrayList<Zone> arrayZone = daoZone.findByChantier(idSelect);	
		
		request.setAttribute("arrayZone", arrayZone);
		this.getServletContext().getRequestDispatcher( "/WEB-INF/admin/create/stationForm.jsp" ).forward( request, response );

    }
    
}



Et dans ma JSP j'ai rajouté la ligne suivante :
<% ArrayList<Zone> arrayZone = (ArrayList<Zone>)request.getAttribute("arrayZone"); %>


Dans ma ListBox je récupère bien les éléments de façon dynamique, mais le soucis c'est qu'elle s'affiche de la manière suivante :
NomList1 + NomList2 + ElementsList2
Or je ne veux pas du nom de la liste 1 en debut. Je pense qu'il doit peut-être encore y avoir un double chargement lorsque j'utilise RequestDispatcher, où je ne sais pas trop à vrai dire, j'ai fais pas mal de test mais rien de concluant à ce sujet.
KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
88 > Killkala
Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
-
Dans mon idée, la deuxième servlet ne devrait pas renvoyer une JSP, il ne faut pas changer de page web mais juste compléter la page déjà affichée avec des données additionnelles.

Par exemple :

public void doGet( HttpServletRequest request, HttpServletResponse response ) throws ServletException, IOException {
    long idSelect = Long.parseLong(request.getParameter("select"));
    List<Zone> zones = daoZone.findByChantier(idSelect);
    String json = zones.stream().map(Zone::toString).collect(Collectors.joining("','","['","']"));
    response.getWriter().write(json);
}

Et côté JS :
zones = eval(xhr.responseText);
que tu pourras mettre directement dans ta liste déroulante en modifiant le DOM (c'est le principe de l'AJAX)
Killkala
Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
> KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
-
Bonjour KX,

Merci pour ton aide encore une fois! J'avoue avoir fait une petite pause sur ce problème qui me prenais beaucoup la tête, mais maintenant je n'ai plus le choix de le résoudre !

Alors côté Java je pense que tout se passe bien, il récupère bien la liste de Zones qui dépend de Chantier. J'ai appliqué tes conseils pour la servlet.

En faite la le problème c'est plutôt côté Ajax (j'avoue que c'est l'une des première fois que j'en fais et ce n'est pas simple!)
Dans mon fichier .JS, j'applique donc ce que tu m'as dis de cette façon :
if (xhr.status == 200 || xhr.status == 0) {	
				zones = eval(xhr.responseText); 
				console.log(zones);
		    }

Et dans ma console (sans parler de ma JSP dans un premier temps mais ca m'a donné le même résultat), ça m'affiche ça :
["com.auscult.beans.Zone@3055971a"]
Je ne comprend pas du tout ce résultat, surtout que les chiffres/lettres après l'@ changent à chaque fois
Moi je voudrai afficher l'Id (ou le nom peut importe ça reviens au même).
J'ai essayé "zones.zone_id" mais là il m'affiche "undefined"

J'espère que tu pourras m'aider !
Merci en tout cas :)
KX
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
88 > Killkala
Messages postés
6
Date d'inscription
lundi 2 octobre 2017
Statut
Membre
Dernière intervention
18 octobre 2017
-
Sur le stream j'ai fait un
map(Zone::toString)
donc on appelle la méthode
toString()
sur les objets Zone.
Si tu obtiens
com.auscult.beans.Zone@3055971a
c'est parce que tu n'as pas redéfini la méthode toString dans ta classe, donc tu hérites le comportement par défaut de la classe Object.
Alors soit tu redéfinis la méthode toString pour ta classe Zone, soit tu changes le mapping pour appeler une autre méthode, par exemple si tu as une méthode
String getName()
tu peux faire
map(Zone::getName)
.
Commenter la réponse de Killkala
Messages postés
16100
Date d'inscription
samedi 31 mai 2008
Statut
Modérateur
Dernière intervention
7 janvier 2020
88
0
Merci
Voici un exemple en pur HTML/JavaScript.

<select id="list1" onchange="list1changelist2();">
    <option value='a'>A</option>
    <option value='b'>B</option>
    <option value='c'>C</option>
</select>
<select id="list2"></div>
<script>
    function list1changelist2() {
        list1 = document.getElementById("list1");
        selected = list1.selectedOptions[0].value;
        var xmlHttp = new XMLHttpRequest();
        xmlHttp.onreadystatechange = function() {
            if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
                list2 = document.getElementById("list2");
                list2.innerHTML = xmlHttp.response;
            }
        }
        xmlHttp.open("GET", "/data?id="+selected, true);
        xmlHttp.send(null);
    }

    list1changelist2(); // pour l'initialisation
</script>

À chaque fois que la liste 1 change de valeur dans le HTML on appelle la fonction du code JavaScript, celui-ci va lire le DOM pour récupérer la valeur sélectionnée, par exemple "a", "b" ou "c" et faire une requête HTTP GET sur ton serveur à l'URL /data?id=a, /data?id=b ou /data?id=c selon la valeur.

Voici ce que pourrait renvoyer l'URL /data selon la valeur de l'id (ce que tu devrais faire avec une deuxième JSP)

/data?id=a
<option>A1</option>
<option>A2</option>
<option>A3</option>

/data?id=b
<option>B4</option>
<option>B5</option>
<option>B6</option>

/data?id=c
<option>C7</option>
<option>C8</option>
<option>C9</option>

C'est ce contenu qui sera inséré dans la liste2 à chaque appel de la fonction (que l'on peut appeler une première fois au chargement de la page pour initialiser la première valeur).
Commenter la réponse de KX