Spring REST for DELETE Request Method - html

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.

Related

Thymleaf how to take an input and then redirect to another page

I'm learning Spring boot. I have a list of products with unique ids, and I want to implement a "lookup by id" functionality, but I don't know how to do it, I searched but got totally different stuff.
I already have a #Getmapping method like this:
#Getmapping(/products/{id})
If I manually type in the id in the url I'll get what I what. But I want to have an input box in the HTML page like:
<form>
Look up by id: <input/>
</form>
and after I submit the form it'll redirect to that page. For example, if I enter input of 1, it'll go to localhost:8080/products/1
I've been searching but all I got was stuff about #Postmapping.
Add a #PostMapping to your controller:
#Controller
#RequestMapping("/products")
public class ProductController {
#GetMapping //Controller method for showing the empty form
public String index(Model model) {
model.addAttribute("formData", new SearchFormData()); // Create an empty form data object so Thymeleaf can bind to it
return "index";
}
#PostMapping
public String searchById(SearchFormData formData) {
return "redirect:/products/" + formData.getId(); //Use the value the user entered in the form to do the redirect
}
#GetMapping("/{id}")
public String showProduct(#PathVariable("id") long id) {
...
}
}
With SearchFormData representing the form fields (there is only 1 field in this case):
public class SearchFormData {
private long id;
// getters and setters
And update Thymeleaf template like this:
<form th:action="#{/products}" th:method="post" th:object="${formData}">
<input th:field="*{id}" type="number">
<button type="submit">Search</button>
</form>
Note that the value of th:object needs to match with the name used to add the SearchFormData instance to the model.
See Form handling with Thymeleaf for more info.
The following simple code will direct you to a URL that is generated from a concatenation of the base address of the <form>'s action attribute and the value of its first <input>:
document.querySelector("form").addEventListener("submit",function(ev){
ev.preventDefault();
this.action="/product/"+this.querySelector("input").value;
console.log(this.action);
// in real code: uncomment next line!
// this.submit()
})
<form>
Look up by id: <input type="text" value="123" />
</form>
In the real code you will delete the console.log() und uncomment the following line: this.submit().
Alternatively you could also do:
document.querySelector("form").addEventListener("submit",function(ev){
ev.preventDefault();
location = "/product/"+this.querySelector("input").value;
})
This will redirect you to the page without actually submitting the form.

how to get path variable in URL instead of query param in form submit get request without JavaScript?

I have the form:
<form class="form" action="/bars" method="get" >
<input type="text" class="form-control" name="pid" id="pid" />
<button type="submit">Find By PID</button>
</form>
When submitted, I want to get URL as /bars/123 (assuming 123 was entered in input field). Instead I get /bars/?pid=123. How can I solve this without using JavaScript? I am using thymeleaf 3 with Spring Boot 2 where my controller code looks like:
#GetMapping("/bars/{pid}")
public List<Bar> findBypid(#PathVariable Integer pid, ... ) {
Bar bar barService.findBypid(pid);
// code omitted
// ......
}
I am not sure how ThymeLeaf can help here without using JavaScript.
You can't. Html (and ThymeLeaf) just wasn't built to work this way. You can either use JavaScript, or add special controller methods that forwards to the correct url. Something like this for example:
#GetMapping("/bars")
public String forwarder(#RequestParam String pid) {
return "redirect:/bars/" + pid;
}
#GetMapping("/bars/{pid}")
public List<Bar> findBypid(#PathVariable Integer pid, ... ) {
Bar bar barService.findBypid(pid);
// code omitted
// .
// .
// .
}

HTML & REST (dynamic "id" in a link)

I am using an HTML as a REST client. I need to send form data to a server.
On a server side (implemented with java), a path to my POST(i`m using POST to update my table) method is something like : #Path("http://www.something.com/{id}")
The path works fine, I have tested it with Postman and browser, but for my HTML client, I need the {id} part of
my link to be dynamic.
For example, I click on some product (lets assume, I have web page with some kind of products), the browser opens a new window, so I can update a information
about that product. To make an update, I need that product "id" to be in my link as follows : http://www.something.com/{id}
<form action="http://www.something.com/2" method="post">
<input name="id" type="hidden">
<input name="product_name">
<input name="product_size">
<input name="product_number">
<input type="submit" value="Add">
</form>
In the example, I just 'hardcoded' {id} to be equal to 2, and it works!
But how can I make http://www.something.com/{id} <-- this {id} part to be dynamic(in my index.html file)?
You will need to do two things
Give your form an id and name, for example
<form action="" method="post" name="my-form" id="my-form">
Write some JavaScript which sets the form's action dynamically on some action being performed, such as
document.getElementById("my-form").action = "http://www.something.com/"+myvar;
But in my opinion I think you would be better off using JavaScript to do the post directly, rather than try changing form actions.
Thank You for Your answers and special thanks to #Toby whose proposed solution worked! I`ll share my final solution in case some one runs in the same issue:
...
<body onload="getId('id')">
<div>
<form action="http://www.something.com/{id}" method="post" id="productForm">
<input name="id" type="hidden" id="id">
<input name="product_name">
<input name="product_size">
<input name="product_number">
<input type="submit" value="Add">
</form>
</div>
<script>
var query = window.location.search.substring(1);
var id = null;
function getId (variable){
var idArr = query.split("=");
id = idArr[1];
document.getElementById("productForm").action="http://www.something.com/"+id;
document.getElementById("id").value=id;
}
</script>
</body>
...
my java class with REST paths looks similar to this:
/**
* to access:
* http://www.something.com/{id}
* #param id
* #param product_name
* #param product_size
* #param product_number
*/
#Path("/{id}")
#POST
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public void tableUpdate(#FormParam("id") int id,#FormParam ("product_name") String name, #FormParam ("product_size") String size, #FormParam ("product_number") String number){
...
}

Differentiate form actions in GCDWebServer?

I am using two forms on an HTML page hosted via GCDWebServer. I have the first form setup like this...
<form name=\"vendorInput\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">
<input type=submit value='Add Vendor' action=\"/\">
and the second form setup like this...
<form name=\"vendorInput\" method=\"post\" enctype=\"application/x-www-form-urlencoded\">
<input type=submit value='Add Item' action=\"/\">
I can't find any documentation that provides support for this; and any action string I type other than / causes the HTML request to break. Is there a way to parse different actions for form submit buttons in GCDWebServer?
You just need to have the action be a different path for each form and then implement a GCDWebServer handler for each path:
[webServer addHandlerForMethod:#"POST"
path:#"/path1"
requestClass:[GCDWebServerURLEncodedFormRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
// Do something with form data i.e. [[(GCDWebServerURLEncodedFormRequest*)request arguments]
return [GCDWebServerDataResponse responseWithHTML:#"<html><body>OK</body></html>"];
}];
[webServer addHandlerForMethod:#"POST"
path:#"/path2"
requestClass:[GCDWebServerURLEncodedFormRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
// Do something with form data i.e. [[(GCDWebServerURLEncodedFormRequest*)request arguments]
return [GCDWebServerDataResponse responseWithHTML:#"<html><body>OK</body></html>"];
}];
See https://github.com/swisspol/GCDWebServer#advanced-example-2-implementing-forms for an example.

Mapping one item posted in json object to the list object in Spring MVC

I have in trouble with posting json object and mapping it with List object in Spring MVC controller. I have the form that has several checkboxes. When a user checks and submits, data in the form is deserialized, sent to Spring MVC controller and mapped to List type object. When a user checks two or more checkboxes, it works fine. but for just one box, it doesn't.
When a user checks two or more, the data is deserialized like below.
{"users":["137","138"]}
However, when a user checks just one checkbox, it is like
{"users":"138"}
and 400 bad request error is returned.
Is there any workaround or solution for this?
The jQuery codes are:
$(document).ready(function() {
$('#groupusers').submit(function() {
var users = $(this).serializeObject();
$.postJSON("${context}/admin/groups/${group.seq}/users", users, function(result) {
...
});
return false;
});
And the form is:
<form id="groupusers" method="post" accept-charset="UTF-8" action="/" class="edit_group">
...
<div id="users">
<c:forEach var="user" items="${users}">
<label><input id="users" name="users" type="checkbox" value="${user.seq}" /> ${user.firstName} ${user.lastName}</label><br>
</c:forEach>
</div>
</form>
List object mapped to the form data:
public class AssignedUsers {
private List<Long> users;
...
}
Thanks in advance.
What is the implementation of the serializeObject() function? You might need to modify that to always return an array, so even if you only checked one box, the object should be: {"users":["138"]}
The server returned a 400 probably because the Jackson at threw a parsing exception at the backend.
Fojas' jQuery Serialize
This is the solution I have found and since been using which does excatly what you are requesting.
Example
HTML
<form id="myForm">
<input name="data[]" value="some data"/>
<input name="data[]" value="more data"/>
<input name="users[]" value="137"/>
</form>
jQuery
$('#myForm').serializeObject();
Output
{
data: ["some data", "more data"]
users: [137]
}