Spring sets #PostMapping fields from GET url query? - java

My setup is as follows:
I have a form and a table on the same page: localhost:8080/persons?firstname=frank
This shows all persons with firstname accordingly.
From the same page, it is possible to submit a form for creating new persons:
<form action="/persons" method="POST">
<input type="hidden" name="_method" value="POST"/>
<input type="text" name="firstname"/>
<input type="text" name="lastname"/>
<input type="submit" value="Create"/>
</form>
Problem: when I actually POST the form content to the Spring #Controller, the following content gets send:
URL: /persons?firstname=frank
Request Body: _method=post&firstname=&lastname=doe
Spring then magically merges GET-query params and POST form params into one DTO, and results in a PersonDto that has both firstname + lastname set
#PostMapping("/persons")
public void addPerson(PersonDto p) {
//p.firstname => Frank, p.lastname = Doe
}
PersonDto {
public String firstname, lastname, age;
}
Somehow Spring derives the request body values also from the get-query url parameters. Why??

To my knowledge, just like you can map the request body to an Object, you can also do it with query parameters.
The reason might be the following:
In Spring MVC, "request parameters" map to query parameters, form
data, and parts in multipart requests. This is because the Servlet API
combines query parameters and form data into a single map called
"parameters", and that includes automatic parsing of the request body.
Reference documentation: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/bind/annotation/RequestParam.html
Since the parameters are merged into a single map, you can get all of them in a single Object.

Related

How to make a Thymeleaf url expression and bind it to a #RequestParam annotation

My form is based on Thymeleaf, I am not using tables because it has many fields.
In the form I have 3 buttons, one is a submit and the others are links. With a link button I want to make a query using a parameter that sends a string to the controller.
I want to get the string that was passed in the URL to the controller and receive the data with an #RequestParam annotation.
I have no error messages, what happens is that the string reaches the controller empty.
This is my link button:
<a class="btn btn-success text-white btn-sm mr-3 " style="border-radius: 16px;" th:href="#{/config/item/items/select(productId=${item.productId})}">
Search
</a>
This is my text field where the user places the query:
<div class="col-2 form-group"
th:classappend="${#fields.hasErrors('item.productId')}? 'has-error':''">
<label for="productId"><strong>Item id </strong></label> <input
type="text" class="form-control" id="productId" name="productId"
th:field="${item.productId}">
</div>
And all this goes inside my form:
<form th:action="#{/config/item/items/save}" method="get"
th:model="${item}">
I have used these two but with no results:
th:href="#{'/config/item/items/select'+${item.productId}}"
th:href="#{|/config/item/items/select${item.productId}|}"
I have reviewed the documentation provided by Thymeleaf at: https://www.thymeleaf.org/doc/articles/standardurlsyntax.html, in chapter number nine.
And I have also seen tutorials but it doesn't work.
If you want to use the #RequestParam annotation you need to add a parameter in your link.
Your code should be something like:
th:href="#{select(productId=${item.productId})"
(According you added the object item to your template)
In your controller "select" you have to use the annotation #RequestParam to retrieve the info:
#GetMapping (path = "/select")
public String list(Model model,
#RequestParam(name = "productId") int productId) {
// rest of the code
}

Spring REST Request method 'DELETE', 'POST', 'PUT' not supported [duplicate]

I have the following method in my controller
#RequestMapping(value = "processPurchase/{poid}", method = RequestMethod.DELETE)
public String processOrder(#PathVariable int poid) {
// do some processing
return acceptPurchaseForm;
}
My HTML
<form id="purchase-list-form" class="form-horizontal" action="/MyNewApp/processPurchase/" method="post">
<input type="hidden" name="_method" value="delete">
<input type="hidden" name="poid" value="">
With the above I still get the following error
WARN : org.springframework.web.servlet.PageNotFound - Request method 'DELETE' not supported
Any help appreciated.
First of all, I assume you have the HiddenHttpMethodFilter configured in your web.xml. It is required to convert your _method with value delete to the DELETE RequestMethod
Secondly, the poid is being passed in the body of the request but in your controller, you are expecting it to be passed in the URL itself. This might explain why Spring is unable to map the request.
EDIT 1:
To pass poid in URL, you will have to include in your form action when your HTML is generated. It depends on your view technology (I use Freemarker) but you would be required to do something like this:
<form action="/MyNewApp/processPurchase/${poid}" method="post">
Assuming that the poid is written to the model that is binded to your view.

