I have a user entity that has many attributes (some fields not shown here):
@Entity
public class User {
@OneToOne(cascade = ALL, orphanRemoval = true)
private File avatar; // File is a custom class I have created
@NotEmpty
@NaturalId
private String name;
@Size(min = 6)
private String password;
@Enumerated(EnumType.STRING)
private Role role;
}
In my thymeleaf template I have a form that submits username, password and avatar (MultipartFile
). Now in my controller instead of these parameters...
@PostMapping("/register")
public String register(@RequestParam String username,
@RequestParam String password,
@RequestParam MultipartFile avatar) { ...
...I want to use @ModelAttribute @Valid User user
. My problem is that:
MultipartFile
should be extracted then stored in user entity (as a custom File
object),Role
should be set manually in the service class.How can I take advantage of @ModelAttribute
?
@ModelAttribute is an annotation that binds a method parameter or method return value to a named model attribute, and then exposes it to a web view. In this tutorial, we'll demonstrate the usability and functionality of this annotation through a common concept, a form submitted from a company's employee.
The @ModelAttribute annotation can be used at the parameter level or the method level. The use of this annotation at the parameter level is to accept the request form values while at the method level is to assign the default values to a model.
The @ModelAttribute annotation is used as part of a Spring MVC web app and can be used in two scenarios. Firstly, it can be used to inject data objects in the model before a JSP loads. This makes it particularly useful by ensuring that a JSP has all the data it needs to display itself.
In Spring MVC, the @ModelAttribute annotation binds a method parameter or method return value to a named model attribute and then exposes it to a web view. It refers to the property of the Model object.
Instead of trying to shoehorn everything into your User
class, write a UserDto
or UserForm
which you can convert from/to a User
. The UserForm
would be specialized for the web and converted to a User
later on.
The conversions you are talking about should be done in your controller (as that is ideally only a conversion layer before actually talking to your business services).
public class UserForm {
private MultipartFile avatar;
@NotEmpty
private String username;
@Size(min = 6)
@NotEmpty
private String password;
public UserForm() {}
public UserForm(String username) {
this.username = username;
}
static UserForm of(User user) {
return new UserForm(user.getUsername());
}
// getters/setters omitted for brevity
}
Then in your controller do what you intended to do (something like this):
@PostMapping("/register")
public String register(@ModelAttribute("user") UserForm userForm, BindingResult bindingResult) {
if (!bindingResult.hasErrors()) {
User user = new User();
user.setName(userForm.getUsername());
user.setPassword(encrypt(userForm.getPassword());
user.setAvataor(createFile(userForm.getAvatar());
userService.register(user);
return "success";
} else {
return "register";
}
}
This way you have a specialized object to fix your web based use cases, whilst keeping your actual User
object clean.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With