How to pass model from view to controller in Spring? - java

I have a controller
#RequestMapping(value = "/admin/manage/{id}", method = RequestMethod.GET)
public ModelAndView goManage(#PathVariable int id) {
UserAccount userAccount = userAccountService.findUserAccount(id);
ModelAndView mav = new ModelAndView("admin/manage");
mav.addObject("userAccount", userAccount);
return mav;
}
and i pass userAccount model to manage.jsp view. In view I display this model. Example:
<div id="info">
<label>Login:</label><label>${userAccount.userDto.username}</label><br />
<label>Name:</label><label>${userAccount.userDto.firstName}
${userAccount.userDto.lastName}</label>
</div>
<form:form
action="${pageContext.request.contextPath}/admin/go"
modelAttribute="userAccount" method="post">
<input class="myButton" type="submit" value="Go" />
</form:form>
And it's ok, but I want pass this model userAccount from view further to next controller when I clicked button Go. My above form implementation doesen't work. How I can pass object from view? It's possible?
#RequestMapping(value = "/admin/go", method = RequestMethod.POST)
public ModelAndView goWithDrawalInvestment(
#ModelAttribute("userAccount") UserAccount userAccount) {
userAccount.setBalance(0);
mav.addObject("userAccount", userAccountDto);
return mav;
}

Related

How to get a List object in a #ModelAttribute in the controller?

I have the following code.
It retrieves listPlaces from the db and binds to the view.
That works fine.
Then I want to update the data on the view, click save and submit that info back to the controller for the controller to update the db with the change.
But when I click save, the code is not entering into the savePlaces method.
Instead it is throwing this error:
No primary or default constructor found for interface java.util.List
What I need to change to retrieve the List object in the savePlaces method?
Entity class
#Entity
public class Place implements Serializable{
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private Long idPlace;
#Column(length=50)
private String place;
public Long getIdPlace() {
return idPlace;
}
public void setIdPlace(Long idPlace) {
this.idPlace = idPlace;
}
public String getPlace() {
return place;
}
public void setPlace(String place) {
this.place = place;
}
}
Controller GET method
#RequestMapping(method = RequestMethod.GET, value = "/myplaces")
public ModelAndView initPlaces() {
List<Place> listPlaces = placesRepository.getPlaces();
ModelAndView modelAndView = new ModelAndView("/myplaces.html");
modelAndView.addObject("listPlaces", listPlaces);
return modelAndView;
}
View
<form action="/myplaces" method="post">
<th:block th:each="place, itemStat : *{listPlaces}">
<input type="text" th:value="*{listPlaces[__${itemStat.index}__].place}" />
</th:block>
<input type="submit" name="btnSave" value="Save"/>
Controller save method executed on btnSave click
#RequestMapping(value = "/myplaces", params = "btnSave", method = RequestMethod.POST)
public ModelAndView savePlaces(#ModelAttribute List<Place> listPlaces) {
//update db code here
ModelAndView modelAndView = new ModelAndView("/myplaces.html");
modelAndView.addObject("listPlaces", listPlaces);
return modelAndView;
}

Not able to hit controller with Spring Boot

Can anyone please help me as I am not able to hit the controller for one of my URLs. Here is the code:
#Controller
#RequestMapping("/posts")
public class PostController {
#Autowired
private PostRepository repository;
#RequestMapping(value = "", method = RequestMethod.GET)
public String listPosts(Model model) {
model.addAttribute("posts", repository.findAll());
return "postList";
}
#RequestMapping(value = "/new", method = RequestMethod.GET)
public String newProject() {
return "newPost";
}
#RequestMapping(value = "/create", method = RequestMethod.POST)
public ModelAndView create(#RequestParam("postDescription") String comment) {
repository.save(new Posts());
return new ModelAndView("redirect:/postList");
}
//...
}
and the JSP:
<form action="<spring:url value="/posts/create" />">
<div class="form-group">
<label for="postDescription">Post</label>
<button type="submit" id="save" class="btn btn-primary">Save</button>
</form>
I'm able to hit RegistrationController but not PostController.
Do I need to configure something else?

Checking for Null Attribute in Thymeleaf Template