Validate a single field against a result from a service in Spring MVC

I can't figure out how to do a simple, 1-field validation where I check the value against a service (or really any other logic check).
Most of the form validation I see uses a class to hold form data using javax.validation and marking up with attributes like #NotNull, #Min(10), etc. And then checking a BindingResult.hasErrors(). Like here: https://spring.io/guides/gs/validating-form-input/
I'm trying to do this for a single field and I want to validate against what a service will return to me rather than one of those validation attributes.
What do I put in my POST handler in the controller to get this going?
This is what I have in my controller to manage the result from the form
#RequestMapping(value = "/myController", method=RequestMethod.POST)
public String checkFieldVal(#RequestParam String valFromForm){
if(!myService.isThisValueGood(valFromForm)) {
//Show the user their value is bad
}
//return to some other page
}
And this is in my JSP (something simple like this):
<form id="form" method="POST">
<label for="valueToCheck">What's your value:</label>
<input type="text" id="valueToCheck" name="valueToCheck"></input>
<input type="submit" value="Submit">
</form >
Try to replace this:
<form id="form" method="POST">
With adding the action like this:
<form action="myController" id="form" method="POST">
And replace this:
#RequestMapping(value = "/myController", method=RequestMethod.POST)
public String checkFieldVal(#RequestParam String valFromForm){
With adding the right name:
#RequestMapping(value = "/myController", method=RequestMethod.POST)
public String checkFieldVal(#RequestParam("valueToCheck") String valueToCheck){
The param name must match in both controller and html.
#RequestParam String valFromForm
<input ... name="valueToCheck">
Option 1: Leaving jsp as it is, you change controller code as,
#RequestParam String valueToCheck
Or you may add qualifier to parameter name as,
#RequestParam("valueToCheck") String valFromForm
Option 2: Leaving controller as it is, you change jsp as,
<input ... name="valFromForm">

Can I tell spring to ignore query parameters?

If I submit this form:
<form id="confirmForm" method="POST">
<input type="hidden" name="guid" value="guidval"/>
</form>
to this url:
/AltRT?guid=guidval
mapped to this controller method:
#RequestMapping(method = RequestMethod.POST)
public String indexPost(#RequestParam String guid)
I am getting both values for my guid. So the value of guid is guidval,guidval. I would like to only get the value from the form.
Is there any way tell Spring to ignore query string parameters?
EDIT for more clarification: The query string is left over from another (get) request. So, if I could clear the query string that would work as well. Also, I do not want edit the name of the form input because I want this post endpoint to be available to other services without having to change them as well.
You cannot do so because the query string will be sent in the HTTP message body of a POST request, http://www.w3schools.com/tags/ref_httpmethods.asp
There are two ways I could think of now
set the form attribute action
<form id="confirmForm" method="POST" action="AltRT">
<input type="hidden" name="guid" value="guidval" />
</form>
convert the form data into JSON object to send it over and then catch it with #RequestBody in Spring if you have to use the original URL.

Do Spring MVC controller look for ids or names?

If I have the following HTML form:
<form id="myForm" action="/myFormHandler" method="post">
<input type="hidden" id="fizz-id" name="fizz" value="3" />
<input type="hidden" id="buzz-id" name="buzz" value="6" />
</form>
(Notice no submit button). And then I have the following jQuery:
$("#someButton").click(function() {
$("#myForm").submit();
});
Then on the server-side (Spring MVC controller), do the hidden field ids or names get sent to the handler method?
#RequestMapping(value = "/myFormHandler.html", method = RequestMethod.POST)
public ModelAndView handleMyForm(
#RequestParam("fizz-id") String fizz,
#RequestParam("buzz-id") String buzz) {
// Should I be looking for "fizz-id" or "fizz"???
}
Thanks in advance.
Its the name attribute that is sent to the server, so in this case you should look for "fizz".
The id attribute is just used for client side interaction, it is not sent in the request to the server.
with a post request ,it is the name attribute of a HTML element that is used to access it using request.getParameter.

Categories