2012-12-22 21 views
5

Quando si visualizza solo una parte di un bean di modello Spring MVC, esiste un modo per aggiornare solo nel modello cosa viene restituito dal browser?Spring MVC + Hibernate: aggiornamento parziale del modello dal browser

Diciamo che abbiamo una classe utente (proprietà pubbliche solo in questo esempio, ovviamente):

public class User { 
    public String firstName; 
    public String lastName; 
    public String email; 
    public Date subscriptionExpiration; 
} 

Adesso visualizzare le prime tre proprietà come campi di input in un JSP e desidera aggiornare l'oggetto in il database di conseguenza. Solo questi 3 parametri dovrebbero essere aggiornati, NON il quarto. Un modo per ottenere questo risultato sarebbe

@RequestMapping("/user/{userId}", method=RequestMethod.POST) 
public String saveChanges(@PathVariable userId, User user, Model model) { 
    User oldUser = User.loadFromDB(userId); 
    oldUser.firstName = user.firstName; 
    oldUser.lastName = user.lastName; 
    oldUser.email = user.email; 
    oldUser.saveToDB(); 

    model.addAttribute("user", oldUser); 
} 

ma questo significherebbe hardcoding tutte le proprietà che potrebbero cambiare, che non mi piacciono troppo.

Esiste un modo per determinare quali campi aggiornare in base a ciò che l'utente è stato autorizzato a modificare? Questo meccanismo dovrebbe essere più intelligente del semplice presupposto che tutto ciò che è nei parametri della richiesta possa essere modificato, altrimenti qualsiasi utente esperto potrebbe inserire manualmente campi aggiuntivi in ​​una richiesta.

L'utilizzo di @Entity (dynamicUpdate = true) non risolve il problema ai miei occhi, poiché non riesco a recuperare l'intero oggetto Utente nella richiesta, e così facendo si aprono molte falle nella sicurezza.

Mi manca una bella funzionalità in primavera o esiste un altro modo per risolvere concettualmente questo problema? Ogni suggerimento è molto apprezzato!

risposta

3

Vedi this question sapere come utilizzare @InitBinder per consentire/impedire che alcuni campi modello di essere vincolato entro la primavera per richiedere i parametri. Ciò consente di assicurarsi che subscriptionExpiration non possa essere modificato iniettando un parametro di richiesta.

E vedere the documentation per come utilizzare l'annotazione @ModelAttribute sui metodi e sugli argomenti del metodo per caricare un utente dal database e aggiungerlo al modello prima che venga chiamato il metodo @RequestMapping e per popolare questo utente con i parametri di richiesta quando viene chiamato il metodo @RequestMapping. Ciò consente di ottenere un utente dal DB e far compilare Spring con i valori ne provenienti dalla richiesta. Tutto ciò che devi fare è convalidare il nuovo stato dell'utente e salvarlo nel database.

2

penso che il metodo

BeanUtils.copyProperties(Object source, Object target, String[] ignoreProperties) 

fa ciò che si vuole. Copia tutte le proprietà da un oggetto a un altro senza toccare le proprietà definite in String[] ignoreProperties.

Copia i valori delle proprietà del bean di origine specificato nel bean di destinazione specificato, ignorando le "ignoreProperties" fornite.

Nota: le classi di origine e di destinazione non devono necessariamente corrispondere o essere derivate l'una dall'altra, a condizione che le proprietà corrispondano. Qualsiasi proprietà del bean che il bean di origine espone ma il bean di destinazione non verrà ignorata in modo silenzioso.

Questo è solo un metodo di convenienza. Per esigenze di trasferimento più complesse, prendere in considerazione l'utilizzo di un BeanWrapper completo.

API Documentation

+0

Per ora ho fatto qualcosa del genere; Sto usando annotazioni personalizzate sui campi per controllare se verranno aggiornati e quindi analizzandoli per ottenere un elenco di ignoreProperties. Funziona bene, ma mi piacerebbe evitare di definirlo manualmente. Grazie per l'input però! – usimon

0

È possibile leggere l'oggetto dal database prima e associare quindi la richiesta. È possibile trovare un esempio a FuWeSta-Sample.

Utilizza uno helper-bean che deve essere inizializzato da Spring.

0

Un'opzione consiste nell'utilizzare campi nascosti nel modulo. un'opzione con svantaggi, ma funziona per alcuni casi

0

La bella funzione che stai cercando è @ModelAttribute. Presumo che il tuo modulo pubblicherà anche l'id dell'utente.

public class UserController { 

    @ModelAttribute 
    public User getUser(@RequestParam(value = "id", required = false) Long id) { 
     return User.loadFromDB(id); 
    } 

    @RequestMapping("/user/{id}", method=RequestMethod.POST) 
    public String saveChanges(@ModelAttribute User user, BindingResult bindingResult, Model model) { 

     if (bindingResult.hasErrors()) { 
      // return ... 
     } 

     // model.asMap().clear(); 

     user.saveToDB(); 
     // return ... 
    } 
} 
Problemi correlati