Errore in Lettura DataBase con JPQL

di il
10 risposte

Errore in Lettura DataBase con JPQL

Utilizzo per leggere su database un metodo con JPQL

Il codice è correttamente funzionante se riesco a effettuare la lettura nel database;
se non trovo il record va in errore.

Vorrei capire cosa sbaglio nella compilazione del metodo.

	@Override
	public Anadip SelByUsername(String username) {
		
		Anadip retVal;
		
		String JPQL = "SELECT a FROM Anadip a WHERE a.userid = :userid";
		
		retVal = (Anadip) entityManager.createQuery(JPQL)
						  .setParameter("userid", username)
						  .getSingleResult();	 
		
		return retVal;
	}


il codice del controller che uso è questo


	@RequestMapping(method = RequestMethod.POST)
	public String getLoginPost(@ModelAttribute("userform") Anadip anadip,Model model,HttpServletRequest request, HttpServletResponse response)
	{
	
		Anadip record = null;
		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		
		if (anadip.getUserid() != null  && anadip.getPassword() != null) {
			
			record = anadipService.SelByUsername(anadip.getUserid());
			if(record == null)  {
				return "redirect:/login/form";
			}
			else
			{
				System.out.println("-------GetLoginPost -- eseguita lettura con  userid:  " + anadip.getUserid());
				if (passwordEncoder.matches(anadip.getPassword(), record.getPassword())) {
				    // utente verificato con userid e password
					System.out.println("-------GetLoginPost -- utente verificato --------  userid:  " + anadip.getUserid() + "  password : " + anadip.getPassword());	
					return "redirect:/";
				} else {
				    // utente non verificato
					return "redirect:/login/form?logout";
				}
			}			
		}
		
		
		String[] test = request.getParameterValues("logout");
		
		if (test != null)
		{
			Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
	        //Tomcat adds extra slash at the end of context path (e.g. "/foo/")
	        cookieWithSlash.setPath(request.getContextPath() + "/"); 
	        cookieWithSlash.setMaxAge(0); 

	        Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
	        //JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
	        cookieWithoutSlash.setPath(request.getContextPath()); 
	        cookieWithoutSlash.setMaxAge(0); 

	        //Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
	        response.addCookie(cookieWithSlash); //For cookie added by Tomcat 
	        response.addCookie(cookieWithoutSlash); //For cookie added by JBoss
	        
	        if (test.length == 2)
	        {
	        	 logger.info("utente: " + test[1]); 
				 persistentTokenRepository.removeUserTokens(test[1]);
	        }
	        
		}
		
		return "redirect:/login/form?logout";
	}



nella pagina login.jsp che riporto

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>


  <div id="mainWrapper">
            <div class="login-container">
                <div class="login-card">
                    <div class="login-form">
                        <c:url var="loginUrl" value="/login/form" />
                        <form action="${loginUrl}" method="post" class="form-horizontal" modelAttribute="userform">
                       
                           <c:if test="${param.error != null}">
                                <div class="alert alert-danger">
                                    <p>Nome utente o password errato</p>
  
                                </div>
                            </c:if>  
 
                            <c:if test="${param.forbidden != null}">
                                <div class="alert alert-danger">
                                    <p>Accesso Negato! Autenticarsi con un utente diverso</p>
                                </div>
                            </c:if>
                            
                            <c:if test="${param.logout != null}">
                                <div class="alert alert-success">
                                    <p>Disconessione eseguita con successo!</p>
                                </div>
                            </c:if>  
                   
                            <div class="input-group input-sm">
                                <label class="input-group-addon" for="userid"><i class="fa fa-user"></i></label>
                                <input type="text" class="form-control" id="userid" name="userid" placeholder="Nome Utente" required>
                            </div>
                            <div class="input-group input-sm">
                                <label class="input-group-addon" for="password"><i class="fa fa-lock"></i></label> 
                                <input type="password" class="form-control" id="password" name="password" placeholder="Password" required>
                            </div>
                            <div class="input-group input-sm">
                              <div class="checkbox">
                                <label class="mt-checkbox mt-checkbox-outline">
                                	<input type="checkbox" id="ricordami" name="ricordami">Ricordami
                                </label>  
                              </div>
                            </div>
                            <input type="hidden" name="${_csrf.parameterName}"
                                value="${_csrf.token}" />
                                 
                            <div class="form-actions">
                                <input type="submit"
                                    class="btn btn-block btn-primary btn-default" value="Log in">
                            </div>
                        </form>
                    </div>
                </div>
            </div>
       </div>


