How can I transfer object fields from one method to other Thymeleaf - java

I have ReservationController that have 2 methods:
#GetMapping
public String getReservationPage(final Model model,
final #PathVariable String hotelId,
final #PathVariable String roomId) {
final RoomApi roomApi = roomClient.findById(roomId).getBody();
model.addAttribute("roomApi", roomApi);
model.addAttribute("hotelId", hotelId);
model.addAttribute("roomId", roomId);
model.addAttribute("reservationForm", new ReservationApi().toBuilder()
.room(roomApi)
.build());
return "reservation";
}
#PostMapping
public String createReservation(final #PathVariable String roomId,
final #PathVariable String hotelId,
final #ModelAttribute("reservationForm") ReservationApi reservationApi) {
final Reservation reservation = reservationMapper.toDomain(reservationApi);
reservationService.save(reservation);
return "redirect:/";
}
And I have one problem, that relate to the roomApi. So how can I transfer roomApi from the getReservationPage to the crateReservation in reservationForm. I also have thymeleaf page with some form, but when I click submit button, roomApi is null in reservation. I think thats because of thymeleaf form does not contain any information about roomApi in reservation, but Im addinig it with builder.
<form th:object="${reservationForm}"
method="post"
th:action="#{/hotels/{hotelId}/rooms/{roomId}/reservations(hotelId=${hotelId}, roomId=${roomId})}">
<div class="form-group">
<label for="additionalInformation">Additional Information</label>
<input type="text" th:field="*{additionalInformation}" th:name="additionalInformation" class="form-control form-control-sm" id="additionalInformation">
</div>>
<button type="submit">Reserve</button>
</form>

Related

Thymeleaf request parameter null value problem

I have a problem,my web app have a passcode form, user will give a Passcode string and app will riderict user to questions page for a spesific event. my controller will find this even by this passcode. i tried with this way but my passcode field is always null.
<form method="get" th:action="#{/findEvent(passcode=${passcode})}">
Passcode:<br>
<input type="text" th:name="${passcode}"><br>
<div>
<button type="submit">Find</button>
</div>
</form>
#GetMapping(value = "/findEvent")
public String resetPassword(#RequestParam(value="passcode",required=false) String passcode) {
if(passcode==null)
return "passcode";
Event event=eventService.findByPassCode(passcode);
List<Question> questions=questionService.findQuestionsByPasscode(passcode);
return "questions";
}
#RequestMapping(value = "/findEvent", method = RequestMethod.POST)
public String findEvent(#RequestParam("passcode") String passcode) {
Event event=eventService.findByPassCode(passcode);
List<Question> questions=questionService.findQuestionsByPasscode(passcode);
return "questions";
}
Same problem with mine
Request parameter with thymeleaf
How can i achieve this ?? can you help me
Use name="passcode" instead
<input type="text" name="passcode" value="1234" />
Since its the same as the object name, just use
#RequestParam String passcode

How to get modelattribute from GET to POST method

I am making a Spring MVC project and i want to register new user.In my first page user sumbit his details like full name,address,mobilenumber etc when user enter the details i will send a OTP on his mobile and Store OTP in CacheLoader.Then i redirect the otp page and also use flashAttribute to use in OTPController GET method.I want when user enter OTP the full data comes to POST method and i will validate OTP then i save the full data in DB.
UserDetailsController.java
#RequestMapping(method = RequestMethod.POST)
public String addUser(#Valid #ModelAttribute("addUser") UserPojo userPojo, BindingResult bindingResult,
Model modelMap, final RedirectAttributes redirectAttributes) {
otpService.clearOTP(userPojo.getPhoneNumber());
boolean validate = adminUserService.uniqueUserName(userPojo.getUserName());
if (validate == false) {
int otp = otpService.generateOTP(userPojo.getPhoneNumber());
String response = smsService.sendOtp(otp, userPojo.getPhoneNumber());
if(response.equals("OK")) {
redirectAttributes.addFlashAttribute("addUser", userPojo);
logger.debug(addUserPojo.toString());
return "redirect:/userotp";
}
logger.debug("response is-OTP Failed");
redirectAttributes.addFlashAttribute("error", "Problem is Send OTP");
return "redirect:/admin/adduser";
}
redirectAttributes.addFlashAttribute("error", "UserName Must Be Unique");
return "redirect:/admin/adduser";
}
OtpController.java
#RequestMapping(value = "/userotp", method = RequestMethod.GET)
public String showAddUser(#ModelAttribute("addUser") UserPojo userPojo,
final BindingResult mapping1BindingResult, final Model model, ModelMap map,
final RedirectAttributes redirectAttributes) {
logger.debug("Enter in the Method" + this.getClass().getSimpleName());
logger.debug("Data is" + addUserPojo.toString());
return "userotp";
}
#RequestMapping(value = "/userotp", method = RequestMethod.POST)
public String validateUser(
final BindingResult mapping1BindingResult, Model model, final RedirectAttributes redirectAttributes,
HttpServletRequest request) {
logger.debug("Enter in the Method" + this.getClass().getSimpleName());
return "userotp";
}
userotp.html
<form:form method="post">
<div class="" role="document" style="padding: 0px 30%;">
<div class=" box">
<h5 class="">User Moblie No. Verify</h5>
<div class="">
<label>Moblie Number For Otp</label> <form:input type="number"
class="form-control" name="otp" placeholder="Enter OTP"/>
<br> <br>
<div class="float-right">
<button type="reset" class="btn btn-secondary">Reset</button>
<button type="submit" class="btn btn-primary">Verify</button>
</div>
</div>
</div>
</div>
</form:form>
I want to get data UserDetails in OtpController POST method.Can anyone help me.
I think you should use #SessionAttributes. To use #SessionAttributes we can store modelAttribute in Session and when there is no use of modelAttribute. We can remove it.
We can remove it like this:
#RequestMapping(value = "/userotp", method = RequestMethod.POST)
public String validate(#ModelAttribute User user, WebRequest request, SessionStatus status) {
// your business logic
status.setComplete();
request.removeAttribute("user", WebRequest.SCOPE_SESSION);
return "userotp";
}

