How to pass multiple form parameter in "th:action" using themleaf - spring-mvc

I am trying to pass parameter in th:action
<form class="form-inline" th:object="${search}" method="get" action="search.html" th:action="#{'/hotels/'+${search.location}+'/'+${search.adults}+'/'+${search.dateCheckOut}+'/'+${search.dateCheckIn}}" id="search-hotel-form">
<select class="selectpicker form-control input-lt" th:field="*{location}" id="city">
<option value="delhi">Delhi</option>
</select>
<input type='text' th:field="*{dateCheckIn}" id="datetimepicker1" />
<input type='text' th:field="*{dateCheckOut}" id="datetimepicker2" />
</form>
then Spring MVC contoller part
#RequestMapping(value = "/hotelsparam/{dateCheckIn}/{dateCheckOut}/{location}", method = RequestMethod.POST)
public ModelAndView searchHotel(#PathVariable("dateCheckOut") Date dateCheckOut, #PathVariable("dateCheckIn") Date dateCheckIn,#PathVariable("location") String location, BindingResult bindingResult) throws ParseException {....
//remove implemntation to make it precise
}
but getting error is
HTTP Status 500 - Request processing failed; nested exception is java.text.ParseException: Unparseable date: "null"
URL Part seem like this
http://localhost:8080/hotels/null/0/null/null?location=delhi&dateCheckIn=04%2F07%2F2015+09%3A00&dateCheckOut=04%2F07%2F2015+20%3A00&adults=1

Related

MultipartFile always null Spring MVC return Response 400 for Upload Excel

I have a problem when uploading using multipartfile. Always return response 400. Required request part files is not present. I have tried many ways. but none worked
i have tried to register CommonsMultipartResolver. but still didnt work for me.
#RequestMapping(value = "/viewFormReportUpload.html",method = RequestMethod.POST)
public ModelAndView uploadFormPage(#ModelAttribute("viewForm") ViewFormDownload viewForm,
#RequestParam("file") MultipartFile files, BindingResult result) throws IOException {
//some code
}
<form:input path="files" type="file" id="file" name="files" accept=".xls,.xlsx" class="form-control" />
try this
<form:input path="files" type="file" id="file" name="file" accept=".xls,.xlsx" class="form-control" />

Saving record in a proper way