I am new to Thymeleaf and am trying to check for a null attribute in my template
<form th:action="#{/saveUser/__${user.id}__}" th:object="${user}" method="post">
The form submits fine if I am editing an existing user with an id already defined, however using the same form to add a new user I get the following
HTTP Status 400 - http://localhost:8080/myApp/saveUser/null"
My controller:
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("user") User user, #PathVariable Long id, Model model) {
model.addAttribute("user", user);
userRepo.save(user); //JPA Repo
return "success";
}
My thought is if I can check for the null id I can plug in a unique one somehow. Better yet, if I could make use of the #GeneratedValue set on my User object's ID then I think I'd be in good shape
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
EDIT Including my user edit form method which returns the same form but pre-populated with the User's model Attributes
#RequestMapping(value = "/edit/user/{id}", method = RequestMethod.GET)
public ModelAndView getUserEditForm(#PathVariable Long id, Model model){
ModelAndView mav = new ModelAndView("userForm");
User user = userRepo.findOne(id);
mav.addObject("userForm", user);
return mav;
}
EDIT 2 Including my whole form (ID is "hidden" from user)
<form th:action="#{/saveUser/__${user.id}__}" th:object="${user}" method="post">
<input id="id" type="hidden" th:field="*{id}" />
<input id="id" type="text" th:field="*{name}" />
<input id="id" type="text" th:field="*{address}" />
<button id="save">Save</button>
</form>
As per discussion assuming that the following method is the one you call which should populate the user object and thus form fails on submission:
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("user") User user, #PathVariable Long id, Model model) {
model.addAttribute("user", user);
userRepo.save(user); //JPA Repo
return "success";
}
The reason that method doesn't work is because you are potentially passing an empty user object to begin with.
To remediate this you need to implement checks to ensure object is not null prior to calling the page.
one solution could be:
#RequestMapping(value = "/saveUser/{id}", method = RequestMethod.POST)
public String saveUser(#ModelAttribute("user") User user, #PathVariable Long id, Model model) {
userRepo.save(user); //JPA Repo
if(user == null) // check if user object is empty
user = new User(); // if user is empty, then instantiate a new user object
model.addAttribute("user", user);
return "success";
}
The above will ensure that when you passing user object to the model, it is always available.
I've temporarily resolved this by creating a new #Controller to accept "null" at the end of the #RequestMapping (which kind of makes sense when creating a new user with a dynamic ID?), and just reimplementing the same logic. So when this is called
http://localhost:8080/myApp/saveUser/null"
It is mapped to my new Controller
#RequestMapping(value = "/saveUser/null", method = RequestMethod.GET)
public ModelAndView saveUser(#ModelAttribute("user") User user, Model model){
model.addAttribute("user", user);
userRepo.save(user);
return "success";
}

Spring MVC user data update issue