Customize items in form select

In my registration form, I have a field that give to users the possiblity to choose roles. But, I want to, only, show two roles : USER and MODERATOR.
But, I don't know how to proceed.
this registration form jsp :
<div class="row">
<div class="form-group col-md-12">
<label style="color:#ffffff;" class="col-md-3 control-lable" for="userProfiles">Roles</label>
<div class="col-md-7">
<form:select path="userProfiles" items="${roles}" multiple="true" itemValue="id" itemLabel="type" class="form-control input-sm" />
<div class="has-error">
<form:errors path="userProfiles" class="help-inline"/>
</div>
</div>
</div>
</div>
I have an enum : UserProfileType
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
}
And this is how it look :
This my controller, the part responsible of registration
//new user
#RequestMapping(value = "/registrationForm", method = RequestMethod.GET)
public String newUser(User user, ModelMap model) {
//User user = new User();
model.addAttribute("user", user);
model.addAttribute("loggedinuser", getPrincipal());
return "registrationForm";
}
//save user
#RequestMapping(value = { "/registrationForm" }, method = RequestMethod.POST)
public String saveUser1(#Valid User user, BindingResult result,
ModelMap model) {
if (result.hasErrors()) {
return "registrationForm";
}
if(!userService.isUserSSOUnique(user.getId(), user.getSsoId())){
FieldError ssoError =new FieldError("user","ssoId",messageSource.getMessage("non.unique.ssoId", new String[]{user.getSsoId()}, Locale.getDefault()));
result.addError(ssoError);
return "registrationForm";
}
userService.saveUser(user);
model.addAttribute("success", "User " + user.getFirstName() + " "+ user.getLastName() + " registered successfully");
model.addAttribute("loggedinuser", getPrincipal());
//return "success";
return "registrationsuccess";
}
I am using spring mvc/security and hibernate.
Thanks in advance
The data to be displayed by the page should be provided and manipulated by the controller. Filter the roles in your controller before handing over to the view.
Depending on how you are adding attributes to the model you can do it as foLlows (or any equivalent way as Spring MVC is flexible)
You could create methods in your Enum class to return the filtered values according to yours needs:
public enum UserProfileType implements Serializable{
USER("USER"),
DBA("DBA"),
ADMIN("ADMIN"),
MODERATOR("MODERATOR");
String userProfileType;
private UserProfileType(String userProfileType){
this.userProfileType = userProfileType;
}
public String getUserProfileType(){
return userProfileType;
}
public static List<UserProfileType> getAdminRoles(){
return Arrays.asList(UserProfileType.USER , UserProfileType.MODERATOR);
}
}
#ModelAttribute("roles")
public List<UserProfileType> roles(){
return UserProfileType.getAdminRoles();
}
You can also filter the roles in the view but its not recommended to have control logic in your view
<form:select path="userProfiles"multiple="true" class="form-control input-sm">
<c:forEach items="${roles}" var = "role">
<c:if test="${role.type eq 'USER' or role.type eq 'MODERATOR'}">
<form:option value="${role.id}" label="${role.type}"/>
</c:if>
</c:forEach>
</form:select>

Spring MVC Formatter and ManyToOne Entity

