Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring MVC + Hibernate: Partial model update from browser

When only displaying a part of a Spring MVC model bean, is there a way to only update in the model what comes back from the browser?

Let's say we have a User class (public properties only in this example, of course):

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

Now I display the first three properties as input fields in a JSP and want to update the object in the database accordingly. Only these 3 parameters should be updated, NOT the fourth one. One way to accomplish this would be

@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);
}

but this would mean hardcoding all properties that could change, which I don't like too much.

Is there any way to determine what fields to update based on what the user was allowed to change? That mechanism should be smarter than just assuming that everything that's in the request parameters may be changed, otherwise any savvy user could manually inject additional fields into a request.

Using @Entity(dynamicUpdate=true) does not solve the problem either in my eyes, as I'm not getting the whole User object back in the request, and doing so would open up many security holes.

Am I missing a nice feature in Spring or is there any other way to conceptually solve for this problem? Any hints are greatly appreciated!

like image 375
usimon Avatar asked Dec 22 '12 20:12

usimon


1 Answers

See this question to know how to use @InitBinder to allow/prevent some model fields to be bound by Spring to request parameters. This allows making sure that the subscriptionExpiration can't be modified by injecting a request parameter.

And see the documentation for how to use the @ModelAttribute annotation on methods and on method arguments to load a user from the database and add it to the model before the @RequestMapping method is called, and to populate this user with request parameters when the @RequestMapping method is called. This allows getting a user from the DB and have Spring populate it with ne values coming from the request. All you have to do is validate the new state of the user and save it to the database.

like image 152
JB Nizet Avatar answered Sep 21 '22 14:09

JB Nizet