I have a problem with saving records to DB with Spring-Mvc and Thymeleaf.
When I click "Update" button on record, to enter the update form (included beneath), all values are in place correctly, but, when I want to subbmit, an error occur. There is no any stacktrace in console, only error in web page, that I am not able to solve.
This is my code:
Controller:
#GetMapping("/{maltId}")
public ModelAndView showMalt(#PathVariable("maltId") Long maltId) {
ModelAndView mav = new ModelAndView("malt/malt-show");
mav.addObject(maltService.findById(maltId));
return mav;
}
#GetMapping("/{maltId}/edit")
public String initUpdateMaltForm(#PathVariable("maltId") Long maltId, Model model) {
model.addAttribute("malt", maltService.findById(maltId));
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
}
#PostMapping("/{maltId}/edit")
public String processUpdateMaltForm(#Valid Malt malt, BindingResult result, #PathVariable("maltId") Long maltId) {
if (result.hasErrors()) {
return VIEWS_MALT_CREATE_OR_UPDATE_FORM;
} else {
malt.setId(maltId);
Malt savedMalt = maltService.save(malt);
return "redirect:/malt/" + savedMalt.getId();
}
}
Model:
#Column(name="malt_name")
private String maltName;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="producer_id")
private Producer producer;
#Column(name="malt_filling")
private int maltFilling;
#Column(name="malt_ebc")
private int maltEbc;
#Column(name="malt_usage")
private String maltUsage;
#ManyToOne(fetch=FetchType.LAZY)
#JoinColumn(name="country_id")
private Country country;
#ManyToMany(mappedBy="malts")
private Set<Batch> batches;
This is the view:
<body>
<form th:object="${malt}" th:action="#{/malt/}" method="post">
<input type="hidden" th:field="*{id}" />
<label>Malt name:</label>
<input type="text" class="form-control" th:field="*{maltName}" />
<label>Producer:</label>
<input type="text" class="form-control"
th:field="*{producer.producerName}" />
<label>Country:</label>
<select class="form-control" th:field="*{country.id}">
<option value="0">Select country</option>
<option th:each="country : ${countries}"
th:value="${country?.id}"
th:text="${country?.countryName}">
</option>
</select>
<label>Malt filling:</label>
<input type="text" class="form-control"
th:field="*{maltFilling}" />
<label>Malt usage:</label>
<input type="text" class="form-control"
th:field="*{maltUsage}" />
<label>Malt EBC:</label>
<input type="number" class="form-control"
th:field="*{maltEbc}" />
<button class="submit-button" type="submit">Submit</button>
</form>
</body>
When I hit Submit button, I get this error:
Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Wed May 15 22:46:22 CEST 2019
There was an unexpected error (type=Not Found, status=404).
No message available
I have tried couple of different approaches, but nothing helps, and since there is no stacktrace in console, I have no idea what is wrong here.
Link to repo: https://github.com/fangirsan/maruszka-new
No stack trace 404 normally indicates that there is no mapping. Since you have, potentially, provided only a part of your Controller I assume that the causation for this is the code in your view right here:
<form th:object="${malt}" th:action="#{/malt/}" method="post">
The action takes to ("/malt/"), however, your controller has not got mapping for this?!
I expect that this should fix it:
<form th:object="${malt}" th:action="#{${'/' + malt.id + '/edit'}}" method="post">
Update
Had a look at your controller and you have the following annotations on your class
#Controller
#RequestMapping("/malt")
public class MaltController{..
#RequestMapping("/malt") will now make your path to save ../malt/{id}/edit'. The code below now should work:
<form th:object="${malt}" th:action="#{${'/malt/' + malt.id + '/edit'}}" method="post">
On using "#{${...}}"
#{} is a link variable, contents within this tag will be appended to the applications root context, e.g., at Stack Overflow #{'/posts'} would result with https://stackoverflow.com/posts
The ${} is a variable expression which will return a String or the object's .toString() value.
If we want to pass a variable within #{} link variable we must include the ${} variable within it, thus resulting in :
#{${'/hope/this/helps' + yourVariable}}

Spring MVC is confusing get and post methods with the same request mapping

I have a login controller that I've mapped the "/login" path to two different methods. One will be called for get and the other for post.
#RequestMapping(value = "/login", method = RequestMethod.GET)
public String login(Model model){
LoginDto loginDto = new LoginDto();
model.addAttribute("loginDto", loginDto);
return "home/login";
}
#RequestMapping(value = "/login", method = RequestMethod.POST)
public String doLogin(#Valid LoginDto loginDto, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "home/login";
}
return "redirect:/";
}
I have the thymeleaf form
<form method="POST" th:action="#{/login}" th:object="${loginDto}">
<div class="form-group-row">
<label> Email </label>
<input type = "text" th:field = "*{email}"/>
<span th:if="${#fields.hasErrors('email')}" th:errors = "*{email}"></span>
</div>
<div>
<label> Password </label>
<input type = "text" th:field = "*{password}"/>
</div>
<input type="submit" />
</form>
When enter data and click submit the method with the GET request is called. I know this from inserting breakpoints in both methods. Also the url now has a ?errors at the end of it. I've also changed the url mapping to the second method to "doLogin" like this
#RequestMapping(value = "/dologin", method = RequestMethod.POST)
public String doLogin(#Valid LoginDto loginDto, BindingResult bindingResult){
if(bindingResult.hasErrors()){
return "home/login";
}
return "redirect:/";
}
and changed the form to this
<form method="POST" th:action="#{/dologin}" th:object="${loginDto}">
<div class="form-group-row">
<label> Email </label>
<input type = "text" th:field = "*{email}"/>
<span th:if="${#fields.hasErrors('email')}" th:errors = "*{email}"></span>
</div>
<div>
<label> Password </label>
<input type = "text" th:field = "*{password}"/>
</div>
<input type="submit" />
</form>
and it works. I can enter data and hit the submit button and I'm in the doLogin method. However, I would like to keep this mapping of GET and POST to the same url to do different things based on the request method.
Further more, when I created the form at first, I forgot to specify a method="post" and while testing it submitted get requests to "/login" from this form. Perhaps that wired something up that needs to be unwired.
Is this a bug? I can map the same url with different request methods to other controller methods but this one doesn't seem to want to work. Any Ideas?
I've figured it out. The reason the method that is mapped to the POST request is because I'm using spring security and it's not completely set up. The login page for spring security was mapped to /login as well and the appended
localhost/login?error
to the url string is something spring security appends when there is an error with the login process. I have not set up authentication with spring security yet so it believes there's an error. I will continue on setting up spring security but this is the reason my POST request was not mapped to the doLogin method.

ASP.NET WEB API Not able to retrieve Post Parameters

I trying to retrieve post parameters in web API but I do get null values everytime.
My html
<form method="POST" action="http://localhost:16192/update" name="myform">
<input name="title" type="text"/>
<input name="isbn" type="text"/>
<input name="author" type="text"/>
<input type="submit" value="Submit"/>
</form>
And My WebAPI
[HttpPost]
[Route("UPDATE/")]
public String updateRecord([FromBody]String title,String isbn="", String author="")
{
return "Updated";
}
The updateRecord method is being called but I always get null values. Any help would be greatly appreciated.
[HttpPost]
[Route("UPDATE/")]
public String updateRecord([FromBody]dynamic values)
{
var title = values.title.Value;
....
return "Updated";
}
or you can create a DTO object (paragraph 2):
http://encosia.com/using-jquery-to-post-frombody-parameters-to-web-api/

