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.
Related
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.
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.
My RequestController:
#Controller
#RequestMapping("/request")
public class RequestsController {
private static final Logger log = LoggerFactory.getLogger(TmtApplication.class);
#Autowired
RequestRepository requestRepository;
#Autowired
UsersRepository usersRepository;
#RequestMapping("/save")
String saveRequest()
{
Request requestObj = new Request(usersRepository.findOne(1L), new Date());
requestObj.setDescription("I got so bored");
requestObj.setStatus(false);
requestObj.setRequestDate(new Date());
requestRepository.save(requestObj);
return "index";
}
}
My button:
<input type="submit" value="Submit Request" style="display: block;">
I'm trying to get my button to fire off this request. What should I add to my HTML to initiate the call for /save?
Update:
Form:
<form action="/request/save" method="post" commandName="requestData">
<input type="text" id="dateInput" value="" style="display: none;"/>
<div style="width: 200px;"><input type="submit" value="Submit Request" style="display: block;">
</div>
</form>
Controller:
#RequestMapping(value = "/save", method = RequestMethod.POST)
String saveRequest(#ModelAttribute("requestData") Request requestData, Map<String, Object> map,
HttpServletRequest request)
{
Request requestObj = new Request(usersRepository.findOne(1L), new Date());
requestObj.setDescription(requestData.getDescription());
requestObj.setStatus(false);
requestObj.setRequestDate(requestData.getRequestDate());
requestRepository.save(requestObj);
return "save";
}
To get this to work using the spring code as-is, you must surround your tag with a form.
<form action="save">
<input type="submit" value="Submit Request" style="display: block;">
</form>
In addition, you must be calling this from the correct URL to get it to work. The form action can be relative to the page you're on, or relative to the root of the URL.
You have two options to hit the RequestMapping, which resolves to:
/request/save
One is to use a relative action. You'll have to serve your HTML up at this url:
{server:port}/request
and then your action should be:
"save"
The second option is to use an absolute path for the form action:
"/request/save"
Which will work from wherever your HTML is served on this server.
Summary
You need to submit something (the form), and tell it where to submit to (action). So you need to sync up your URL's, your form, and the submission endpoint.
Additionally, it is a good idea to specify the request method on your RequestMapping so that you can handle POST/GET separately. According to the Spring Documentation, the default behavior is to map ALL HTTP methods:
The above example does not specify GET vs. PUT, POST, and so forth,
because #RequestMapping maps all HTTP methods by default.
It's a good idea to specify a POST for a form submit.
#RequestMapping(value = "/save", method = RequestMethod.POST)
This is the direction you should go, since a form submit should be a POST action so that the contents of the form go in the request body, and eventually you will want it to take in fields from your form for the POST, and map them to objects in your Controller class.
A few Tips:
Consider using a Templating engine like Thymeleaf (which spring often has in their tutorials), or JSP+taglibs. Thymeleaf is a bit more lightweight, and if you use it, you'll have the benefit of doing things the way Spring has written a lot of their examples. See this tutorial for an example:
Spring Boot: Handling Form Submission
Alternatively if someone is just trying to test a Request Mapping, or you're just trying to verify that your MVC endpoint is doing what you think, it would be a lot simpler to use a tool like Postman (which I highly reccomend) to submit your requests. That would take a few variables out for you so you can focus on what you're trying to develop (A REST API?), rather than the testing setup.
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">
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.