In my current spring-boot project, I have a form which data is handled by by this controller method:
#RequestMapping(value="alterar", method=RequestMethod.POST)
#ResponseBody
public void altera(#ModelAttribute("object") E object, BindingResult result) throws Exception {
serv.altera(object);
}
and this method call that one in the service class:
public void altera(E e) throws Exception {
settings.save_settings(e);
}
but when I try submit data through this controller, despite the browser's developer tools shows the fields are being sent to the server, no data is received by the controller (I saw both values for object and result.getModel(); for both, the value for the fields are null).
Anyone can see what I am doing wrong here?
ps.: the html for the form:
<form role="form" class="form" id="form" method="post" enctype="application/x-www-form-urlencoded" action="/Paypal/alterar">
<div class="field-box">
<label>http.ConnectionTimeOut</label>
<div class="col-md-7">
<input type="text" name="http_ConnectionTimeOut" class="form-control" value="" />
</div>
</div>
...
</form>
There is not model attribute defined in html form
Try updating your view as
<form role="form" class="form" id="form" method="post" enctype="application/x-www-form-urlencoded" action="/Paypal/alterar" modelAttribute="object">
Moreover modelattribute will just bind your whole class with one single object that is object here and will directly give the default value which is null. Try using #ResponseBody instead.
Related
I did the get, post and delete method. But now I'm suffering to do the put method.
My controller:
#RequestMapping("/teste/equipe/editar/{id}")
public String update(#RequestBody Team newTeam ,#PathVariable("id") Long id)
{
Team team = teamService.findById(id);
team.setName(newTeam.getName());
team.setName(newTeam.getRole());
teamService.save(team);
return "redirect:/teste/equipe";
}
HTML:
<form action="/teste/equipe/editar/{id}" method="PUT">
<input type="text" th:field="${team.name}" placeholder="Nome">
<br>
<input type="text" th:field="${team.role}" placeholder="Função">
<button>
Enviar
</button>
</form>
Error:
Not certain this helps but the error on the whitelabel error page states:
Number Format Exception for input {id}
Seems like you're expecting {id} in your form:
<form action="/teste/equipe/editar/****{id}****" method="PUT">
to be interpolated with an actual ID. Should it instead be:
<form action="/teste/equipe/editar/${id}" method="PUT">
I'm trying to validate my form input, but after its submit it does not load my controller method, instead it shows a Whitelabel Error Page with Internal Server Errorand status 500 but with the correct validation errors.
I know it must be a matching issue with the expected parameters of my method, but so far from what I've gathered the rule is simply BindingResult then Model which I did but it still does not trigger my controller method...
Any thoughts are appreciated.
Controller-Method, that is not triggered unfortunately:
#Controller
#Validated
public class UserController {
#PostMapping("/users/add")
def String usersAdd(#Valid #ModelAttribute("user") User user, BindingResult bindingResult, Model model) {
if (bindingResult.hasErrors()) {
return "userAdd"
} else {
userRepository.save(user)
return "usersList"
}
}
Template-Form:
<form action="#" th:action="#{/users/add}" th:object="${user}" method="post">
<div class="form-row">
<div class="form-group col-md-12">
<input type="text" class="form-control" th:field="*{name}">
<div th:if="${#fields.hasErrors('name')}" th:errors="*{name}">Name Error</div>
</div>
</div>
<div class="form-row">
<div class="form-group col-md-6">
<button type="submit" class="btn btn-success">Add</button>
</div>
</div>
</form>
Model-Class:
#Document(collection = "users")
public class User {
#Id
String id
#Size(min=3, max=100)
String name
}
Update:
Went debugging and found this part, so it seems it's invoking with the correct parameters. I am new to Spring, so I'm having difficulties thinking about other "newbie"-problems.
in InvocableHandlerMethod.java the method DoInvoke is called on my usersAdd with Station, BeanPropertyBindingResult, BindingAwareModelMap.
When Invoking the method it causes a ConstraintViolationException which will abort invocation, is this expected?
I figured it out after a looong debug session. The #Valid before my User user causes a ConstraintViolationException, which will, expectedly, abort the invocation of my usersAdd because, as expected, the parameter is not valid.
And the reason for this behaviour was the #Validated at the controller class, which I picked up from some tutorial, but when removed everything works and validates as expected.
I guess I was checking a REST-Tutorial and tried to use their approach... not the best idea ;)
I have the following content in my HTML which is using Thymeleaf
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<span th:text="${domain}" th:field="*{domain}">domain</span>
<input type="Submit" value="close" />
</form>
And I have the following in my Controller which is using Sprint Boot
#RequestMapping(value = "/shutDown", method = RequestMethod.POST)
public ModelAndView shutDownPage(ModelAndView modelAndView, Authentication authentication,
#ModelAttribute("ddata") DInputBean dInputBean) {
String domain = dInputBean.getdomain();
return modelAndView;
}
I'm hoping I'd get value of domain from the HTML in the Controller but it's always null. DInputBean has getters and setters for "domain" field.
The th:field attribute can be used on <input>, <select>, or, <textarea>.
A solution you could possibly replacing you second <span> with a hidden input element.
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<input type="hidden" th:field="*{domain}" th:value="${domain}" />
<input type="Submit" value="close" />
</form>
If you wanted to keep the second div, just place the <input type="hidden"> inside the second <span> and remove the th:field attribute from the second <span>.
Edit:
If you wanted to add the value of domain in a span.
<form action="#" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<span>Domain</span>
<span th:text="${domain}">domain<span>
<input type="hidden" th:field="*{domain}" th:value="${domain}" />
<input type="Submit" value="close" />
</form>
http://www.thymeleaf.org/doc/tutorials/3.0/thymeleafspring.html#inputs
An option is to use a read-only input field:
<input type="text" th:field="*{domain}" th:value="${domain}" readonly="readonly"/>
This both displays the value and sends it on submit.
The key is to add the value of the domain variable to the form:
#GetMapping("/shutDownPage")
public String shutDownPage(Model model) {
model.addAttribute("ddata" new Ddata()); //or however you create your bean
String username = ... //however you get your username
String domain = myRepositoryService.findDomainByUsername(username);
model.addAttribute("domain", domain);
return "shutDownPage";
}
Include an HTML page in the action so that when you open the HTML page in a browser without a server/container, the button will still appear to work:
<form action="confirmationPage.html" th:action="#{/shutDown}" th:object="${ddata}" method="post">
<!-- You can benefit from using a conditional expression -->
<span th:text="${domain != null ? domain : 'No domain supplied'}">[domain]</span>
<input type="hidden" th:field="*{domain}" th:value="${domain}"/>
<input type="Submit" value="close"/>
</form>
And your post method:
#PostMapping("/shutDown") //use shorthand
public String shutDownPagePost(#ModelAttribute("ddata") DInputBean dInputBean {
String domain = dInputBean.getDomain();
//do whatever with it
return "confirmationPage";
}
I would like to call the url via http delete method. I tried th:onclick and th:action but not working.
html code:
<button id="delete" name="delete" th:onclick="#{'/foos/{id}'(id=${foo.id})}" th:method="delete">Delete</button>
controller code:
#RequestMapping(value="/foos/{id}", method = RequestMethod.DELETE)
#ResponseBody
public String delete(#PathVariable String id) {
studentService.delete(id);
return "Successfully deleted";
}
I think you will need a form for your transaction. And also this hidden input field.
<form action="#" th:action="#{'/delete/{id}'(id=${foo.id})}" th:method="delete" >
<input type="hidden" name="_method" value="delete" />
<button type="submit" id="submitButton"> </button>
</form>
The th:method="delete" creates the hidden input field automatically for you. If you add it manually as well you will have it twice. Check the source code.
I still got the POST Error message after the recommendations here. I found out Spring ignores those hidden fields by default. The solution is to activate it in your application.properties file:
spring.mvc.hiddenmethod.filter.enabled=true
My working code in my application looks like this:
Form:
<form action="#" th:action="#{'/books/delete/{id}'(id=${book.id})}" th:method="delete" >
<button type="submit" class="btn">
Delete
</button>
</form>
Controller:
#RequestMapping(value="/books/delete/{id}", method = RequestMethod.DELETE)
public String deleteBook(#PathVariable Long id) {
bookService.deleteBook(id);
return "books";
}
I am using Liferay portal-6 with Spring-3.
In my portlet, first it goes to the #Rendermapping without params and displays the default jsp,
when I click on a button I am passing the actionurl, but its not going to the corresponding #Actionmapping.
My searchForm.jsp looks like this:
<portlet:actionURL var="showSearchResultsUrl">
<portlet:param name="myaction" value="searchResults" />
</portlet:actionURL>
<form:form id="searchForm" name="searchForm" commandName="patientStoryForm" method="POST" action="${showSearchResultsUrl}" enctype="multipart/form-data" >
<input type="button" name="search_btn" value="Search"/></td>
</form:form>
My controller is like this:
#Controller(value = "searchPatientStoryController")
#RequestMapping(value = "VIEW")
#SessionAttributes(types = PatientStoryForm.class)
public class SearchPatientStoryController {
#RenderMapping
public String showSearchForm(RenderResponse response, Model model) {
return "searchForm";
}
#RenderMapping(params = "myaction=searchResultsForm")
public String showSearchResultsForm(RenderResponse response, Model model) {
return "searchResultsForm";
}
#ActionMapping(params = "myaction=searchResults")
public void searchResults(
#ModelAttribute(value = "patientStoryForm") PatientStoryForm patientStoryForm,
BindingResult bindingResult, ActionResponse response, ActionRequest request,
SessionStatus sessionStatus, Model model) {
response.setRenderParameter("myaction", "searchResultsForm");
}
}
When I click on button in searchForm.jsp it is supposed to go to #Actionmapping but it is not going.
Please help me.
Thanks in advance.
You would need to submit the form in order to invoke the associated action method.
However, in the jsp code, I see the below code which indicates that it is just a button.
<input type="button" name="search_btn" value="Search"/>
In order to submit the form, you can do either of the following ways:
Use a submit button instead of a normal form button like this:
<input type="submit" name="search_btn" value="Search"/>
Invoke a javascript function on click event of the button and submit the form:
<script type="text/javascript">
function submitForm(form){
var actionUrl = '<portlet:actionURL var="showSearchResultsUrl"><portlet:param name="myaction" value="searchResults"/></portlet:actionURL>';
form.action = actionUrl;
form.submit();
}
</script>
and
<input type="button" name="search_btn" value="Search" onclick="javascript:submitForm(this.form)"/>
Can you try replacing your actionURL like the following
<portlet:actionURL name="searchResults" var="showSearchResultsUrl">
<portlet:param name="myaction" value="searchResults" />
</portlet:actionURL>
You need to set the action of your form, something like this:
<form:form action="<%=showSearchResultsUrl%>" id="searchForm" name="searchForm" commandName="patientStoryForm" method="POST" action="${showSearchResultsUrl}" enctype="multipart/form-data" >
<input type="button" name="search_btn" value="Search"/></td>
This way your action name will be "myaction" with the value "searchResults" as your mapping on the controller side.