how to transfer data from one jsp form to another - java

I am writing a simple training application using spring hibernate where I save user data in parts, the user enters data during registration and in my account, I have a problem, I don’t know how to transfer data from the first form to the second on another jsp page, to transfer to another controller and save to database as data of one person
registration.jsp
<spring:form name="myForm" action="save-user" method="post"
modelAttribute="user" onsubmit="return validateForm()">
<spring:hidden path="id" />
<div class="center">
емайл: <br>
<spring:input path="userEmail" />
<br> <br>
</div>
<div class="center">
логин: <br>
<spring:input path="userLogin" />
<br> <br>
</div>
<div class="center">
пароль: <br>
<spring:input path="password" />
<br> <br>
</div>
<div class="center">
<input type="submit" value="зарегистрироваться">
</div>
</spring:form>
<form action="registration" method="post"></form>
RegistrationController{
#RequestMapping(value = "/save-user", method = RequestMethod.POST)
public ModelAndView saveUser(UserBean user) {
userService.saveUser(user);
Integer id = user.getId();
String email = user.getUserEmail();
String login = user.getUserLogin();
String password = user.getPassword();
Map<String, String> result = new HashMap<String, String>();
result.put("email", email);
result.put("id", String.valueOf(id));
result.put("login", login);
result.put("password", password);
return new ModelAndView("privateroom", result);
}
}
privateroom.jsp
<spring:form name="myForm_1" action="save-user-two" method="post"
modelAttribute="user" onsubmit="return validateForm()">
<spring:hidden path="${id}" />
<div class="center">
имя: <br>
<spring:input path="userName" />
<br> <br>
</div>
<div class="center">
фамилия: <br>
<spring:input path="userSurname" />
<br> <br>
</div>
<div class="center">
дата рождения: <br>
<spring:input path="userDateOfBirth" />
<br> <br>
</div>
<spring:hidden path="${email}"/>
<spring:hidden path="${login}"/>
<spring:hidden path="${password}"/>
<div class="center">
<input type="submit" value="дополнить данные">
</div>
</spring:form>
PrivateRoomController{
#RequestMapping(value = "/save-user-two", method = RequestMethod.POST)
public ModelAndView saveUser(UserBean user) {
userService.saveUser(user);
return new ModelAndView("privateroom");
}
}

In this case you can store the user information in Session every time the information submitted from the client (browser) to controller.
Note: I recommend not to send back the information to client browser to be stored in hidden fields, especially should not send back the password to client browser. You can send the remaining (email, id, login) if you really need to show them on the next page.
RegistrationController {
#RequestMapping(value = "/save-user", method = RequestMethod.POST)
public ModelAndView saveUser(UserBean user, HttpSession session) {
// Store user object in the user's session
session.setAttribute("user", user);
// Return back some information for showing purpose only
Map<String, String> result = new HashMap<String, String>();
result.put("email", user.getEmail());
result.put("id", String.valueOf(user.getId()));
result.put("login", user.getLogin());
return new ModelAndView("privateroom", result);
}
}
During the last submit, you can retrieve back the user information from Session and save it using userService.saveUser.
PrivateRoomController {
#RequestMapping(value = "/save-user-two", method = RequestMethod.POST)
public ModelAndView saveUser(UserBean user, HttpSession session) {
// Retrieve user object in the user's session
UserBean userFromSession = session.getAttribute("user");
// Update some additional values
userFromSession.setUserName(user.getUserName());
userFromSession.setUserSurename(user.getUserSurename());
userFromSession.setUserDateOfBirth(user.getUserDateOfBirth());
// Save to database at once
userService.saveUser(userFromSession);
return new ModelAndView("privateroom");
}
}

Related

Spring Boot Forms; hiding the path value and showing placeholder

