Spring Data JPA: How to update a model elegantly?
The easiest way is an appropriately set up controller method:
@RequestMapping(value = "/users/{user}", method = RequestMethod.PATCH)
public … updateUser(@ModelAttribute User user) { … }
According to the reference documentation when this method is called the following steps happen:
- An instance of
User
needs to be obtained. This basically requires aConverter
fromString
toUser
to be registered with Spring MVC to convert the path segment extracted from the URI template into aUser
. If you're e.g. using Spring Data and enable its web support as described in its reference documentation, this will work out of the box. - After the existing instance was obtained, request data will be bound to the existing object.
- The bound object will be handed into the method.
Additional hints
- Don't use
GET
as HTTP method for updates.GET
is defined to be a safe operation (no side effects), which an update is not.PATCH
is the correct method here as it's defined to allow partial updates to an existing resource. - To submit form data into
PUT
andPATCH
requests, you need to register anHttpPutFormContentFilter
with the application as described here. I filed an issue with Spring Boot to register that by default.
diligent
Updated on July 19, 2022Comments
-
diligent almost 2 years
My Model is like this:
@Entity @Table(name = "user") public class User { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Column(name="email") private String email; @Column(name = "weblink") private String webLink; //getter & setter }
we collect form or mobile data via http request, and springmvc will make these data to a Model like user.
for example, I have a request like this:
http://localhost:8080/update?id=1919&[email protected]
in contoller, the request url and its paramters will be automaticlly trans to a
User
object.@RequestMapping(method = RequestMethod.GET, value = "/update0") public User update(@ModelAttribute("User") User user){ System.out.println(user.getId()); System.out.println(user.getEmail()); System.out.println(user.getWebLink()); return userRepository.save(test); }
if I have a record in mysql which id is 1919, and the columns (id, email, weblik) are all have values.
as you see, the user object which passed by web or mobile have two properties
http://localhost:8080/update?id=1919&[email protected]
id and email have values and weblink do not have.
So, if i execute
save
method, the columns email will be updated to[email protected]
, and the weblik field will also be updated toNULL
, but I don't want to update this field, I just want to update email field.I have two ways to fix the problem, but all of them are not elegant.
5.1 load user object first and update
User userExist = userRepository.findOne(user.getId()); userExist.setEmail(user.getEmail()); //or using //BeanUtil.copyProprty(formDto,modle) userRepository.save();
5.2 using
@DynamicUpdate
, but its not working.Is there other way to update the User Model and do not do some extra work.
Thanks in advance.
-
Mauro Monti over 8 years@oliver-gierke I got the step 1 working, but I can't make step 2 to work, I mean the object is obtained from the db passed into the method as parameter but the body of the request seems to be ignored. Per my understanding whatever I sent into the request body should be applied into the fetched object. Any suggestions? Do you have a working example to take a look? Thanks!
-
Mauro Monti over 8 yearsForget about it, I found the problem. HttpPutFormContentFilter wasnt being created because I am extending WebMvcConfigurerAdapter and that prevents the instantiation of WebMvcAutoConfiguration. Now I have another question, why HttpPutFormContentFilter is applied only when the content type is application/x-www-form-urlencoded? Is it possible to apply the same process but with an application/json content-type? Thanks!
-
Behrang over 7 years@MauroMonti did you find an elegant way to implement this for JSON and/or XML?
-
nissim_dev about 6 yearsIs there anyway to get Id from an authenticationObject for instantiation? Currently in the solution u posted, it requires userId to be sent in
"/users/{user}"
. I require this because when user with id 1 logs in, I just want them to goto the page/user
instead of/user/1
.When they want to update something they would still goto PATCH/user
instead of PATCH/user/1