in the below example, I am trying to undersatnd the difference between #RequestMapping and #PostMapping.
For #RequestMapping:
when i do the POST request:
http://localhost:8085/call1/initparam1?val=1111 via postman, it executes correctly.
but when its is proceeded by by GET request
http://localhost:8085/call1/getparam1
i do not get 1111 as a result.
For #PostMapping, when i do the POST request:
http://localhost:8085/call1/initparam2/1999 via postman, it executes correctly.
but when its is proceeded by by GET request
http://localhost:8085/call1/getparam1
i do not get 1999 as a result.
please explain to me what is the difference between using both annotations, as i spent time googling and researching but i could not figure out why the first example is not working.
Controller1
#Controller
#ResponseBody
#RequestMapping("/call1")
public class Call1 {
public String str = "inti";
#RequestMapping(value = "/initparam1", method = RequestMethod.POST)
public void initparam1(#RequestParam(value = "val") String val) {
this.str = val;
}
#PostMapping(value = "/initparam2/{val}")
public void initparam2(#PathVariable String val) {
this.str = val;
}
#RequestMapping("/getparam1")
#ResponseBody
public String getParam1() {
return this.str;
}
}
From the #PostMapping docs :
Specifically, #PostMapping is a composed annotation that acts as a shortcut for #RequestMapping(method = RequestMethod.POST).
So it is only convenience annotation that is more "verbose" and indicates that method annotated with it is used for handling POST HTTP requests.
I have just checked your controller methods with 2.1.4 spring boot version and your scenarios work as expected so there has to be something wrong in your configuration or the way you are sending requests.
Related
I am getting this error while calling an API from postman, after I hosted my spring app in VM. Locally it works. But Get methods in my VMs are working.
[http-nio-8081-exec-4] PageNotFound - Request method 'GET' not supported
My controller method looks like this:
#RestController
#RequestMapping("/orders/")
public class OrdersController {}
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
The API request running forever and dont get any response. I found the exception in my log. Any idea on this issue?
You created two urls there:
url/orders/ -> accepts get/post/etc... (though its not implemented)
url/orders/create -> accepts post
#RestController
#RequestMapping("/orders")
public class OrdersController {
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
System.out.println(request)}
}
You can try the above code.
You are trying to make a GET request on an only POST endpoint, thus then not loading the page. Your endpoint should be of type GET. You can also have the same endpoint for GET and POST requests as follows:
#RestController
#RequestMapping("/orders/")
public class OrdersController {}
#PostMapping(value = "create", produces = "text/plain")
private String createOrder(#RequestBody POCreationRequest request) throws ParseException {
//Parse post requests
}
#GetMapping(value= "create")
private String servePage() {
return create; //create is the name of the html view.
}
Now when going to localhost:8080/orders/create it should serve the view.
You can also make the GET mapping return a JSON object by:
#GetMapping(value= "create")
private String serveJSON() {
return "{\"hello\": \"world\"}"; //The string is treated as JSON and not as a view.
}
I am learning spring boot, and i developed the below simple example. I would like to annotate a class as Controller using #Controller. this class has constructor and I want to have access to GreetingFromDeuController as shown:
http://localhost:8080:/GreetingFromDeuController?str = "hi"
the error i am receiving is
#RequestMapping is not applicable on a constructor
please let me know how to solve.
code:
#Controller
#RequestMapping("/GreetingFromDeuController")
public class GreetingFromDeuController {
private String str;
#RequestMapping("/GreetingFrom/deu")
GreetingFromDeuController(#RequestParam(value = "str") String str) {
this.str = str;
}
#RequestMapping("/GreetingFromDeuController")
public String getGreetingFromDeu() {
return this.str;
}
}
First of all your constructor gets initialize much before you hit your URL. So you need to work on your design or tell me your business requirement and I will try to provide you a solution. My refactor code solution will help you to achieve that in two steps. First hit POST method which will do work on setting variable and then subsequent hits of GET method will return that set value.
We can refactor code like below. It will explain use of RequestMapping on method and class.
Considering we have to write two API, one for reading and one for writing.
URLS :
1. POST http://localhost:8080/example/greetings (in request body send {str:'hi'})
2. GET http://localhost:8080/example/greetings
#Controller
#RequestMapping("/example")
public class GreetingFromDeuController {
private String str;
#RequestMapping(value="/greetings" , method = RequestMethod.POST)
public void setGreetingFromDeu(#RequestBody(value = "str") String str)
{
this.str = str;
}
#RequestMapping(value="/greetings" , method = RequestMethod.GET)
public String getGreetingFromDeu()
{
return this.str;
}
}
The #RequestMapping documentation says:
Annotation for mapping web requests onto methods in request-handling
classes with flexible method signatures.
Then you can not do that, if you want to initialize your variables or whatever you can use several ways:
1.- Use #PostConstruct
#PostContruct
public void init() {
this.str = "Anything";
}
2.- Use a simple request to set anything only
#RequestMapping(value="/refresh/anythings", method = RequestMethod.PUT)
public void refresh(#RequestBody(value = "str") String str) {
this.str = str;
}
3.- Use #Value
In application.properties / application.yaml
properties.str = anything
In the Controller
#Value("${properties.str:default}") // by default str is "default"
public String str;
#RequestMapping(value="/greetings" , method = RequestMethod.GET)
public String getGreetingFromDeu() {
return this.str;
}
As far I am concerned, #RequestMapping is not meant for constructors. It should be used for annotating methods or classes. Methods that are responsible for handling requests.
#RequestMapping should be used to map request with endPoint. which can be used as class level and method level.
You can use #RestController (improved from #Controller see difference).
The ideal flow for Spring Boot is Controller -> Service -> Repository
Controller -> maps request with endPoint and return response
Service -> perform business logic
Repository -> Handle database operation
Example
#RestController
#RequestMapping("/api")
public class GreetingController {
#Autowired GreetinService greetingService;
// Request http://localhost:8080/api/GreetingFrom
#GetMapping("/GreetingFrom")
public ResponseEntity<String> GreetingRequestParam(#RequestParam(value = "name") String name) {
greetingService.performBusinessLogic(name);
return new ResponseEntity<String>("Greetings from "+name,HttpStatus.OK);
}
// Request http://localhost:8080/api/GreetingFrom/user2121
#GetMapping("/GreetingFrom/{name}")
public ResponseEntity<String> GreetingPathVariable(#PathVariable(value = "name") String name) {
return new ResponseEntity<String>("Greetings from "+name,HttpStatus.OK);
}
}
#RequestMapping("/accounts")
public class controller {
#GetMapping("/get/{id}")
public final ResponseEntity<?> getHandler(){
}
#PostMapping(value = "/create")
public final ResponseEntity<?> createHandler(){
/*
trying to use some spring library methods to get the url string of
'/accounts/get/{id}' instead of manually hard coding it
*/
}
}
This is the mock code, now I am in createHandler, after finishing creating something, then I want to return a header including an URL string, but I don't want to manually concat this URL string ('/accounts/get/{id}') which is the end point of method getHandler(), so I am wondering if there is a method to use to achieve that? I know request.getRequestURI(), but that is only for the URI in the current context.
More explanation: if there is some library or framework with the implementation of route:
Routes.Accounts.get(1234)
which return the URL for the accounts get
/api/accounts/1234
The idea is, that you don't need to specify get or create (verbs are a big no-no in REST).
Imagine this:
#RequestMapping("/accounts")
public class controller {
#GetMapping("/{id}")
public final ResponseEntity<?> getHandler(#PathVariable("id") String id) {
//just to illustrate
return complicatedHandlerCalculation(id).asResponse();
}
#PostMapping
public final ResponseEntity<?> createHandler() {
//return a 204 Response, containing the URI from getHandler, with {id} resolved to the id from your database (or wherever).
}
}
This would be accessible like HTTP-GET: /api/accounts/1 and HTTP-POST: /api/accounts, the latter would return an URI for /api/accounts/2 (what can be gotten with HTTP-GET or updated/modified with HTTP-PUT)
To resolve this URI, you could use reflection and evaluate the annotations on the corresponding class/methods like Jersey does.
A Spring equivalent could be:
// Controller requestMapping
String controllerMapping = this.getClass().getAnnotation(RequestMapping.class).value()[0];
and
//Method requestMapping
String methodMapping = new Object(){}.getClass().getEnclosingMethod().getAnnotation(GetMapping.class).value()[0];
taken from How do i get the requestmapping value in the controller?
I'm using Spring boot 1.4.0, Consider below code in a #RestController, what I expect is, the server side will receive a http body with form_urlencoded content type, but unfortunately it demands me a query parameter type with email and token. What's the problem here and how to fix?
#DeleteMapping(consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
#ResponseStatus(HttpStatus.NO_CONTENT)
public void removeAdmin(#RequestParam(value = "email") String email, #RequestParam(value = "token") String token) {
//...
}
#DeleteMapping is only a convenience extension the provides #RequestMapping(method=DELETE) It will not handle request paramters. You will still have to map those in the controllers method signature if you need the data to perform the work.
Since you want a body, You could create an object and mark it as #RequestBody:
public class DeleteBody {
public String email;
public String token;
}
public void removeAdmin(#RequestBody DeleteBody deleteBody) {
...
}
I have a REST Webservice returning an int via #responseBody and I want this response to be in XML, and I don't know how to achieve that despite many tries.
My controller is as follow:
#RequestMapping(value = "/UserByAppli", method = RequestMethod.GET)
#ResponseBody
public List<Application> getNbUserByAppli()
{
return this.DAO.getNbUserByAppli();
}
And my application Object:
#Component
#XmlRootElement(name="Application")
#XmlAccessorType(XmlAccessType.FIELD)
public class Application
{
#XmlElement(name="Nom")
private String name;
#XmlElement(name="NbUtilisateurs")
private int nbUsers;
public Application()
{
}
...
}
It always returns application/json, and when I specify the header "Accept=application/xml" I get a 406 response code with org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation in Spring logs.
An explanation or a search direction would be appreciated...
Make sure you have JAXB2 in your classpath and have registered the appropriate message converter and pass the Accept: application/xml header. Also, like M. Deinum suggested, for the marshalling to work, you also need to wrap the <Application /> elements in another element <Applications />.