I am having a small issue with Spring Boot forms displaying the information of the path value instead of the placeholder once you get to the editProfile.jsp. I want the input field to look like this;
Edit Profile Page instead of this Wrong Edit Profile. I do not want my users to have to click, select and delete the auto completed value. I want it to show the placeholder only and allow them to overwrite what is shown with ease.
This is the editProfile.jsp
<%--#elvariable id="editProfile" type=""--%>
<form:form method="POST" modelAttribute="editProfile">
<div class="MyForm form-group">
<h1>Edit Profile</h1>
<form:input type="email" class="MyInput" id="email" path="email" placeholder="${editProfile.email}" />
<form:button type="submit" class="from-control">Submit</form:button>
</div>
<div>
<img src="images/reg1.png" alt="picture">
</div>
</form:form>
</body>
</html>
This is the code specified in the Controller
#RequestMapping(value = "edit/{email}", method = RequestMethod.GET)
public String getEditUserData(#PathVariable("email") String email, Model model) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
model.addAttribute("editProfile", accountInstance);
return "editProfile";
}
#RequestMapping(value = "edit/{email}", method = RequestMethod.POST)
public String enterEditUserData(#ModelAttribute("login") AccountEntity accountForm, #PathVariable("email") String email, Model model ) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
accountInstance.setEmail(accountForm.getEmail());
accountRepo.save(accountInstance);
return "redirect:/login";
}
I have figured it out; You have to add a model of a new Entity, so the path variable does not fill in with the instance of the specific path value. Here is the new code, and compare it to the one I sent above.
#RequestMapping(value = "edit/{email}", method = RequestMethod.GET)
public String getEditUserData(#PathVariable("email") String email, Model model) {
AccountEntity accountInstance = accountRepo.findByEmail(email);
model.addAttribute("editProfile2", new AccountEntity());
model.addAttribute("editProfile1", accountInstance);
return "editProfile";
}
<%--#elvariable id="editProfile" type=""--%>
<%--#elvariable id="editProfile2" type=""--%>
<form:form method="POST" modelAttribute="editProfile2">
<div class="grid form-group">
<h1>Edit Profile</h1>
<form:input type="email" class="MyInput" id="email" path="email" placeholder='${editProfile1.email}' />
<form:button type="submit" class="from-control">Submit</form:button>
</div>

Update operation is not performing -Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]

