9

Ho un modulo MVC Spring 3 con 2 parametri che sto tentando di inviare al mio metodo controller e sto ricevendo un errore 404. La svolta su questo problema è che il modulo ha 2 pulsanti di invio e il pulsante di invio che viene cliccato determina il valore di uno dei parametri. Ecco la mia forma.Spring 3 - modulo con 2 pulsanti, invio di 2 parametri al metodo controller

<form:form action="/approve/${bulletin.id}" method="post"> 
     <table> 
      <tr> 
       <td colspan="2"><b>From:</b> <c:out value="${bulletin.name}" /></td> 
      </tr> 
      <tr> 
       <td colspan="2"><b>Subject:</b> <c:out 
         value="${bulletin.subject}" /></td> 
      </tr> 
      <tr> 
       <td colspan="2"><b>Date:</b> <c:out value="${bulletin.date}" /> 
        <br></td> 
      </tr> 
      <tr> 
       <td colspan="2"><t:notePrint note="${bulletin.note}" /> <input 
        type="hidden" name="id" value="${bulletin.id}" /></td> 
      </tr> 
      <tr> 
       <td><input type="submit" name="approve" value="Approve" /></td> 
       <td><input type="submit" name="deny" value="Deny" /></td> 
      </tr> 
     </table> 
     <br /> 
    </form:form> 

Ecco la forma del mio controller.

@RequestMapping(value = "/approve/{id}", method = RequestMethod.POST) 
public String approveBulletin(@RequestParam int id, 
     @RequestParam(required = false, value = "approve") String approve, 
     @RequestParam(required = false, value = "deny") String deny, Model model) { 
    try { 
     if (approve.equalsIgnoreCase("approve")) { 
      bulletinDAO.approveBulletin(id); 
      model.addAttribute("approval", 
        "Your bulletin has been approved."); 
     } 
     if (deny.equalsIgnoreCase("deny")) { 
      bulletinDAO.denyBulletin(id); 
      model.addAttribute("approval", "Your bulletin has been denied."); 
     } 

     List<Bulletin> bulletins = bulletinDAO.getApprovedBulletins(); 
     model.addAttribute("bulletins", bulletins); 
    } catch (Exception e) { 
     System.out.println(e.getMessage()); 
     return "FailurePage"; 
    } 

    return "ApproveBulletin"; 
} 

risposta

15

Ho risolto il mio problema. Sto postando il mio codice a beneficio di chiunque altro abbia colpito questo thread con lo stesso problema. Ecco la mia forma.

<form:form action="approve" method="post"> 
    <table> 
     <tr> 
      <td colspan="2"><b>From:</b> <c:out value="${bulletin.name}" /></td> 
     </tr> 
     <tr> 
      <td colspan="2"><b>Subject:</b> <c:out 
        value="${bulletin.subject}" /></td> 
     </tr> 
     <tr> 
      <td colspan="2"><b>Date:</b> <c:out value="${bulletin.date}" /> 
       <br></td> 
     </tr> 
     <tr> 
      <td colspan="2"><t:notePrint note="${bulletin.note}" /> <input 
       type="hidden" name="id" value="${bulletin.id}" /></td> 
     </tr> 
     <tr> 
      <td><input type="submit" name="approve" value="Approve" /></td> 
      <td><input type="submit" name="deny" value="Deny" /></td> 
     </tr> 
    </table> 
    <br /> 
</form:form> 

Ecco i metodi del mio controller.

@RequestMapping(value = "/approve", method = RequestMethod.POST, params = { "approve" }) 
public String approve(@RequestParam int id, @RequestParam String approve, Model model) { 
    try { 
     bulletinDAO.approveBulletin(id); 
     model.addAttribute("approval", "Your bulletin has been approved."); 

     List<Bulletin> bulletins = bulletinDAO.getApprovedBulletins(); 
     model.addAttribute("bulletins", bulletins); 
    } catch (Exception e) { 
     System.out.println(e.getMessage()); 
     return "FailurePage"; 
    } 

    return "ApproveBulletin"; 
} 