al verificarsi di una errata immissione delle credenziali utente, deve comparire il messaggio Nome utente o password errato

come posso impostare la condizione di errore in param ?

                         <c:if test="${param.error != null}">
                                <div class="alert alert-danger">
                                    <p>Nome utente o password errato</p>
  
                                </div>
                            </c:if>  
Mi scuso per la maniera forse poco professionale di porre il problema, ma vorrei riuscire a capire esattamente il ciclo.

AndBin su questo lato sei un prezioso compagno di viaggio.
Ad ogni problematica, oltre a restituire la soluzione al problema, accompagni con una spiegazione chiara e illuminante.
Ti ringrazio tantissimo per la tua cortese attenzione.

Grazie

Moreno

10 Risposte

  • Re: Errore in Lettura DataBase con JPQL

    Ti consiglio di tenere sempre sotto mano la documentazione (Per la JEE: https://docs.oracle.com/javaee/6/api).
    Nello specifico: https://docs.oracle.com/javaee/6/api/javax/persistence/Query.html

    Il metodo getSingleResult() non ritorna null se non trova nessun record, ma solleva una NoResultException. E questa la devi gestire opportunamente tu.

    Quindi hai 2 possibilità:
    1) Usare un try/catch per la chiamata al metodo getSingleResult() e gestire la NoResultException opportunamente
    2) Utilizzare getResultList(), che in caso di singolo risultato restituisce un List con una sola Entity, oppure una lista vuota in caso di nessun risultato e non solleva eccezioni se non in caso di vero problema.


    Ciao.
  • Re: Errore in Lettura DataBase con JPQL

    misonsan ha scritto:


    se non trovo il record va in errore.
    Il punto è che getSingleResult() lancia NoResultException se non c'è alcun risultato. Quindi o lo si gestisce o si fa la query in altro modo.

    P.S. usa i metodi di EntityManager che sono "tipizzati" (quelli con il Class in argomento). Eviti i cast.

    misonsan ha scritto:


    AndBin su questo lato sei un prezioso compagno di viaggio.
    Ad ogni problematica, oltre a restituire la soluzione al problema, accompagni con una spiegazione chiara e illuminante.
    Grazie
  • Re: Errore in Lettura DataBase con JPQL

    Grazie per il prezioso suggerimento.
    Ho corretto il codice nel metodo SelByUsername utilizzando try catch.


    
    	@Override
    	public Anadip SelByUsername(String username) {
    		
    		Anadip retVal;
    		
    		String JPQL = "SELECT a FROM Anadip a WHERE a.userid = :userid";
    		
    				
    		try {
    			retVal = (Anadip) entityManager.createQuery(JPQL)
    					  .setParameter("userid", username)
    					  .getSingleResult();
    			
    		}catch (NoResultException nre) {
    			retVal = null;
    		}
    		
    		return retVal;
    	}
    
    Vorrei capire perchè ritornando null dal metodo che effettua la lettura sul database, nella pagina .jsp non mi esce con il messaggio

    Nome utente o password errato ma bensi con il messaggio Disconessione eseguita con successo!
    
                               <c:if test="${param.error != null}">
                                    <div class="alert alert-danger">
                                        <p>Nome utente o password errato</p>
      
                                    </div>
                                </c:if>  
     
                                <c:if test="${param.forbidden != null}">
                                    <div class="alert alert-danger">
                                        <p>Accesso Negato! Autenticarsi con un utente diverso</p>
                                    </div>
                                </c:if>
                                
                                <c:if test="${param.logout != null}">
                                    <div class="alert alert-success">
                                        <p>Disconessione eseguita con successo!</p>
                                    </div>
                                </c:if>  
    
    Grazie

    Moreno
  • Re: Errore in Lettura DataBase con JPQL

    misonsan ha scritto:


    Vorrei capire perchè ritornando null dal metodo che effettua la lettura sul database, nella pagina .jsp non mi esce con il messaggio

    Nome utente o password errato ma bensi con il messaggio Disconessione eseguita con successo!
    nel codice hai:
    			record = anadipService.SelByUsername(anadip.getUserid());
    			if(record == null)  {
    				return "redirect:/login/form";
    			}
    Quindi a rigor di logica, con un redirect fatto dal client di quel tipo, nessuno dei 3 param indicati nella jsp potrebbe essere != null.
  • Re: Errore in Lettura DataBase con JPQL

    Ciao AndBin

    In caso di record non trovato sul database, anzichè effettuare un redirect, rimando alla stessa pagina.
    La visualizzazione della pagina di login avviene comunque senza la visualizzazione del messaggio d'errore, ma solo abblencando i campi inseriti dall'utente.

    il codice corretto è
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String getLoginPost(@ModelAttribute("userform") Anadip anadip,Model model,HttpServletRequest request, HttpServletResponse response)
    	{
    		// recupero i valori inseriti nel model
    	
    		//logica per verificare la password criptata
    		
    		/*
    		1) faccio la lettura dell'utente con la user id inserita.
    		   se trovato il record sul database
    		2) Faccio controllo con passwordEncoder.matches passando come parametri 
    			- il primo è la password in chiaro inserita dall'utente
    			- il secondo è la password criptata salvata nel database
    			Se il matches ti dà true, l'utente è autenticato. 
    		*/
    	
    		
    		
    		Anadip record = null;
    		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    		
    		if (anadip.getUserid() != null  && anadip.getPassword() != null) {
    			
    			record = anadipService.SelByUsername(anadip.getUserid());
    			if(record == null)  {
    				return "login";       //return "redirect:/login/form";  <--  vecchia istrizione
    			}
    			else
    			{
    				System.out.println("-------GetLoginPost -- eseguita lettura con  userid:  " + anadip.getUserid());
    				if (passwordEncoder.matches(anadip.getPassword(), record.getPassword())) {
    				    // utente verificato con userid e password
    					System.out.println("-------GetLoginPost -- utente verificato --------  userid:  " + anadip.getUserid() + "  password : " + anadip.getPassword());	
    					return "redirect:/";
    				} else {
    				    // utente non verificato
    					return "redirect:/login/form?logout";
    				}
    			}			
    		}
    		
    		
    		
    		String[] test = request.getParameterValues("logout");
    		
    		if (test != null)
    		{
    			Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
    	        //Tomcat adds extra slash at the end of context path (e.g. "/foo/")
    	        cookieWithSlash.setPath(request.getContextPath() + "/"); 
    	        cookieWithSlash.setMaxAge(0); 
    
    	        Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
    	        //JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
    	        cookieWithoutSlash.setPath(request.getContextPath()); 
    	        cookieWithoutSlash.setMaxAge(0); 
    
    	        //Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
    	        response.addCookie(cookieWithSlash); //For cookie added by Tomcat 
    	        response.addCookie(cookieWithoutSlash); //For cookie added by JBoss
    	        
    	        if (test.length == 2)
    	        {
    	        	 logger.info("utente: " + test[1]); 
    				 persistentTokenRepository.removeUserTokens(test[1]);
    	        }
    	        
    		}
    		
    		return "redirect:/login/form?logout";
    	}
    
    
  • Re: Errore in Lettura DataBase con JPQL

    misonsan ha scritto:


    
    [code]			if(record == null)  {
    				return "login";       //return "redirect:/login/form";  <--  vecchia istrizione
    			}
    Se così fai andare ad una "vista" interna, la richiesta (url, parametri ecc..) resta quella fatta al getLoginPost. Quindi i param che la JSP "vede" sono quelli passati al POST che ha fatto eseguire getLoginPost.
  • Re: Errore in Lettura DataBase con JPQL

    Ciao AndBin

    Seguendo quanto mi hai indicato nell'ultima risposta, ho modificato il metodo cercando di impostare lo stato nel response con un valore di errore.
    In internet ho trovato poi un esempio in cui veniva personalizzato anche il request.

    Ripropongo il codice, che non raggiunge comunque il risultato desiderato.

    Vorrei capire l'errore e come funziona il meccanismo.
    E' corretto utilizzare HttpServletRequest e HttpServletResponse ?

    Grazie

    Moreno
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String getLoginPost(@ModelAttribute("userform") Anadip anadip,Model model,HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    	{
    		// recupero i valori inseriti nel model
    	
    		//logica per verificare la password criptata
    		
    		/*
    		1) faccio la lettura dell'utente con la user id inserita.
    		   se trovato il record sul database
    		2) Faccio controllo con passwordEncoder.matches passando come parametri 
    			- il primo è la password in chiaro inserita dall'utente
    			- il secondo è la password criptata salvata nel database
    			Se il matches ti dà true, l'utente è autenticato. 
    		*/
    	
    		try	
    		{
    			
    			Anadip record = null;
    			BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    			
    			if (anadip.getUserid() != null  && anadip.getPassword() != null) {
    				
    				record = anadipService.SelByUsername(anadip.getUserid());
    				if(record == null)  {
    				
    								response.setStatus(401);    // imposto il codice di errori trovati
    					request.setAttribute("message", "UTENTE inesistente. Reinserire le Credenziali");
    					request.getRequestDispatcher("/WEB-INF/view/login.jsp").forward(request, response);
    					
    	
    					System.out.println("-------GetLoginPost -- per userid:  " + anadip.getUserid() + " impostato la response:  " + response.getStatus());
    					return "login";       //return "redirect:/login/form";
    				}
    				else
    				{
    					System.out.println("-------GetLoginPost -- eseguita lettura con  userid:  " + anadip.getUserid());
    					if (passwordEncoder.matches(anadip.getPassword(), record.getPassword())) {
    					    // utente verificato con userid e password
    						System.out.println("-------GetLoginPost -- utente verificato --------  userid:  " + anadip.getUserid() + "  password : " + anadip.getPassword());	
    						return "redirect:/";
    					} else {
    					    // utente non verificato
    						return "redirect:/login/form?logout";
    					}
    				}			
    			}
    			
    			
    			
    			String[] test = request.getParameterValues("logout");
    			
    			if (test != null)
    			{
    				Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
    		        //Tomcat adds extra slash at the end of context path (e.g. "/foo/")
    		        cookieWithSlash.setPath(request.getContextPath() + "/"); 
    		        cookieWithSlash.setMaxAge(0); 
    
    		        Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
    		        //JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
    		        cookieWithoutSlash.setPath(request.getContextPath()); 
    		        cookieWithoutSlash.setMaxAge(0); 
    
    		        //Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
    		        response.addCookie(cookieWithSlash); //For cookie added by Tomcat 
    		        response.addCookie(cookieWithoutSlash); //For cookie added by JBoss
    		        
    		        if (test.length == 2)
    		        {
    		        	 logger.info("utente: " + test[1]); 
    					 persistentTokenRepository.removeUserTokens(test[1]);
    		        }
    		        
    			}
    			
    			return "redirect:/login/form?logout";
    
    			
    		} catch (Exception e) {
    			
    			throw new ServletException("getLoginPost - errore in esecuzione metodo", e);
    		}
    		
    		
    	}
    
    
  • Re: Errore in Lettura DataBase con JPQL

    Scusa ma se stai usando Spring per la risoluzione delle view (cioè il fatto di restituire dal metodo un nome "logico" della view), allora NON è molto corretto che vai a fare tu un forward esplicitamente.
  • Re: Errore in Lettura DataBase con JPQL

    Ciao AndBin

    Non ho capito molto della tua ultima risposta.
    Virrei chiederti se puoi aiutarmi a far funzionare il metodo in modo che possa restituirmi, in caso di errate credenziali il messaggio relativo che è impostato nella pagina login.jsp

    Pensavo fosse sufficiente impostare response.setStatus(401) ad un valore che facesse scattare il param.error != null

    forse è un problema banalissimo, ma non vedo come poterlo risolvere.

    Non voglia il pesce pescato per non far fatica (forse lo dimostra il fatto di questa lunga chat), ma vorrei pescare da solo ma capendo come.


    Grazie

    Moreno
  • Re: Errore in Lettura DataBase con JPQL

    Ciao AndBin

    Sto riguardando il codice e ho messo qualche System.out.println per seguire il codice del metodo.
    Ho visto un paio di cose strane e vorrei chiederti un chiarimento.
    Riporto il codice del metodo.
    
    	@RequestMapping(method = RequestMethod.POST)
    	public String getLoginPost(@ModelAttribute("userform") Anadip anadip,Model model,HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    	{
    		// recupero i valori inseriti nel model
    	
    		//logica per verificare la password criptata
    		
    		/*
    		1) faccio la lettura dell'utente con la user id inserita.
    		   se trovato il record sul database
    		2) Faccio controllo con passwordEncoder.matches passando come parametri 
    			- il primo è la password in chiaro inserita dall'utente
    			- il secondo è la password criptata salvata nel database
    			Se il matches ti dà true, l'utente è autenticato. 
    		*/
    	
    		try	
    		{
    			
    			Anadip record = null;
    			BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
    			
    			if (anadip.getUserid() != null  && anadip.getPassword() != null) {
    				
    				record = anadipService.SelByUsername(anadip.getUserid());
    				if(record == null)  {
    					
    
    					request.setAttribute("message", "UTENTE inesistente. Reinserire le Credenziali");
    					request.getRequestDispatcher("/WEB-INF/view/login.jsp").forward(request, response);
    					
    					response.setStatus(401);    // imposto il codice di errori trovati
    					System.out.println("-------GetLoginPost -- per userid:  " + anadip.getUserid() + " impostato la response:  " + response.getStatus());
    					return "login";       
    				}
    				else
    				{
    					System.out.println("-------GetLoginPost -- eseguita lettura con  userid:  " + anadip.getUserid());
    					if (passwordEncoder.matches(anadip.getPassword(), record.getPassword())) {
    					    // utente verificato con userid e password
    						System.out.println("-------GetLoginPost -- utente verificato --------  userid:  " + anadip.getUserid() + "  password : " + anadip.getPassword());	
    						return "redirect:/";
    					} else {
    					    // utente non verificato
    						return "redirect:/login/form?logout";
    					}
    				}			
    			}
    			
    			
    			
    			String[] test = request.getParameterValues("logout");
    			
    			if (test != null)
    			{
    				Cookie cookieWithSlash = new Cookie("JSESSIONID", null);
    		        //Tomcat adds extra slash at the end of context path (e.g. "/foo/")
    		        cookieWithSlash.setPath(request.getContextPath() + "/"); 
    		        cookieWithSlash.setMaxAge(0); 
    
    		        Cookie cookieWithoutSlash = new Cookie("JSESSIONID", null);
    		        //JBoss doesn't add extra slash at the end of context path (e.g. "/foo")
    		        cookieWithoutSlash.setPath(request.getContextPath()); 
    		        cookieWithoutSlash.setMaxAge(0); 
    
    		        //Remove cookies on logout so that invalidSessionURL (session timeout) is not displayed on proper logout event
    		        response.addCookie(cookieWithSlash); //For cookie added by Tomcat 
    		        response.addCookie(cookieWithoutSlash); //For cookie added by JBoss
    		        
    		        if (test.length == 2)
    		        {
    		        	 logger.info("utente: " + test[1]); 
    					 persistentTokenRepository.removeUserTokens(test[1]);
    		        }
    		        
    			}
    			
    			return "redirect:/login/form?logout";
    
    			
    		} catch (Exception e) {
    			
    			throw new ServletException("getLoginPost - errore in esecuzione metodo", e);
    		}
    		
    		
    	}
    
    
    Imposto delle credenziali inesistenti per vedere il comportamento del codice.
    ti riporto anche la trace della console
    
    
    Hibernate: 
        select
            anadip0_.Matricola as Matricol1_0_,
            anadip0_.Cognome as Cognome2_0_,
            anadip0_.DataOperation as DataOper3_0_,
            anadip0_.KeyUtentiOperation as KeyUtent4_0_,
            anadip0_.loggabile as loggabil5_0_,
            anadip0_.Nome as Nome6_0_,
            anadip0_.NOTEDip as NOTEDip7_0_,
            anadip0_.PasswordDip as Password8_0_,
            anadip0_.IdStato as IdStato10_0_,
            anadip0_.Titolo as Titolo11_0_,
            anadip0_.UserId as UserId9_0_,
            anadip0_.UserLevel as UserLev12_0_ 
        from
            AnaDip anadip0_ 
        where
            anadip0_.UserId=?
    -------GetLoginPost -- per userid:  abcdefgh impostato la response:  200
    
    
    
    corretamente non viene trovato l'utente nel Database.
    In questa condizione, forzo il valore dello stato a 401
    response.setStatus(401);
    per indicare che ho un errore,
    ma come ben vedi nella riga immediatmente sucessiva in cui con
    System.out.println("-------GetLoginPost -- per userid: " + anadip.getUserid() + " impostato la response: " + response.getStatus());

    traccio il percorso del codice e traccio alcune variabili, il valore dello stato di response non è 401, come ho impostato, ma bensì 200.

    Puoi spiegarmi perchè ?
    Il settaggio a 401 non è corretto nel formalismo che uso ?


    continuando viene restituito
    return "login";
    che correttamente mi ripresenta la pagina di login, ma mi viene presentata non con il fprmalismo css di bootstrap, come è presentata di norma, ma nell'aspetto visualizzato nello screenshot allegato.

    Riesci a capire perchè viene visualizzata in questo modo ?

    Grazie

    Moreno
    Allegati:
    19656_40422ef1f36b0ce4e0b1704db69e31e1.jpg
    19656_40422ef1f36b0ce4e0b1704db69e31e1.jpg
Devi accedere o registrarti per scrivere nel forum
10 risposte