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.
Related
I am having some difficulties in calling a method when a button is clicked.
In my Index.JSP
I have the following section of HTML code
<div class="hero-copy">
<h1 class="hero-title mt-0">Deep Algorithm by Sadman Sakib</h1>
<p class="hero-paragraph">A personal portfolio/demonstration of all university and extra-curricular activites, beautifully packaged, in a modern and responsive Spring MVC Web Application</p>
<div class="hero-cta">
<a class="button button-primary" onclick="">View Projects</a>
<div class="lights-toggle">
<input id="lights-toggle" type="checkbox" name="lights-toggle" class="switch" checked="checked" >
<label for="lights-toggle" class="text-xs"><span>Turn me <span class="label-text">dark</span></span></label>
</div>
</div>
</div>
Now "View Projects" is a button which will print "Hello" out in the console, I am not sure what I should be using to call the method in my controller. At the moment I am using onClick but am not sure what I should put as a parameter.
This is my controller class
#Controller
public class HelloController {
#RequestMapping("/projects")
public void add()
{
System.out.println("Hello");
}
}
This is my view, user will click view projects and it will print hello out in the console, how would I go about doing this?
EDIT
When I use a form it works, however when using href it does not link to my controller.
<form action="add">
<input type="submit" class="button button-primary" value="Me">
</form>
<span>View GitHub</span>
<h3>View GitHub</h3>
How can I use href to link back to my controller. Do I need to import some dependencies/taglines
First you must understand what the controller is doing. The controller is mapping the request which have the path /projects, so usually, the url will be something like http://localhost:8080/projects if your app is running on port 8080. Upon calling '/projects' from your browser, the method add() will be executed.
The easiest way to trigger the method add() in the controller is using href in the link.
The code will be as follows:
<a class="button button-primary" href="${pageContext.servletContext.contextPath}/projects">View Projects</a>
If you really want to use the onclick method, then you must create a javascript function and call the url which is mapping to /projects
Update 28/06/20
The code will not work because the method being invoked is returning void. Add #ResponseStatus(value = HttpStatus.OK) on the method then it should work just fine.
#Controller
public class HelloController {
#RequestMapping("/projects")
#ResponseStatus(value = HttpStatus.OK)
public void add()
{
System.out.println("Hello");
}
}
So basically I managed to fix it, I should call my controller using href like this
href="<c:url value="/projects"/>
Cheers to everyone who helped
I am using Spring framework version 4.3.5.RELEASE.
Spring security version is 4.2.2.RELEASE.
I am facing a strange issue related to CSRF. Whenever I submit a form (from a JSP file), Sometimes it works fine, the form gets submitted without error but sometimes after submitting the form, it shows Http Status 405 ? Method not supported. I have included csrf token too, both in hidden field as well as appended it as query string in form's action's tag.
Here is an example POST form from my project:
<form:form class="form-horizontal" method="POST" modelAttribute="dealerVisit" enctype="multipart/form-data"
action="http://localhost:8080/update/edit.html?${_csrf.parameterName}=${_csrf.token}">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}">
</form:form>
Here is the controller where I am submitting the above form:
#RequestMapping(value = "/update/edit.html", method = RequestMethod.POST)
public String saveEdit(ModelMap map, #Valid #ModelAttribute(MODEL_KEY) DealerVisitVO dealerVisitVO, BindingResult result,
#RequestParam(required = false, name="followup") Boolean followup) {
//my codes here
}
The problem is coming random. It works sometimes and sometimes it doesnt. With no change in code or form. Disabling the CSRF is not a possible solution as this is 1 requirement of my client.
Please help if anyone was able to solve.
In spring security, CSRF token get generated per session basis and remains the same until your session is not expired. This is one case you are getting 405 method not allowed because your session is expiring on some interval (you may check that). Secondly, if you're using spring's form then there is no need to put token in hidden field explicitly, spring does it by default also no need to put it into the query string. Your code should be like this...
<form:form class="form-horizontal" method="POST" modelAttribute="dealerVisit" enctype="multipart/form-data" action="http://localhost:8080/update/edit.html">
<!-- Spring will add by default -->
<!-- <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"> -->
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.
I am trying to code an HTML form that sends data to a RESTful web service (managed with Spring) using select HTML element.
The REST has to create an object Event on my database.
The problem I find is that the #RequestParam in the REST comes empty even if my options' values are present.
This is my HTML form.
<form name="editForm" role="form" novalidate ng-submit="vm.save()">
<!-- other fields that works correct -->
<div class="form-group">
<label class="control-label" data-translate="businessRequestApp.event.participantsAdd" for="field_attendees">Attendees</label>
<select style="height: 300px;" multiple class="form-control" id="field_attendees" ng-model="vm.event.usersOnIt" ng-options="customUser as customUser.username for customUser in vm.customusers | orderBy:'id' track by customUser.id">
<option value="{{customUser.username}}" name="attendeesToParse"></option>
</select>
</div>
</form>
This is my REST.
#PostMapping("/events")
#Timed
public ResponseEntity<Event> createEvent(#RequestBody Event event, #RequestParam(value="attendeesToParse") List<String> participants) throws URISyntaxException {
//Some code that creates an object "Event" on my database
}
I am trying to fill a field List of String. Due to my business logic I can't insert it into Event's class, so I have to threat it separately.
Note that #RequestBody works correctly, the issue is only with #RequestParam that does not receive anything.
Thanks in advice for your time.
Options elements are never sent. Select's value is sent. Try to move the name="attendeesToParse" to the select itself.
If you need multiple values create a hidden input and store selected options into the field. Use the hidden input name to get values in the controller.
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.