@RequestMapping(value = "/approve", method = RequestMethod.POST, params = { "deny" }) 
public String deny(@RequestParam int id, @RequestParam String deny, Model model) { 
    try { 
     bulletinDAO.denyBulletin(id); 
     model.addAttribute("approval", "Your bulletin has been denied."); 

     List<Bulletin> bulletins = bulletinDAO.getApprovedBulletins(); 
     model.addAttribute("bulletins", bulletins); 
    } catch (Exception e) { 
     System.out.println(e.getMessage()); 
     return "FailurePage"; 
    } 

    return "ApproveBulletin"; 
} 
+0

E come è possibile testarlo con MockMVC? –

+0

Questo non è stato testato con MockMVC. Questo è stato testato utilizzando l'applicazione in Tomcat come un utente lo userebbe normalmente. –

9

di action è impostato su "/ approvare" ancora la mappatura del controller è la tua forma "/ approvazione/{action}/{id}"; il Servlet Dispatcher non ha modo di stabilire la connessione tra questi due.

Anche se il metodo era mappati in modo corretto, non avrebbe fatto quello che ci si aspetta di fare: si sta confondendo action e input e quello che corrispondono nella richiesta HTTP.

action imposta l'URL della richiesta di modulo, nel tuo caso è "/approva". parametro di ogni elemento <input>name viene utilizzato per aggiungere parametri HTTP con il valore di value, quindi la richiesta dovrebbe avere una combinazione di:

  • id=${id} (tutte le richieste)
  • approve=Approve (se l'utente fa clic su "approvare")
  • deny=Deny (se l'utente fa clic su "negare")

Per gestire entrambi i casi la firma del controllore dovrebbe essere cambiato a qualcosa di simile:

@RequestMapping(value = "/approve", method = RequestMethod.POST) 
public String approveBulletin(@RequestParam int id, 
      @RequestParam(required=false, defaultValue="") String approve, 
      @RequestParam(required=false, defaultValue="") String deny, 
      Model model) { 
    if (approve.equals("Approve")) { 
     // user clicked "approve" 
    } else if (deny.equals("Deny")) { 
     // user clicked "deny"    
    } else { 
     throw new IllegalArgumentException("Need either approve or deny!"); 
    } 

    // (...) 
} 

Ma preferisco suggerire la modifica dei parametri dei pulsanti di conferma:

<td><input type="submit" name="approveParam" value="approveVal" /></td> 
<td><input type="submit" name="approveParam" value="denyVal" /></td> 

In questo modo si ottiene sempre esattamente due parametri: id e approve, allora si può solo controllare il valore della approve per vedere se si trattava di una "approvare" o "negare":

public String approveBulletin(@RequestParam int id, 
     @RequestParam(value = "approveParam") String approveOrDeny, 
     Model model) { 
    if (approveOrDeny.equalsIgnoreCase("approveVal")) { 
     // user clicked "approve" 
    } else if (approveOrDeny.equalsIgnoreCase("denyVal")) { 
     // user clicked "deny" 
    } else { 
     // wrong parameter sent 
    } 

Che cosa aiuta a diagnosticare tali problemi (es. se si tratta del problema del client o del server) sta ispezionando la richiesta in uscita utilizzando gli strumenti web del browser (Firebug in Firefox, Strumenti per sviluppatori in Chrome, ecc.). Puoi facilmente catturare la richiesta e vedere quali sono i parametri, l'URL e il metodo HTTP e confrontarli con le tue aspettative.

+0

Ho aggiornato il mio post originale con l'ultima versione del mio codice, secondo i vostri suggerimenti. L'ID viene ora passato, ma non il valore del pulsante su cui ho fatto clic. –

+0

Puoi confermare se è possibile visualizzare il parametro "approva" o "nega" nella richiesta? (usando gli strumenti del browser) Ho appena provato che, in forma semplificata, invia correttamente il valore del pulsante. – kryger

+0

Ho appena trovato il parametro in Firebug. Sotto Net/All/Post, sto vedendo questo: id =% 25% 7Bid% 7D e approve = Approve. Come dovrei riscrivere il codice? –

Problemi correlati