RestController with GET + POST on same method? - java

I'd like to create a single method and configure both GET + POST on it, using spring-mvc:
#RestController
public class MyServlet {
#RequestMapping(value = "test", method = {RequestMethod.GET, RequestMethod.POST})
public void test(#Valid MyReq req) {
//MyReq contains some params
}
}
Problem: with the code above, any POST request leads to an empty MyReq object.
If I change the method signature to #RequestBody #Valid MyReq req, then the post works, but the GET request fails.
So isn't is possible to just use get and post together on the same method, if a bean is used as input parameters?

The best solution to your problem seems to be something like this:
#RestController
public class MyServlet {
#RequestMapping(value = "test", method = {RequestMethod.GET})
public void testGet(#Valid #RequestParam("foo") String foo) {
doStuff(foo)
}
#RequestMapping(value = "test", method = {RequestMethod.POST})
public void testPost(#Valid #RequestBody MyReq req) {
doStuff(req.getFoo());
}
}
You can process the request data in different ways depending on how you receive it and call the same method to do the business logic.

#RequestMapping(value = "/test", method = { RequestMethod.POST, RequestMethod.GET })
public void test(#ModelAttribute("xxxx") POJO pojo) {
//your code
}
This will work for both POST and GET. (make sure the order first POST and then GET)
For GET your POJO has to contain the attribute which you're using in request parameter
like below
public class POJO {
private String parameter1;
private String parameter2;
//getters and setters
URl should be like below
/test?parameter1=blah
Like this way u can use it for both GET and POST

I was unable to get this working on the same method and I'd like to know a solution, but this is my workaround, which differs from luizfzs's in that you take the same request object and not use #RequestParam
#RestController
public class Controller {
#GetMapping("people")
public void getPeople(MyReq req) {
//do it...
}
#PostMapping("people")
public void getPeoplePost(#RequestBody MyReq req) {
getPeople(req);
}
}

Related

How do I execute two Mappings at once in SpringBoot by calling only the first mapping first?

#PostMapping(value = "/save")
public String saveRequest(#RequestBody Request request) {
requestRepo.save(request);
return "Saved...";
}
#RequestMapping(value = "/redirect", method = RequestMethod.GET)
public void method(HttpServletResponse httpServletResponse) {
httpServletResponse.setHeader("Location", "https://www.google.com");
httpServletResponse.setStatus(302);
}
Is there a way to execute the second mapping automatically after executing the first mapping?
Or a way to mix/make this better?
EDIT: updated redirect mapping method
#PostMapping(value = "/yourEndpointFromWhichToBeRedirected")
public String saveRequest(#RequestBody Request request) {
requestRepo.save(request);
return "redirect:/endpointToWhichToBeRedirectedTo";
}

How can I get my spring boot controller to read the body of my http request to an object if the http request has content type urlencoded?

I am new to spring and spring boot and have set up a simple controller that can read http requests to an object if there is a header set setting the content-type to application/json.
However, when I do not set the content type in a header, this does not work and I get the error: "Content type 'application/x-www-form-urlencoded;charset=UTF-8' not supported". I understand that at no point have I told the controller that I actually want the it to read the body as JSON rather than as urlencoded and I'm looking for a way of doing this.
I have experimented with the #RequestBody, #RequestParam and #ResponseBody annotations but so far have had no luck.
I have also looked at overriding the WebMvcConfigurer.configureContentNegotiation method by setting default and other media-types but am less clear on what I am doing here.
Here is my simple controller in its current form
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public Greeting postGreeting(#RequestBody Greeting body) {
return new Greeting(body.getId(),"hello " + body.getContent());
}
}
Here is the constructor for my greeting class for reference:
public Greeting(long id, String content) {
this.id = id;
this.content = content;
}
The body of my request is '{"id":10, "content": "world"}'
Ideally, I would like to find a way to be able to process an http request with no content type header set (so presumably defaulting to form-urlencoded) as JSON so that there is less to think about when setting up the post request and the controller is less brittle.
Try this:
#RestController
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public HttpEntity<String> postGreeting(#RequestBody Greeting body) {
//SETGREETING()
return new HttpEntity<String>("data has been saved");
}
}
And don't forget to accept application/json header.
Try below code
import org.springframework.web.bind.annotation.ModelAttribute;
public class GreetingController {
#RequestMapping(value = "/greeting",
method = RequestMethod.POST)
public Greeting postGreeting(#ModelAttribute Greeting body) {
return new Greeting(body.getId(),"hello " + body.getContent());
}
}

Can I create multiple HTTP POST methods with same request mapping with different requestbody