I’ve an issue with update of user data in Spring MVC app.
So, I have user and I have FORM filled with data from JSP. Now data from FORM overrides all fields of user data with null, except entered in jsp.
In another case – user’s data overrides form’s data.
Help me, please, to do it correctly. I’ve tried a lot of variants but nothing works.
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView updateView(#ModelAttribute(value = "updateForm")
HttpSession session) {
User user = (User) session.getAttribute("user");
UserForm updateForm = new UserForm();
updateForm.setUser(user);
return new ModelAndView("profileupdate", "updateForm", updateForm);
}
#RequestMapping(method = RequestMethod.POST)
public String updateUserProcess(#ModelAttribute(value = "updateForm")
UserForm updateForm,
BindingResult result, Model model,
HttpSession session) {
User user = (User) session.getAttribute("user");
model.addAttribute("updateForm", updateForm);
if (result.hasErrors()) {
return "profileupdate";
}
if (!updatingUser(updateForm, model, user))
model.addAttribute("errorMsg", "Login or Email is already in use!");
return "profileupdate";
}
return "updated";
}
private boolean updatingUser(UserForm updateForm, Model model, User user) {
fillForm(updateForm, user);
user = updateForm.getUser();
//Another case
//user = updateForm.getUser();
//fillForm(updateForm, user);
return userService.updateUser(user);
}
private void fillForm(UserForm updateForm, User user) {
updateForm.setUserId(user.getUserId());
updateForm.setLogin(user.getLogin());
updateForm.setPassword(user.getPassword());
updateForm.setEmail(user.getEmail());
}
}
** UserForm class**
public class UserForm {
private Integer userId;
private String login;
private String name;
private String password;
private String email;
public UserForm() {
}
public User getUser() {
User user = new User();
user.setUserId(userId);
user.setLogin(login);
user.setPassword(password);
user.setName(name);
user.setEmail(email);
return user;
}
public void setUser(User user) {
this.userId = user.getUserId();
this.login = user.getLogin();
this.password = user.getPassword();
this.name = user.getName();
this.email = user.getEmail();
………………………….
getters and setters
}
This is my DAO and Service
#Override
public boolean updateUser(User user) {
return userDao.updateUser(user);
}
#Override
#Transactional
public boolean updateUser(User user) {
if (isUserExists(user)) {
return false;
}
currentSession().update(user);
return true;
}
Updade.jsp
<sf:form name="login"
method="POST"
action="${app}/edit"
modelAttribute="updateForm"
enctype="application/x-www-form-urlencoded">
<label for="login">Login:</label><br>
<input name="login" id="login" type="text" value=""/> <br>
<sf:errors path="login" cssClass="error"/><br>
<br><label for="password">Password:</label>
<br><input name="password" id="password" type="password" value=""/>
<br>
<sf:errors path="password" cssClass="error"/><br>
<br> <input type="submit" name="submit" value="Update"/>
</sf:form>
It would be very hard for spring or hibernate to guess what values are null because user wants them to be null and what are null because they do not have to be touched. You as the progammer have to supply a fully completed object.
There are two common ways to do that :
you suppose null fields should be left untouched and modify fillform accordingly :
if (updateForm.getUserId().isEmpty()) { updateForm.setUserId(user.getUserId()); }
...
you prefil your form with current User value in the get that precedes the post (more common unless you need a post without the get part before)
EDIT
To prefill the form (the jsp part seems to be fine) your controller should put a filled UserFormin the model in the GET method.
#RequestMapping(method = RequestMethod.GET)
public String updateView(#ModelAttribute(value = "updateForm")
UserForm updateForm,
HttpSession session) {
User user = (User) session.getAttribute("user");
updateForm.setUser(user);
return "profileupdate";
}
with updateForm being implicitely in model due to the #ModelAttribute annotation, or
#RequestMapping(method = RequestMethod.GET)
public ModelAndView updateView(HttpSession session) {
updateForm = new UserForm();
User user = (User) session.getAttribute("user");
updateForm.setUser(user);
return new ModelAndView("profileupdate", "updateForm", updateForm);
}
I also removed the value="/edit" because it is not on updateUserProcess and I assumed the "/edit" was allready established on controller.
Well, main problem was in the path on JSP. Instead of handle request through controller I've set just a link to the page. So, advice - be careful and attentive with mappings.
WRONG VERSION OF LINK
<form name="redaction"
action="${pageContext.request.contextPath}/updatepage.jsp"
method="GET"
enctype="application/x-www-form-urlencoded">
<input type="submit" name="submit" value="Redaction"/>
</form>
RIGHT VERSION OF LINK
<form name="redaction"
action="${pageContext.request.contextPath}/edit"
method="GET"
enctype="application/x-www-form-urlencoded">
<input type="submit" name="submit" value="Redaction"/>
</form>
And controller
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public String updateView(UserForm userForm,
HttpSession session,
ModelMap model) {
User user = (User) session.getAttribute("user");
userForm.setUser(user);
model.addAttribute("userForm", userForm);
return "profileupdate";
}
#RequestMapping(value = "/edit.do", method = RequestMethod.POST)
public String updateUserProcess(#ModelAttribute(value = "userForm")
UserForm userForm,
BindingResult result, Model model,
HttpSession session) {
User user = (User) session.getAttribute("user");
session.getAttribute("userForm");
model.addAttribute("userForm", userForm);
userValidator.validate(userForm, result);
if (result.hasErrors()) {
logger.error("Validation error");
return "profileupdate";
}
if (!updatingUser(userForm, model, user)) {
logger.error("User update error!");
logger.error("Login or Email is already in use!");
model.addAttribute("errorMsg", "Login or Email is already in use!");
return "profileupdate";
}
logger.info("User updated!");
return "newuserprofile";
}
Have you checked the values of user.getUserID,user.getLogin(),user.getPassword(),user.getEmail()
in the following segment of code? Is it null or the data you recieved in the model object User?
updateForm.setUserId(user.getUserId());
updateForm.setLogin(user.getLogin());
updateForm.setPassword(user.getPassword());
updateForm.setEmail(user.getEmail());
Please post the code for userService.updateUser(user) so that we can understand more.

How to pass ID to controller?

I have a form
<form method="POST" action="/user/${id}">
<input type="text" name="id" value="${id}" placeholder="Input Id">
<button>Get User</button>
</form>
How to pass id to controller?
#RequestMapping (value = "/user/{id}", method = RequestMethod.POST)
public String getStudent(#PathVariable ("id") Integer id, Model model){
User savedUser = userRepository.get(id);
model.addAttribute("user", savedUser);
return "user";
}
You could do this way , consider i am passing the ${id} value through the query string
Get User
And in your controller,
#RequestMapping ("user")
public String getStudent(#RequestParam Integer id, Model model){
User savedUser = userRepository.get(id);
model.addAttribute("user", savedUser);
return "user";
}
Hope this helps !

Categories