Spring 3.1 MVC and Security: both login and registration form (multiple forms) on same page get submitted

I'm using Spring (3.1), Spring MVC (3.1) and Spring Security (3.0) in combination and I've put together a single JSP page that has two forms on it; One is a form to login and the other is a form to register (i.e. create a new user).
For the register form, I use the Spring form tags, backed up by a controller to handle the request but for the login form I don't bother with the Spring form tags as I don't believe they're needed. There is also no controller that I need to write to handle the form submission as Spring Security takes care of authenticating so long as the request is submitted to j_spring_security_check.
The register form is working fine but the login form is a problem. It seems that when I click the submit button on the login form, the registration form is also submitted, or at least Spring thinks I'm trying to submit that form. Here is the JSP:
<form id="loginform" method="POST" action="<c:url value='j_spring_security_check'/>">
<label for="existing_email">Email:</label>
<input name="j_username" id="existing_email" type="text" value="${SPRING_SECURITY_LAST_USERNAME}" />
<label for="existing_password">Password:</label>
<input name="j_password" id="existing_password" type="password" />
<input id="login-form-submit" type="submit" value="Sign in" />
</form>
<form:form id="registrationform" modelAttribute="user" method="POST" action="register">
<form:label path="username" for="email">Email:</form:label>
<form:input path="username" name="username" id="email" type="text" />
<form:errors path="username" cssClass="formError" />
<form:label path="password" for="password">Password:</form:label>
<form:input path="password" name="password" id="password" type="password" />
<form:errors path="password" cssClass="formError" />
<input id="registration-form-submit" type="submit" value="Sign up" />
</form:form>
Notice that form tags for the input of type submit are not present and this seems to be a normal thing to do in the examples I've seen. Adding form tags to the submit button I guess doesn't make sense as it doesn't map to anything on the target object (user in this case).
When I click the "Sign in" button I get the following exception:
SEVERE: Servlet.service() for servlet [appServlet] in context with path [/project1] threw exception [An exception occurred processing JSP page /WEB-INF/views/registration.jsp at line 29
28: <form:form id="registrationform" modelAttribute="user" method="POST" action="register">
29: <form:label path="username" for="username">Username:</form:label>
30: <form:input path="username" name="username" id="username" type="text" />
31: <form:errors path="username" cssClass="formError" />
32:
Stacktrace:] with root cause
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'user' available as request attribute
at org.springframework.web.servlet.support.BindStatus.<init>(BindStatus.java:141)
This I recognise from cases where you forget to include the modelAttribute attribute in form:form, but of course I don't want to submit this form to my controller.
I have a feeling there is a mistake I'm making or a simple solution. Can anyone recommend a way around this or perhaps a different approach?
Here is the controller method that handles requests to register in case that's needed:
#RequestMapping(value = "**/register", method = RequestMethod.POST)
public String registerUser(#ModelAttribute("user") #Validated User user, BindingResult errors, ModelMap model) {
if (errors.hasErrors()) {
return "registration";
}
// Other stuff then...
return "profile"
}
If you are using "user" modelAttribute in form tag then a non-null request attribute must be present with name "user".
One way to add that in request attribute is what you did in your answer above. Other ways are:
(1) Add in ModelMap:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
model.addAttribute("user", new User());
model.addAttribute("error", "true");
return "registration";
}
(2) Add in request scope (Using WebRequest or HttpServletRequest):
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model, WebRequest webRequest) {
webRequest.setAttribute("user", new User(), WebRequest.SCOPE_REQUEST);
model.addAttribute("error", "true");
return "registration";
}
(3) Use #ModelAttribute on method:
#ModelAttribute("user")
public User user() {
return new User();
}
Please also see Using #ModelAttribute on a method and Using #ModelAttribute on a method argument
Also note that you don't have to use type attribute. See form:input and form:password.
I think the problem is specifically when a login fails and the same page is served up, albeit on a different URL path and so through a different controller method. Therefore my original suspicion that the issue is that both forms are submitted may be something of a red herring, though I still don't fully understand what's going on and that may yet have something to do with it. In any case, this is what corrected the problem for me:
I had a controller method that originally looked like this:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(ModelMap model) {
model.addAttribute("error", "true");
return "registration";
}
In the Spring Security context I specify /loginfailed as the path to go to by default if a login attempt fails. This is where it seems the user object is needed so if I alter the signature as follows it all works:
#RequestMapping(value = "/loginfailed", method = RequestMethod.GET)
public String loginFailed(#ModelAttribute("user") User user, BindingResult errors, ModelMap model) {
model.addAttribute("error", "true");
return "registration";
}
Any comments/clarification welcome from others.

Resources