2013-09-05 19 views
5

Ho un controller con un metodo GET scritta in questo modo:Spring Web MVC, @ModelAttribute e @RequestParam insieme

@Controller 
public class ThingController { 

    @RequestMapping(value = "/Thing.html", method = RequestMethod.GET) 
    public String editThing(@RequestParam("thingId") String thingId, @ModelAttribute ThingBean thing, BindingResult result) { 
     thing = <some service call using thingId> 
     logger.debug("The thing to edit is {}", thingBean); 
     return "thing/edit"; 
    } 
} 

Il fagiolo è corretto (getter e setter), la chiamata di servizio restituisce il ThingBean corretta con il thingId e la mia pagina JSP su thing/edit.jsp si presenta.

Il JSP è:

<html> 
<body> 
    <h1 id="title" class="title">Edit Thing</h1> 

<form:form id="thing" modelAttribute="thing"> 
    <form:input path="subject" id="subject" tabindex="1" /> 
    <form:textarea path="message" /> 

</form:form> 

</body> 
</html> 

Eppure, JSP visualizza i valori vuoti per l'oggetto e il messaggio. Sì, ci sono getter/setter su queste proprietà.

Ho un controller molto simile che funziona bene, tranne che non esiste @RequestParam nella firma del metodo GET-mappato lì.

Non ho visto da nessuna parte nei documenti WebMVC di Spring che dice che non posso farlo - perché non funziona? Perché l'oggetto ModelAttribute aggiornato non è associato al modulo JSP?

EDIT: molti molti luoghi diversi

Questo controller, e questo stesso modello per le chiamate GET ha funzionato - la variabile annotato con @ModelAttribute è riempito in con il metodo quindi disponibile per la pagina JSP da visualizzare. Perché, aggiungendo un'annotazione @RequestParam, si ferma?

@RequestMapping(value = "/Things.html", method = RequestMethod.GET) 
public String getThings(@ModelAttribute ThingForm thingForm, BindingResult result) { 

    try { 
     // need to get list of Things 
     List<Thing> Things = <service call that gets list of Things>; 
     thingForm.setThings(Things); 
     logger.debug("Things are {}", Things); 

    } 
    catch (ResourceNotFoundException e) { 
     return "error"; 
    } 

    logger.debug("Thing list loading - end"); 

    // Go to jsp 
    return "thing/list"; 
} 
+0

ci mostri il vostro altro controller.and Cosa M.Deinum ha detto è corretto. – beinghuman

+0

Domanda modificata per aggiungere un controesempio. –

+1

Come ho menzionato nella mia risposta nel controller che hai postato, stai ** riassegnando ** una variabile (l'argomento del metodo) NON stai chancing l'oggetto che passi nel metodo. Nel controller si dice che funziona ** si aggiunge ** qualcosa a un oggetto che funziona come un oggetto modello. Fondamentalmente è abbastanza diverso. –

risposta

7

Il problema è che stai solo assegnando un nuovo riferimento alla cosa, che non funzionerà mai in Java. Devi metterlo nel modello altrimenti non sarà noto al tuo punto di vista.

@RequestMapping(value = "/Thing.html", method = RequestMethod.GET) 
public String editThing(@RequestParam("thingId") String thingId, @ModelAttribute ThingBean thing, BindingResult result) { 
    thing = <some service call using thingId> // This is only assigning a new reference not updating 
    logger.debug("The thing to edit is {}", thingBean); 
    return "thing/edit"; 
} 

Così, invece fare questo

@RequestMapping(value = "/Thing.html", method = RequestMethod.GET) 
public String editThing(@RequestParam("thingId") String thingId, @ModelAttribute ThingBean thing, BindingResult result, Model model) { 
    thing = <some service call using thingId> 
    model.addAttribute("thing", thing); 
    logger.debug("The thing to edit is {}", thingBean); 
    return "thing/edit"; 
} 

Il che mi fa chiedere perché ancora di avere un attributo di modello in questo metodo? È fondamentalmente inutile.

Invece di quanto sopra vorrei fare qualcosa di simile

@ModelAttribute("thing") 
public Thing prepareModel(@RequestParam("thingId") String thingId) { 
    return thingSergice.findById(thingId); 
} 

Ora, questo metodo sarà invocato prima di ogni metodo di richiesta movimentazione. In cui puoi semplicemente fare riferimento ad esso invece di doverlo cercare ogni volta. (E a giudicare dal codice l'attributo del modello Thingbean nel vostro metodo è abbastanza inutile vorrei riscrivere quella al seguente)

@RequestMapping(value = "/Thing.html", method = RequestMethod.GET) 
public String editThing() { 
    return "thing/edit"; 
} 
+0

Così ho aggiunto un controesempio, e quel modello ha funzionato più e più volte. La variabile annotata con ModelAttribute è stata aggiornata dal metodo con annotazione GET ed era disponibile nel JSP. L'unica differenza con la mia nuova era aver aggiunto il parametro annotato RequestParam. –

+0

Come ho detto nel mio altro commento, non sono la stessa cosa ... In quello che non funziona si sta ** riassegnando ** mentre l'altro è ** aggiornando ** l'oggetto del modello. –

+0

ARGH. Stupida sindrome da programmatore. Ultimamente ho fatto troppa programmazione C laterale. Grazie, certo che lo vedo ora. –

1

Hai dimenticato di specificare il nome ModelAttribute, l'uso seguente correzione:

public String editThing(@RequestParam("thingId") String thingId, 
@ModelAttribute("thing") ThingBean thing, BindingResult result) { 
.... 
} 

Se sopra non funziona uso questo:

public String editThing(@RequestParam("thingId") String thingId, 
    @ModelAttribute("thing") ThingBean thing, BindingResult result, Model model) { 
      .... 
    thing = <some service call using thingId> 
    logger.debug("The thing to edit is {}", thingBean); 
    model.addAttribute("thing",thing); 
    return "thing/edit"; 
} 

Se possibile, mi consiglia di utilizzare una migliore denominazione convenzione per componenti, ad esempio: thingModel anziché thing. Ciò promuove una migliore leggibilità per te e per gli altri.

+0

Ho redatto il codice di produzione. Fidati di me, è chiamato meglio di "thing" –

+0

A proposito, non è necessario specificare il nome in Java 8. – naXa

Problemi correlati