Spring mvc: I cant map form action url to controller action - spring

I apologize in advance if this or a similar question has already been asked, but I could not find a suitable answer.
I have a simple form like this in EditUser.jsp (mapped to: .../admin/users/edit/{userId}):
<form action="/admin/users/edit/addRole/${user.userId}" method="POST">
<select name="role">
<c:forEach var="role" items="${roles}">
<option value="${role}">${role}</option>
</c:forEach>
</select>
<button type="submit" value="AddRole">Add Role</button>
</form>
And #RequestMapping like this:
#RequestMapping(value = "/admin/users/edit/addRole/${userId}", method = RequestMethod.POST)
public String addUserRole(
Model model,
#RequestParam("role") String role,
#PathVariable(value="userId") long userId)
{
...
return "redirect:/admin/users/edit/${userId}";
}
The problem is the result of the request: HTTP Status 404 - /admin/users/edit/addRole/7- "The requested resource is not available" (7 is some user id). A cannot map the POST request to the controller action. I already tried with th:action but it redirects me to the previous page .../admin/users.
Any help pointers appreciated .

I think you url is wrong. As long as you do not deploy the application in the servlets container root path, it will not work because the url is missing the applications name. So a correct url would be something like:
<form action="myAppName/admin/users/edit/addRole/${user.userId}" method="POST">
But better would been using <c:url> or <spring:url>-tag this adds the application name to the url (if the given url starts with an /)
<form action="<c:url value="/admin/users/edit/addRole/${user.userId}" />" method="POST">
for some more information have a look at this two answers:
How to use relative paths without including the context root name? (the highes ranked answer of BalusC is for an quite old jsp version (<2.0)) so take the answer with the c:url tag
How to use with an tag?

I finally found the error - $ sign in #RequestMapping annotation. A just removŠµ $ from annotation and from return "...url" and that's all.

Related

Pass data from Thymeleaf template to springboot controller

I have simple web application written using Springboot and Thymeleaf templates. Report controller receives the data from form and builds the TestPlanReportResponse object which is added as model attribute like this:
#PostMapping("/report")
public String homeSubmit(#ModelAttribute HomeFormInput homeFormInput, Model model, Errors errors) {
final TestPlanReportResponse response = new TestPlanReportResponse(homeFormInput);
model.addAttribute("allData", response);
return "charts";
}
I can work with that data in "charts" thymeleaf template and show the data I need, but I need to send exactly the same object back to controller when button is clicked, but i getting TestPlanReportResponse
object as parameter with nulls set.
#PostMapping("/report/send")
public String sendReport(#ModelAttribute TestPlanReportResponse reportData, Model model) {
//reportData contains just nulls
}
Here is how my button is set in charts template:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<button type="submit">Send the report</button>
</form>
So my question is how to send the object back from thymeleaf template? Should i create a hidden input and put there the "allData" object just to send it back? It looks for me like dirty hack. What would be the appropriate way to pass data back? I want to have this app stateless so don't to store the data on a server side.
When I used to work with Spring and Thymeleaf and form, we had the same issue, passing the data back and forth between a form, the template, and different controllers.
And what you suggest is what we did, we used hidden input as dirty as it may look,it was the standard suggested answer, we did not find anything better.
You need to create an input, with a type a value and link it to a field, like this:
<form action="#" th:action="#{/report/send}" th:object="${allData}" method="post">
<input type="hidden" th:value="*{allDataValue1}" th:field="*{allDataField1}" />
//Do this for all your attributes/values that you wish to pass to the controller
<button class="btn btn-info btn-lg btn-block" type="submit">Send the report</button>
</form>
Though, i found this answer, you can try looking into this thread

Create a fragment for a form in Thymeleaf (and spring)

First I created a form in a simple HTML with Thymeleaf and everything was fine. Then moved to step 2 and I relocated my form to a fragment. I called the fragment like this:
<div th:insert="~{address::form($(address)}"></div>
and the fragment (which is in address.html) is like this:
<form th:fragment="form(address)" action="#" th:action="#{/address}" th:object="${address}" method="post">
<label>Street<label><span><input type="text" th:field="*{street}"></span>
<label>County:</label>
<span>
<select th:field="*{county}">
<option th:each="s : ${countyList}" th:value="${s.value}" th:text="${s.text}"></option>
</select>
</span>
...
but this is not working and it's throwing:
java.lang.IllegalStateException: Neither BindingResult nor plain target object for bean name 'street' available as request attribute
Please help with how to move an entire form into a Thymeleaf fragment? Also please add ideas for combos, so I can get their list from the model bean. Thank you!
PS the controller looks like this for now (add and edit ) buti will work to make it 1 function instead:
#GetMapping(value="/address")
public String newAddress(AddressModel address, Model model) {
model.addAttribute("address", address);
model.addAttribute("countyList", countyService.listCombo());
...
return "index";
}
#GetMapping(value="/address/{id}")
public String editAddress(Model model, #PathVariable("id") Long id) {
AddressModel address = addressService.load(id);
model.addAttribute("address", address);
model.addAttribute("countyList", countyService.listCombo());
...
return "index";
}
In my case the problem was coming from an unexpected direction. I have put 2 fragments address::form (for creating the form) and address::list (for showing a list of addresses) in the same file and somehow, for some yet unknown reason these 2 fragments are not working fine when in the same file. And the error was not very helpful. But as soon as I put them in 2 separate files like this: addressForm::form and addressList::list everything was ok. Interesting that if I keep the fragments in the same file but swap the order in which they are defined I can render the page correctly but I still get the error in the logs. Strange things.

Hidden field "ufprt" being added to Razor Umbraco Form - Why?

I have got a form (below) that is posted to an umbraco surface controller.
#using (Html.BeginUmbracoForm("AddToBasket", "Basket"))
{
<h1>#Model.productSelectionModel.Product.Title - #Model.productSelectionModel.Product.Price.ToString("C")</h1>
<ul>
#foreach (var productOption in Model.productSelectionModel.ProductOptions)
{
<li>#productOption.Option.Title</li>
#Html.DropDownList(productOption.Option.Id.ToString(), productOption.ValuesInOptions.ToSelectList(f => f.OptionValue.OptionValue1,
f => f.Id.ToString(),
"Select"));
}
</ul>
<input type="submit" value="Add To Basket">
}
When I look at the HTML rendered for this form it seems to have added a hidden field called ufprt. Does any one know what this is? Why is it being added, I'm not using it any where ( I don't think I am anyway)
Any ideas?
<input name='ufprt' type='hidden' value='6C01896EF3D5F430F9ED041DD2B0D31F89FA969A085C6F4FDEC3C9D4B906846E7AA80041CEA12573E9F58C1740893B770AAE3319FAA8FA35C89A54D301CFE31B85ADC0D3D9506D208DB068D1257C5F0D5F1B3B90FD59A5C2938EED0A2EB1168AD4573CD5D043D47A8F1AA789E988CC614686B89BE57D35DA8EAAA110044C393F' />
It is to route the form to the correct controller/action method (Umbraco has the ability to route forms via that input value rather than the typical MVC approach of using the URL). I believe this is particular to surface controllers (i.e., it wouldn't apply to a normal controller, API controller, or RenderMvcController).
It is not a CSRF token as another answer indicates. If it were, it would likely have a name of "__RequestVerificationToken" as indicated here: http://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-%28csrf%29-attacks
EDIT: This information has been added here: https://github.com/kgiszewski/LearnUmbraco7/blob/a97e85e5ad17e2ba9fc463f02c76885911046b57/Chapter%2006%20-%20Surface%2C%20WebAPI%20and%20RenderMVC%20Controllers/02%20-%20Surface%20Controllers.md#special-routing

Spring Redirect URL differs in browser

I am creating sample Spring MVC application.In this application i have one form when i submit the form i perform some action.
My problem is after the form submit url is changed for example i have url as http://localhost:8080/SampleWeb/sample/user this is for my form display when i submit the form the url redirected to http://localhost:8080/sample/user-by-name
in my jsp
<form:form method="POST" action="/sample/user">
<table>
<tr>
In my controller
#Controller
#RequestMapping("/sample")
public class SampleController {
#RequestMapping(value = "/user", method = RequestMethod.GET)
return "redirect:" + "SampleWeb/sample/user-by-name";
when i change the redirect url to "/SampleWeb/sample/user-by-name"
it works in firefox but in chrome http://localhost:8080/SampleWeb/SampleWeb/sample/user-by-name it adds two times.
if i give return "redirect:" + "/sample/user-by-name"; means url will be http://localhost:8080/sample/user-by-name
I am new to the Spring mvc. Please anyone can help me
Remove the first slash from this line <form:form method="POST" action="sample/user-by-name">
Do not hard code the context path in your controller / jsp page. Mention context path in your JSP page as shown below. It worked for me.
<form:form method="POST" action="${pageContext.request.contextPath}/sample/user-by-name">
Or
<form:form method="POST" action="<%=request.getContextPath()%>/sample/user-by-name">
Try this:
<c:url var="myUrl" value="/sample/user-by-name"/>
<form:form method="POST" action="${myUrl}">

Creating a form in Spring

I have a simple contact form in my spring project, which is meant to access a backing object, but I get this error
"Neither BindingResult nor plain target object for bean name 'indexBacking' available as request attribute"
My form looks like this:
<form:form action="index.htm" enctype="multipart/form-data" method="post" commandName="indexBacking" accept-charset="UTF-8">
<form:label path="personName">Name</form:label>
<form:input id="personName" path="personName" autocomplete="false" /><br />
<form:label path="personEmail">Email</form:label>
<form:input id="personEmail" path="personEmail" autocomplete="false" /><br />
<form:label path="personComments">Your Comments</form:label>
<form:input id="personComments" path="personComments" autocomplete="false" /><br />
<input type="submit" alt="Submit"/>
</form:form>
Which is meant to access my controller and save the fields "personName", "personEmail" and "personComments" into my backing object called "indexBacking".
My controller method that I am trying to access is here:
#RequestMapping(value = PAGE_NAME, method = RequestMethod.POST)
public String handleContactForm(ModelMap map, HttpServletRequest request, #ModelAttribute("indexBacking") IndexBacking bo, BindingResult result) {
return MODEL_NAME;
}
But I am not sure hot it links with the backing object. Any ideas what I am doing wrong?
Thanks
Jon
Try using modelAttribute="indexBacking" on form:form instead of commandName="indexBacking".
Also, take a look at this answer; it might have useful information for your case.
The problem was very simple, I was just being an idiot. I saw a colleague of mine working on a form and assumed a few of his classes were part of Spring as default. All I had to do was handle the received data at the other end properly (by calling the appropriate methods in the controller) and it worked fine.
Thanks for your help chaps - credit to #nobeh for pointing me in the right direction.
The problem is in your controller!
The following may help you much for your request Check This

Resources