Editing data marked as unique - spring

So I have my model which briefly looks like this:
#Column
#NotNull
#Size(min = 3)
private String firstname;
#Column
#NotNull
private String lastname;
#Column
#UniqueUsername(message = "Such username already exists")
private String username;
Then there is the controller
#RequestMapping(value = "editUser/{id}", method = RequestMethod.POST)
public String editUser(#Valid #ModelAttribute("user") User user, BindingResult bindingResult, #PathVariable Long id, Model model) {
if (bindingResult.hasErrors()) {
System.out.println(bindingResult.getAllErrors());
return "editUser" ;
}
model.addAttribute("roles", roleRepository.findAll());
model.addAttribute("user", userService.findOne(id));
userService.editUser(id, user);
return "redirect:/admin/users";
}
this is the view
I'm using thymeleaf as my template engine.
So I've got the simplest form there is consisting of firstname, lastname, username
and I'd like to be able to edit only lastname but when I send the form it violates the unique constraint on my username field ( which is kinda obvious ).
The goal is to be able to edit one of the user's attributes but preserving the others. How do I do it?

Related

Multiple Use of validations in Spring Boot

I have an API with validation on it.
public class ModelVo {
#NotBlank(message = "...")
private String name;
#Pattern(regex="...", message = "...")
private String lastName;
...
}
I use of it
#PostMapping("/path1")
public ResponseEntity<RestResponse<Object>> create(#Valid #RequestBody ModelVo modelvo){
Now I want use of this validation for other method( for instance update API) again but I don't like #Pattern annotation on lastName fild work for second method. Is it possible?
Assuming that for create() you want to validate lastName with #Pattern but for update() you don't want to validate lastName you can achieve this with validation groups.
Your Controller:
#PostMapping("/path1")
public ResponseEntity<RestResponse<Object>> create(#Validated #RequestBody
ModelVo modelvo){
#PutMapping("/path1")
public ResponseEntity<RestResponse<Object>> update(#Validated(BasicInfo.class) #RequestBody
ModelVo modelvo){
Your Model class:
public class ModelVo {
#NotBlank(message = "...", groups = BasicInfo.class)
private String name;
#Pattern(regex="...", message = "...")
private String lastName;
}
You also need to create the BasicInfo class but that has nothing special.
You may get more information from the following links:
https://www.baeldung.com/spring-valid-vs-validated
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/validation/annotation/Validated.html

How do I link two entities within a #RestController?

I have the following endpoint:
#PostMapping
Employee createEmployee(#Valid #RequestBody Employee newEmployee, BindingResult bindingResult) {
return employeeRepository.save(newEmployee);
}
I can send POST requests as JSON and have an employee created, but how do I link associated entities, such as a Department entity?
When I send a post request, it looks like this (I know it's not valid JSON, it's just browser console output):
departmentId: 1
emailAddress: "dillon#james.com"
firstName: "Dillon"
lastName: "James"
phoneNumber: undefined
The department exists in my database, and has an ID of 1. I thought that Spring would automatically set the departmentId somehow on my Employee model, but it doesn't seem to do that, or I must be missing something.
I'm basically trying to set the department of the newly created employee, but how I have it currently doesn't seem to do so.
For reference, this is how my Employee entity is defined:
#Entity
#Getter
#Setter
public class Employee {
#Id
#GeneratedValue
private Long id;
#NotNull
private String firstName;
#NotNull
private String lastName;
#NotNull
#Column(unique = true)
private String emailAddress;
#ManyToOne
private Department department;
private String phoneNumber;
}

Form validation in thymeleaf by Springboot

I am new to the Springboot and Thymeleaf, I am creating a web where i am using form validation where I am trying to validate fields from an entity class to validate non empty fields.
import javax.validation.constraints.NotBlank;
public class Student {
#NotBlank(message = "Name required")
public String name;
#NotBlank(message = "email required")
public String email;
#NotBlank(message = "address required")
public String address;
#NotBlank(message = "username required")
public String username;
#NotBlank(message = "password required")
public String password;
'''
constructor
getter and setter
'''
}
It is not showing error in my html file, showing error on server.
If any one has any idea please help me.
In order this to work add #valid annotation next to #ModelAttribute("student").
public String addUser(#Valid #ModelAttribute("student") Student student, BindingResult result, Model model){
And also try adding #NotEmpty above the field of Student entity. #NotEmpty will check if the object has empty strings.
Try this,
public String addUser(#Valid #ModelAttribute("student") Student student, Model model){
...
}
Also, add #NotNull on entity attributes and check once.
Try out this:
public String addUser(#Valid #ModelAttribute("student") Student student, BindingResult result, Model model){
Also, add #NotNull on entity attributes and check once.

Spring 3 mvc #Valid annotation doesn't work with List<Entity> property

I want to update an entity, which has a one-to-many List collection of other entity. When the handler method gets called, the validation doesn't seem to run on the collection. I've read the documentation, and searched stackoverflow, but did not find anything useful.
Model:
#Entity
public class Employee {
#Id
#GeneratedValue
private int employeeId;
#NotEmpty
private String name;
#Min(value=18)
private int age;
#OneToMany(mappedBy="parent",cascade=CascadeType.ALL)
private List<Child> children;
//getters,setters
}
#Entity
public class Child {
#Id
#GeneratedValue
private int childId;
#Column(nullable=false)
#NotNull
#Size(min=1,message="Child's name must not be empty")
private String childName;
#Max(value=18)
private Integer age;
#ManyToOne
#JoinColumn(name="employeeId")
private Employee parent;
//getters,setters
}
In the controller:
#RequestMapping(value = { "/edit/{id}" }, method = RequestMethod.POST)
private String update(#PathVariable int id, ModelMap model, #Valid Employee employee, BindingResult result) {
if (result.hasErrors()) {
return "employee/edit";
}
employeeDao.merge(employee);
return "redirect:../list";
}
The validation works for the simple properties of the Employee bean, but not for the elements in the children list.
How can this be fixed?
Seems like you should decorate your children list with #Valid annotation, as described here.
It should look something like this:
#OneToMany(mappedBy="parent",cascade=CascadeType.ALL)
#Valid
private List<Child> children;

Values of #PathVariable and #ModelAttribute overlapping

I have an User object stored in the session with #SessionAttributes. And a straight-forward method decorated with #ModelAttribute in order to initialize it whenever the session's value is null.
User class:
#Entity
#Table( name="USER")
public class User implements java.io.Serializable {
private Long id;
private String username;
private String password;
....
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name ="ID")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
...
Controller:
#RequestMapping("/item")
#Controller
#SessionAttributes({"user"})
public class MyController {
#ModelAttribute method:
#ModelAttribute("user")
public User createUser(Principal principal) {
return userService.findByUsername(principal.getName());
}
It all seems to work as expected except in this particular method:
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showItem(#PathVariable("id") Long id, #ModelAttribute("user") User user,
Model uiModel) {
...
}
The problem is that User.id is being set with #PathVariable("id"). I believe I ran into this with #RequestParam too. I'm assuming that's because both have the same name and type. After reading Spring's documentation (see below) I'm assuming this is expected behavior:
The next step is data binding. The WebDataBinder class matches request parameter names — including query string parameters and form fields — to model attribute fields by name. Matching fields are populated after type conversion (from String to the target field type) has been applied where necessary.
However, I would think this scenario is fairly common, how are other people handling this? If my findings are correct and this is expected behavior (or bug), this seems to be very error prone.
Possible solutions:
Change #PathVariable("id") to #PathVariable("somethingElse"). Works but it's not as straightforward with #RequestParam (e.g. I don't know how to change jqgrid's request parameter id to something else but this is another issue).
Change #PathVariable("id") type from Long to Int. This will make User.id and id types differ but the cast to Long looks ugly :)
Don't use #ModelAttribute here and query the DB for User again. Not consistent with other methods and involves redundant DB calls.
Any suggestions?
How about this approach -
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showItem(#PathVariable("id") Long id,
Model uiModel) {
User user = (User)uiModel.asMap().get("user");
...
}
use #SessionAttribute
#RequestMapping(value = "/{id}", method = RequestMethod.GET)
public String showItem(#PathVariable("id") Long id, #SessionAttribute("user") User user,
Model uiModel) {
...
}

Resources