I'm trying to develop an application in spring boot + thymeleaf, and I'm able to retrieve the logged in user details in the profile tab from the MySQL database, but when I try to change one or two field details (update) and hit the update button it is showing me an error message - Fri Sep 04 20:39:47 IST 2020
There was an unexpected error (type=Method Not Allowed, status=405).
Request method 'POST' not supported
see my controller code (I'm using #RestController annotated on top of the class)-
#RequestMapping(value = "/profile", method = RequestMethod.PUT)
public ModelAndView updateProfile(#ModelAttribute Customer customer, HttpSession session) {
ModelAndView model = new ModelAndView();
Customer exist = cRepo.findByCustEmail(customer.getCustEmail());
if(exist != null) {
if(exist.getCustEmail().equals(session.getAttribute("emailsession"))) {
cRepo.save(customer);
model.addObject("msg", "User Details has been successfully updated!!");
model.setViewName("profile");
}
}else {
model.addObject("exist", "Please enter correct email address!");
String email = (String) session.getAttribute("emailsession");
Customer cust = cRepo.findByCustEmail(email);
model.addObject("customer", cust);
model.setViewName("profile");
}
return model;
}
Thymleaf code (html) -
<div align="center" class="alert alert-success" th:if="${msg}" th:utext="${msg}"></div>
<div align="center" class="alert alert-danger" th:if="${exist}" th:utext="${exist}"></div>
<!-- Modal HTML -->
<div id="myModal">
<div class="modal-dialog modal-login">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Profile Details</h4>
</div>
<div class="modal-body">
<form name="myForm" th:action="#{/profile}" th:object="${customer}" method="post">
<div class="form-group">
<i class="fa fa-id-card"></i>
<input name="id" type="text" class="form-control" placeholder="Enter Id" th:field="${customer.custId}" disabled="true" required="required" />
</div>
<div class="form-group">
<i class="fa fa-user"></i>
<input name="name" type="text" class="form-control" placeholder="Enter Name" th:field="${customer.custName}" required="required" />
</div>
<div class="form-group">
<i class="fa fa-envelope"></i>
<input name="email" type="email" class="form-control" placeholder="Enter Email" th:field="${customer.custEmail}" required="required" />
</div>
<div class="form-group">
<i class="fa fa-lock"></i>
<input name="password" type="text" class="form-control" placeholder="Enter Password" th:field="${customer.custPassword}" required="required" />
</div>
<div class="form-group">
<input type="submit" class="btn btn-primary btn-block btn-lg" value="Update" />
</div>
</form>
</div>
</div>
</div>
</div>
I want when user login and visit he/she should be able to check his/her profile(which I'm able to do working code) and when the user wants to update few fields(1-2 based on choice) and hit update he/she should be able to update the details (not create new user or record) because when I use #Controller on top of class then this code work and create new user instead update.
Your controller is annotated with #RequestMapping(value = "/profile", method = RequestMethod.PUT) which makes it a PUT endpoint. However, your request is clearly a POST. If we look at your html form it contains method="post". HTML forms only support GET and POST as valid methods so you need to update your endpoint to be a POST endpoint.
tldr;
RequestMapping(value = "/profile", method = RequestMethod.PUT)
to
RequestMapping(value = "/profile", method = RequestMethod.POST)
You request mapping in is POST but Controller has set to accept request as PUT.
<form name="myForm" th:action="#{/profile}" th:object="${customer}" **method="post"**>
#RequestMapping(value = "/profile", method = **RequestMethod.PUT**)
Just keep these in similar way both should be same.
Please check what I find and resolve this.
#RequestMapping(value = "/profile" ,method = RequestMethod.POST)
public ModelAndView updateProfile(#ModelAttribute Customer customer, HttpSession session) {
ModelAndView model = new ModelAndView();
Customer exist = cRepo.findByCustEmail(customer.getCustEmail());
if(exist != null) {
if(exist.getCustEmail().equals(session.getAttribute("emailsession"))) {
**exist.setCustId(exist.getCustId());
exist.setCustName(customer.getCustName());
exist.setCustEmail(customer.getCustEmail());
exist.setCustPassword(customer.getCustPassword());**
cRepo.save(exist);
model.addObject("msg", "User Details has been successfully updated!!");
model.addObject("customer", exist);
model.setViewName("profile");
}
}else {
model.addObject("exist", "Please enter correct email address!");
String email = (String) session.getAttribute("emailsession");
Customer cust = cRepo.findByCustEmail(email);
model.addObject("customer", cust);
model.setViewName("profile");
}
return model;
}

How to send data from jsp to controller in spring using form

How to send data from jsp to controller in spring using form ?
<form:form action="${searchUrl}" method="post">
<div class="form-group">
<label class="control-label"> search by ID </label>
<br>
<input type="text" id="ticketId" placeholder=" Enter ticket ID ">
</div>
</form:form>
Could not able to get ticketId using this method
You need to declare name attribute (name="ticketId") and access the same on the controller. Like below.
JSP:
<input type="text" name="ticketId" id="ticketId" placeholder=" Enter ticket ID">
Controller:
#RequestParam(value = "ticketId", required = false) String ticketId
I hope it is helpful to you, for me it is working fine.
If you want to use spring forms, make sure to follow the below steps :
Step:1.In the spring controller, you should return the bean object like below to respected JSP.
Class User {
private String ticketId;
// setter & getter
}
#RequestMapping(value = "/test", method = RequestMethod.GET)
public String init(Model model) {
model.addAttribute("msg", "Please Enter Your Login Details");
model.addAttribute("loginBean", new User());
return "login";
}
Step:2 add a model attribute and add taglib in the JSP page.
<%#taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<form:form action="${searchUrl}" method="post"
modelAttribute="loginBean">
<div class="form-group">
<label class="control-label"> search by ID </label>
<br>
<form:input type="text" id="ticketId" path = "ticketId"
placeholder=" Enter ticket ID " />
</div>
</form:form>
Step : 3
#RequestMapping(value = "/test", method = RequestMethod.Post)
public String init(Model model,
#ModelAttribute("user") User user,BindingResult
result) {
sout("user"+user);
return "home";
}

Cannot read strings from form

I am writing form that lets user to change his password. Instead of passing User object to form, I am passing 3 empty Strings. Everything is okay, but when I am passing Submit, Strings returns as empty. Is there any way to get String from forms in Spring without packaging them into objects like changePasswordForm with 3 String fields?
My code:
Change password view:
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="${currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="${newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="${newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
User controller:
package io.gromo13.personalBlog.controller;
import io.gromo13.personalBlog.service.RoleService;
import io.gromo13.personalBlog.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import io.gromo13.personalBlog.model.User;
import javax.validation.Valid;
#Controller
#RequestMapping("/user")
#SessionAttributes("user")
public class UserController {
#Autowired
UserService userService;
#Autowired
RoleService roleService;
public void setUserService(UserService userService) {
this.userService = userService;
}
public void setRoleService(RoleService roleService) {
this.roleService = roleService;
}
#GetMapping("/{id}")
public String profile(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
return "/user/profile";
}
#GetMapping("/register")
public String register(Model model) {
model.addAttribute("roles", roleService.getAll());
model.addAttribute("user", new User());
return "/user/register";
}
#PostMapping("/register")
public String registerSubmit(#Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/register";
userService.add(user);
return "redirect:/admin/users";
}
#GetMapping("/edit/{id}")
public String edit(#PathVariable Long id, Model model) {
User user = userService.get(id);
model.addAttribute("user", user);
model.addAttribute("password", "");
return "/user/edit";
}
#PostMapping("/edit/{id}")
public String editSubmit(#ModelAttribute("user") #Valid User user, BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/edit";
userService.edit(user);
return "redirect:/admin/users";
}
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", "");
model.addAttribute("newPassword", "");
model.addAttribute("newPasswordConfirmation", "");
return "/user/changePassword";
}
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#ModelAttribute("currentPassword") String currentPassword,
#ModelAttribute("newPassword") String newPassword,
#ModelAttribute("newPasswordConfirmation") String newPasswordConfirmation,
BindingResult bindingResult) {
if (bindingResult.hasErrors())
return "/user/changePassword";
User user = userService.get(id);
if (newPassword.equals(newPasswordConfirmation) && user.getPassword().equals(currentPassword)) {
user.setPassword(newPassword);
userService.edit(user);
}
return "redirect:/admin/users";
}
#GetMapping("/delete/{id}")
public String delete(#PathVariable Long id) {
userService.delete(id);
return "redirect:/admin/users";
}
}
Actually my whole page is working fine, I just cannot read single Strings passed to forms without wrapping to objects.
Every tutorial about forms in Spring I found is passing object like xForm or User to view and read them. It works for me too, but I do not see sense in creating special object just for single form.
change th:field to name tag
<!DOCTYPE html>
<html lang="en"
xmlns:th="http://www.thymeleaf.org">
<head th:replace="/fragments/head"></head>
<body>
<div class="container">
<div th:replace="/fragments/header"> </div>
<div class="jumbotron">
<h1 class="display-4">Changing password</h1>
<form action="#" th:action="#{/user/changePassword/} + ${user.id}" method="post">
<div class="form-group">
<label>Current password</label>
<input type="password" name="currentPassword" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" name="newPassword" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" name="newPasswordConfirmation" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
</div>
<div th:replace="/fragments/footer"> </div>
</div>
</body>
</html>
remove this from controller
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("currentPassword", ""); //remove
model.addAttribute("newPassword", ""); //remove
model.addAttribute("newPasswordConfirmation", ""); //remove
return "/user/changePassword";
}
and here change ModelAttribute to RequestParam Annotation
#PostMapping("/changePassword/{id}")
public String changePasswordSubmit(#PathVariable Long id,
#RequestParam("currentPassword") String currentPassword,
#RequestParam("newPassword") String newPassword,
#RequestParam("newPasswordConfirmation") String newPasswordConfirmation) {
this sentence bindingResult not work because this validate a POJO using validations annotations
//if (bindingResult.hasErrors())
// return "/user/changePassword";
for this case the best way is create a new POJO with those fields and then validate them.
if you want to use the validation you need to create a POJO and add the constraints.
1)
public class ChangePass {
#Size(min = 8,max = 13, message = "error current password between {min} to {max}")
private String currentPassword;
#Size(min = 8,max = 13,message = "error new password between {min} to {max}")
private String newPassword;
//validate later
private String newPasswordConfirmation;
}
2)
then you need to add a instance of this POJO in the view.
#GetMapping("/changePassword/{id}")
public String changePasword(Model model) {
model.addAttribute("userPass", new ChangePass()); // adding model
return "/user/changePassword";
}
3)
in your form you need to fix 2 things add
th:object="${userPass}" and add th:field="*{currentPassword}" not th:field="${currenctPassword}" the difference is " * "
<form th:action="#{/user/changePassword/} + ${user.id}" method="post" th:object="${userPass}">
<div class="form-group">
<label>Current password</label>
<input type="password" th:field="*{currentPassword}" class="form-control" placeholder="Your current password"/>
</div>
<div class="form-group">
<label>New password</label>
<input type="password" th:field="*{newPassword}" class="form-control" placeholder="Your new password"/>
</div>
<div class="form-group">
<label>New password confirmation</label>
<input type="password" th:field="*{newPasswordConfirmation}" class="form-control" placeholder="Confirm your new password"/>
</div>
<button class="btn btn-primary">Submit</button>
<button class="btn btn-secondary">Reset</button>
</form>
4)
and the Post Method should be...
#PostMapping("/changePassword/{id}")
public String changePassword(#PathVariable Long id,
#ModelAttribute("userPass"),
#Valid ChangePass change,
BindingResult errors){
if(errors.hasErrors()){
return "/user/changePassword";
}
//your next code

Unable to bind list of checkboxes in Thymeleaf to get modified data POSTed back

I'm trying to write a UI for user management and one of the important things is ability to change user roles.
Model is simple, user belongs to many roles, role has many users.
The code below presents self contained #Controller for editing existing user:
#Controller
public class NewController {
final Role r1 = new Role("admin");
final Role r2 = new Role("user");
final Role r3 = new Role("editor");
final List<Role> allRoles = Arrays.asList(r1, r2, r3);
final List<Role> userRoles = Arrays.asList(r3);
#RequestMapping(value = "/edit", method = RequestMethod.GET)
public ModelAndView editUser() {
final User user = new User();
user.setEmail("asdasdsa#email.com");
user.setUsername("username");
user.setAuthorities(userRoles);
final ModelAndView mav = new ModelAndView("edit");
allRoles.stream()
.filter(r-> user.getAuthorities().contains(r))
.forEach(r -> r.setChecked(true));
mav.addObject("roles", allRoles);
mav.addObject("user", user);
return mav;
}
#RequestMapping(value = "/edit", method = RequestMethod.POST)
public ModelAndView updateUser(
#ModelAttribute("user") User user,
#ModelAttribute("roles") ArrayList<Role> roles,
ModelMap model) {
final List<Role> newRoles = roles.stream()
.filter(r -> r.isChecked() != null)
.filter(r -> r.isChecked() == true)
.collect(Collectors.toList());
user.setAuthorities(newRoles);
return new ModelAndView("redirect:/edit");
}
}
And that's my Spring-Thymeleaf page where I'm able to edit the user:
<form th:action="'/edit'" method="POST" enctype="utf8">
<div class="form-group row">
<label class="col-sm-3" th:text="#{label.user.id}">Id</label>
<span class="col-sm-5" th:text="${user.id}">id</span>
</div>
<div class="form-group row">
<label class="col-sm-3" th:text="#{label.user.username}">Username</label>
<input class="form-control" name="username" th:value="${user.username}" required="required"/></span>
</div>
<div class="form-group row">
<label class="col-sm-3" th:text="#{label.user.email}">email</label>
<input type="email" class="form-control" name="email" th:value="${user.email}"
required="required"/></span>
</div>
<div class="form-group row">
<label class="col-sm-3" th:text="#{label.user.password}">password</label>
<input id="password" class="form-control" name="password" value=""
type="password"/></span>
</div>
<div class="form-group row">
<label class="col-sm-3" th:text="#{label.user.confirmPass}">confirm</label>
<input id="matchPassword" class="form-control" name="matchingPassword" value=""
type="password"/></span>
</div>
<div th:each="item, index : ${roles}">
<input type="checkbox"
th:text="${item.authority}"
name="${item.authority}"
th:checked="${item.checked}" />
</div>
<button type="submit" class="btn btn-primary" th:text="#{label.edit.save}">save</button>
</form>
When I click 'Save' button, updateUser method gets triggered, but ArrayList roles is empty. Other values for User model are passed correctly, I can change username/email/password without problems, user bean is populated correctly.
Ok, solved it differently:
Fragment of the HTML page with checkbox handling should be:
<th:block th:each="role : ${roles}">
<input type="checkbox"
name="newRoles"
th:checked="${role.checked}"
th:value="${role.id}"/>
<label th:text="${role.authority}"></label>
</th:block>
So when you submit the form, you get list of Role ids inside newRoles RequestParam, and that's my POST controller:
#RequestMapping(value = "/users/{id}/edit", method = RequestMethod.POST)
public ModelAndView updateUser(
#ModelAttribute("user") User user,
#RequestParam(value = "newRoles") ArrayList<Long> roles,
BindingResult bindingResult , Model model) {
final List<Role> newRoles =
roles.stream()
.map(id -> roleService.findOne(id))
.collect(Collectors.toList());
user.setAuthorities(newRoles);
userService.update(user);
return new ModelAndView("redirect:/users");
}

Categories

Resources