Can I create multiple HTTP POST methods with same request mapping with different requestbody
#RequestMapping("api/v1/")
#RequestMapping(value = "test" ,method = RequestMethod.POST)
public RObjet create(#RequestBody RBody rbody)
{
// do some process...
}
#RequestMapping("api/v1/")
#RequestMapping(value = "test" ,method = RequestMethod.POST)
public RObjet2 create2(#RequestBody RBody2 rbody)
{
// do something.
}
Is this possible.? How do we handle this in spring boot.
Yes, you can use POST Http Method for the same end point URI with different request body and also you could get different responses. One way to achieve this, is mapping requests using end point URI + Headers
e.g.
#RestController
#RequestMapping("/api/bills")
public class BillingController {
#RequestMapping(method = RequestMethod.POST, headers = "action=add-bill")
public BillId addBill(#Valid #RequestBody BillingData data) {
//Some code
}
#RequestMapping(method = RequestMethod.POST, headers = "action=delete-bill-by-id")
#ResponseStatus(code = HttpStatus.NO_CONTENT)
public void removeBill(#Valid #RequestBody BillId identifier) {
//Some code here to remove bill
}
}
In this case, both class methods in BillingController are mapped to the same HTTP Method (POST) and URI (/api/bills). The header action drives what class method in BillingController is going to be invoked once you point your post request to /api/bills
How to hit BillingController.addBill?
NOTE: I know that good REST API design dictates that if I want to delete records I should use DELETE method, however this sample was created only as reference to show how to use same URI/Method to handle 2 different end points.
You have to option for this.
it is possible with consumes field. You can use different consuming types.
You can user params field if you have in url.
#RequestMapping(value="/path", params="id")
public String test1(#RequestBody RBody body) {}
#RequestMapping(value="/path", params="name")
public String test2(#RequestBody RBody body) {}

How to put parameters in RESTful POST with JerseyFramework

Let's assume that I have simple class:
public class Test
{
#Path("/test")
#POST
#Produces(APPLICATION_JSON)
#Consumes(APPLICATION_JSON)
public TestResponse post(TestResponse request, #HeaderParam("text") String text)
{
return new TestResponse(request.getData());
}
}
and I want to test this class. So how I can param in code like this:
Entity<TestRequest> requestEntity = Entity.entity(request, MediaType.APPLICATION_JSON);
final TestResponse response = target("test").request().post(requestEntity, TestResponse.class);
target("test").request().header("text", "value").post(...);
When you call request(). You get back an Invocation.Builder. You can take a look at the other methods. For the most part they all return the same Invocation.Builder, so can just chain the calls.

How to read flash attributes after redirection in Spring MVC 3.1?

I would like to know how to read a flash attributes after redirection in Spring MVC 3.1.
I have the following code:
#Controller
#RequestMapping("/foo")
public class FooController {
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(...) {
// I want to see my flash attributes here!
}
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public ModelAndView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new ModelAndView().setViewName("redirect:/foo/bar");
}
}
What I am missing?
Use Model, it should have flash attributes prepopulated:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(Model model) {
String some = (String) model.asMap().get("some");
// do the job
}
or, alternatively, you can use RequestContextUtils#getInputFlashMap:
#RequestMapping(value = "/bar", method = RequestMethod.GET)
public ModelAndView handleGet(HttpServletRequest request) {
Map<String, ?> inputFlashMap = RequestContextUtils.getInputFlashMap(request);
if (inputFlashMap != null) {
String some = (String) inputFlashMap.get("some");
// do the job
}
}
P.S. You can do return return new ModelAndView("redirect:/foo/bar"); in handlePost.
EDIT:
JavaDoc says:
A RedirectAttributes model is empty when the method is called and is
never used unless the method returns a redirect view name or a
RedirectView.
It doesn't mention ModelAndView, so maybe change handlePost to return "redirect:/foo/bar" string or RedirectView:
#RequestMapping(value = "/bar", method = RequestMethod.POST)
public RedirectView handlePost(RedirectAttributes redirectAttrs) {
redirectAttrs.addFlashAttributes("some", "thing");
return new RedirectView("/foo/bar", true);
}
I use RedirectAttributes in my code with RedirectView and model.asMap() method and it works OK.
Try this:
#Controller
public class FooController
{
#RequestMapping(value = "/foo")
public String handleFoo(RedirectAttributes redirectAttrs)
{
redirectAttrs.addFlashAttribute("some", "thing");
return "redirect:/bar";
}
#RequestMapping(value = "/bar")
public void handleBar(#ModelAttribute("some") String some)
{
System.out.println("some=" + some);
}
}
works in Spring MVC 3.2.2
For all those like me who were having problems with seeing the POST url in the browser when a validation would fail.
The POST url is a private url that should not be exposed to users but it was automatically rendered when a validation failed. i.e. if a field was below a minimum length. I was using #Valid. I wanted the original GET url of the form to show at all times even when validation bounced back to the form, so I did the following:
if (validation.hasErrors()) {
redirectAttributes.addFlashAttribute("org.springframework.validation.BindingResult.story", validation);
redirectAttributes.addFlashAttribute("story", story);
return new ModelAndView("redirect:/january/2015");
where story is the form object representation, redirectAttributes are RedirectAttributes you put in the method signature and validation is the BindingResult. /january/2015 is the mapping to the GET controller where the form lives.
After this implementation, in the mapping for /january/2015, story comes in intact as follows:
Story story= (Story) model.asMap().get("story");
//story from the POST method
I had to augment my GET method and check if this was not null. If not null, then send this to the form else I would send a newly initialized Story type to the form as default behaviour before.
In this manner, I am able to return to the form with the bindingresults intact (errors show on form) but have my GET url in place of the post url.

Categories

Resources