I am working on a spring mvc project. A Name class has a many to one relationship with a gender class. I have a Genderformatter to handle the select list needed for create and update name:
public class GenderFormatter implements Formatter<Gender> {
#Autowired
private GenderRepository genderRepository;
public String print(Gender gender, Locale locale) {
return gender.getId().toString();
}
public Gender parse(String id, Locale locale) throws ParseException {
Gender gender = this.genderRepository.findOne(Integer.valueOf(id));
return gender;
}
}
Here is relavent portion of the addupdatename.jsp
<form:form modelAttribute="name" method="${method}"
class="form-horizontal" id="add-name-form">
...
<!-- Gender Select List -->
<spring:bind path="gender">
<c:set var="cssGroup"
value="control-group ${status.error ? 'error' : '' }" />
<div class="${cssGroup}">
<label class="control-label">Gender</label>
<div class="controls">
<form:select path="gender">
<form:option value="${name.gender.id}" label="${name.gender.gender}" />
<form:options items="${genders}" itemValue="id" itemLabel="gender" />
</form:select>
<span class="help-inline">${status.errorMessage}</span>
</div>
</div>
</spring:bind>
The NameController relevant GET and POST:
#RequestMapping(value = "/names/new", method = RequestMethod.GET)
public String initCreationForm(ModelMap model) {
Name name = new Name();
model.addAttribute(name);
model.put("genders", this.nameAdminService.findGenders());
return "name/addupdatename";
}
#RequestMapping(value = "/names/new", method = RequestMethod.POST)
public String processCreationForm(#Valid Name name, BindingResult result,
SessionStatus status) {
if (result.hasErrors()) {
return "name/addupdatename";
} else {
this.nameRepository.save(name);
status.setComplete();
return "redirect:/names/" + name.getId();
}
}
This all works fine. Now I'm adding CRUD functions for the Gender entity and running into problems. The GenderController and jsp objects follow the same pattern as the Name code. As long as the GenderFormatter is registered as a conversion service, the gender forms wont process add or updates to the data. I assume because on the gender add or update form post, the formatter is trying to convert the gender field to a gender object.
Is there a way to specify when or which fields a formatter should format?

Syntactically incorrect request sent upon submitting form with invalid data in Spring MVC (which uses hibernate Validator)

Login form:
<f:form class="form-horizontal" method="post" action="/login"
commandName="logindata">
<fieldset>
<legend class="text-info">Login</legend>
<div class="control-group">
<f:label path="uname" class="control-label" for="uname">Username</f:label>
<div class="controls">
<f:input type="text" path="uname" name="uname" id="uname"
placeholder="Username" />
</div>
</div>
<div class="control-group">
<f:label path="pwd" class="control-label" for="pwd">Password</f:label>
<div class="controls">
<f:input type="password" path="pwd" name="pwd" id="pwd"
placeholder="Password" />
</div>
</div>
<div class="control-group">
<div class="controls">
<button type="submit" class="btn" id="login">
Login <i class="icon-chevron-right"></i>
</button>
</div>
</div>
<div id="errormsg" class="alert alert-error">${message}</div>
</fieldset>
</f:form>
the loginData class:
package com.demo.forms;
import org.hibernate.validator.constraints.Length;
import org.hibernate.validator.constraints.NotEmpty;
public class loginData {
#Length(min=4)
private String uname;
#NotEmpty
private String pwd;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
}
Controller methods for showing and submitting the form: (Shows homepage which contains signup form and login form)
#RequestMapping(value = "/", method=RequestMethod.GET)
public String showHome(Model model)
{
loginservice.logout();
model.addAttribute("logindata", new loginData());
model.addAttribute("signupdata", new signupData());
return "home";
}
Method called upon submitting login form:
#RequestMapping(value = "login", method=RequestMethod.POST)
public String submitloginForm(#Valid loginData logindata, SessionStatus state, Model model, BindingResult result)
{
if((loginservice.loggedin()) || (result.hasErrors()))
{
return showHome(model);
}
else
{
String uname = logindata.getUname();
String pwd = logindata.getPwd();
if(loginservice.login(uname, pwd))
{
model.addAttribute("user",uname);
return "redirect:profile";
}
else
{
model.addAttribute("message","Invalid Username/Password");
return showHome(model);
}
}
}
The login works fine when the data entered is 'valid' (either correct or wrong). However, when it is invalid, for instance, when the password field is empty or the username is less than four characters long, following error is shown:
The request sent by the client was syntactically incorrect.
Any idea how this might be fixed?
You have to modify the order of your arguments. Put the BindingResult result parameter always directly after the parameter with the #Valid annotation.
#RequestMapping(value = "login", method=RequestMethod.POST)
public String submitloginForm(#Valid loginData logindata, BindingResult result,
SessionStatus state, Model model)
This was even mentioned in this weeks This Week in Spring - March 5th, 2013 blog entry
Someone asked me this the other day and I felt like it was worthy of a
mention: in your Spring MVC #Controller class handler methods, make
sure that the BindingResult argument is immediately after the model or
command argument, like this: #RequestMapping(...) public String
handleRequest( #ModelAttribute #Valid YourCustomPojo attempt,
BindingResult result). In this example, handleRequest will validate
the POJO (YourCustomPojo) - checking the POJO for JSR303-annotations
and attempting to apply the constraints because the POJO is annotated
with #Valid - and stash any errors in the BindingResult, which it
makes available if we ask for it.
Spring will
0) determin the handler method
1) create an instance of loginData
2) populate it
3) validate it, and store the validation result in BindingResult
4) invoke the method (with loginData and BindingResult values), no matter whenever the binding Result contains an error or not

Categories