redirect to POST method in same controller - java

I have a spring RestController and want to redirect to POST method in same controller with RequestBody.
any solution welcomes, not only redirect.
MyController:
#RequestMapping(value = "/addCompany", method = RequestMethod.POST)
public String addCompany(#Valid Company company, BindingResult result,
HttpServletRequest request, Model model) throws Exception {
//some logic
//need to pass Company Object as RequestBody
return "redirect:/app/postmethod/";
}
//Method to redirected
#RequestMapping(value = "/postmethod", method = {RequestMethod.POST, RequestMethod.GET})
public String getData( #RequestBody(required=false) Company compnay, HttpServletRequest request, Model model) throws Exception {
//some logic
//required company object
return "htmlpage";
}
I need to redirect my request to /postmethod from addCompany method in the same controller, I am open to use any feasible solution.

Check here:
https://www.baeldung.com/spring-redirect-and-forward#redirecting-an-http-post-request
As per HTTP 1.1 protocol reference, status codes 301 (Moved
Permanently) and 302 (Found) allow the request method to be changed
from POST to GET. The specification also defines the corresponding 307
(Temporary Redirect) and 308 (Permanent Redirect) status codes that
don't allow the request method to be changed from POST to GET.
#PostMapping("/redirectPostToPost")
public ModelAndView redirectPostToPost(HttpServletRequest request) {
request.setAttribute(
View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:/redirectedPostToPost");
}
#PostMapping("/redirectedPostToPost")
public ModelAndView redirectedPostToPost() {
return new ModelAndView("redirection");
}
The request body will be passed. Here is an example using your code:
#RestController
#RequestMapping("app")
public class TestController {
#PostMapping("/addCompany")
public ModelAndView addCompany(#RequestBody Company company, HttpServletRequest request) {
System.out.println("First method: " + company.name);
request.setAttribute(
View.RESPONSE_STATUS_ATTRIBUTE, HttpStatus.TEMPORARY_REDIRECT);
return new ModelAndView("redirect:/app/postmethod/");
}
#PostMapping("/postmethod")
public void getData(#RequestBody Company company) {
System.out.println("Redirected: " + company.name);
}
public static class Company {
String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}
When using POST request to http://localhost:8080/app/addCompany with body {"name": "Test Company"}, in the output I receive next:
First method: Test Company
Redirected: Test Company

I found a good explanation on this page here.
For protecting users against inadvertently (re)submitting a POST transaction which they had not intended, or submitting a POST into a context which they would not have wanted.
So you can set the data in session and using get method to call post method if you want to do this.

Related

PageNotFound - Request method 'GET' not supported

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.
}

GET & POST in RequestMapping [duplicate]

I have a resource that supports both GET and POST requests. Here a sample code for a sample resource:
#RequestMapping(value = "/books", method = RequestMethod.GET)
public ModelAndView listBooks(#ModelAttribute("booksFilter") BooksFilter filter, two #RequestParam parameters, HttpServletRequest request)
throws ParseException {
LONG CODE
}
#RequestMapping(value = "/books", method = RequestMethod.POST)
public ModelAndView listBooksPOST(#ModelAttribute("booksFilter") BooksFilter filter, BindingResult result)
throws ParseException {
SAME LONG CODE with a minor difference
}
The code in the two methods is practically the same, except for lets say a variable definition. The two methods can be easily combined using method = {RequestMethod.POST, RequestMethod.GET}, and a simple if inside. I tried, but it doesn't work, because the two methods have a different parameter at the end, i.e. HttpServletRequest and BindingResult (the #RequestParam's are not required and therefore not needed in the POST request). Any ideas how to combine the two methods?
#RequestMapping(value = "/testonly", method = { RequestMethod.GET, RequestMethod.POST })
public ModelAndView listBooksPOST(#ModelAttribute("booksFilter") BooksFilter filter,
#RequestParam(required = false) String parameter1,
#RequestParam(required = false) String parameter2,
BindingResult result, HttpServletRequest request)
throws ParseException {
LONG CODE and SAME LONG CODE with a minor difference
}
if #RequestParam(required = true) then you must pass parameter1,parameter2
Use BindingResult and request them based on your conditions.
The Other way
#RequestMapping(value = "/books", method = RequestMethod.GET)
public ModelAndView listBooks(#ModelAttribute("booksFilter") BooksFilter filter,
two #RequestParam parameters, HttpServletRequest request) throws ParseException {
myMethod();
}
#RequestMapping(value = "/books", method = RequestMethod.POST)
public ModelAndView listBooksPOST(#ModelAttribute("booksFilter") BooksFilter filter,
BindingResult result) throws ParseException {
myMethod();
do here your minor difference
}
private returntype myMethod(){
LONG CODE
}
Below is one of the way by which you can achieve that, may not be an ideal way to do.
Have one method accepting both types of request, then check what type of request you received, is it of type "GET" or "POST", once you come to know that, do respective actions and the call one method which does common task for both request Methods ie GET and POST.
#RequestMapping(value = "/books")
public ModelAndView listBooks(HttpServletRequest request){
//handle both get and post request here
// first check request type and do respective actions needed for get and post.
if(GET REQUEST){
//WORK RELATED TO GET
}else if(POST REQUEST){
//WORK RELATED TO POST
}
commonMethod(param1, param2....);
}
#RequestMapping(value = "/books", method = { RequestMethod.GET,
RequestMethod.POST })
public ModelAndView listBooks(#ModelAttribute("booksFilter") BooksFilter filter,
HttpServletRequest request)
throws ParseException {
//your code
}
This will works for both GET and POST.
For GET if your pojo(BooksFilter) have to contain the attribute which you're using in request parameter
like below
public class BooksFilter{
private String parameter1;
private String parameter2;
//getters and setters
URl should be like below
/books?parameter1=blah
Like this way u can use it for both GET and POST

#PutMapping and #PostMapping annotations on same method

I want to apply both Put and Post mapping request to a method as show below. It does work for PUT, but not for POST requests. What am I dong wrong?
#RestController
#RequestMapping("/PQR")
public class XController {
#PutMapping("xyz")
#PostMapping("xyz")
public MyDomainObject createOrUpdateDAO(
HttpServletRequest request,
#RequestBody String body) throws IOException {
//...
}
}
When I make a POST request, I get a 405 HTTP status code:
[nio-8080-exec-3] o.s.web.servlet.PageNotFound: Request method 'POST' not supported
If I look at this example, same method has same method is mapped for GET and POST requests.
#RequestMapping(value="/method3", method = { RequestMethod.POST,RequestMethod.GET })
#ResponseBody
public String method3() {
return "method3";
}
Remove #PostMapping and #PutMapping annotations and add method to your #RequestMapping, i.e:
#RequestMapping(value={"/PQR", "xyz"},
method={RequestMethod.POST,RequestMethod.PUT})

Transferring an object via REST

I've been trying to send an object from one application to another using rest.
Sender:
#Controller
public class Sender {
#RequestMapping(value = "/comMessageApp-api/getMessages")
public String restGetMessages() {
String url = "http://localhost:8079/comMessageApp-api/responseMessages";
HttpEntity<Dto2> entity = new HttpEntity<>(new Dto2());
ResponseEntity<Dto2> response = restTemplate.exchange(url, HttpMethod.POST, entity, Dto2.class);
}
}
Receiver:
#RestController
public class Receiver {
#RequestMapping(value = "/comMessageApp-api/responseMessages")
public void restResponseMessages(HttpEntity<Dto2> request) {
System.out.println(request.getBody());
}
}
DTO:
public class Dto2 {
private String string = "Test string";
public Dto2() {
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
}
Jackson is used serialization/deserialization.
Any ideas, why request.getBody() printed in the Receiver is null???
I tried to send the object inside HttpEntity and inside RequestEntity. No success in both cases. On the receiving side I always get null.
Your sender (client) side is very close but your server side doesn't return a value so change the type to Void:
ResponseEntity<Void> response = restOps.exchange(url, HttpMethod.POST, entity, Void.class);
Your receiver (server) side is not quite set up correctly either, you need to set the HTTP method to [edited] POST. You'll also need to tell Spring to map the body of the request (your rest payload) onto the parameter;
#RequestMapping(value = "/comMessageApp-api/responseMessages", method=RequestMethod.POST)
public void recieveDto (#RequestBody final Dto dto) {
System.out.println(dto.toString());
}
[EDIT] Brainfart, the http method should be set to POST on receive annotation.
[Further suggestion]
403 errors may be due to Spring Security, if you have it switched on (check your POM if you're not sure) try this;
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf()
.disable()
.authorizeRequests().
antMatchers("/**").permitAll();
}
}
You'll want to be tightening up security once you know it works.
try to use #RequestMapping(method = RequestMethod.POST, produces = "application/json", consumes = "application/json")

How to redirect to external url from service class?

In my current spring project, I am adding several pairs of classes (controller/service) to provide payment option through several payment services. Each one of this classes have a structure like that:
controller
#Controller
#RequestMapping(value = "pagseguro")
public class pagseguroPaymentController extends paymentController<Pagseguro> {
...
#Override
#RequestMapping(value = "comprar", method = RequestMethod.POST)
public void comprar(String payerId, String guid) throws Exception {
this.payment.comprar(payerId, guid);
}
...
}
service
#Service
public class pagseguroPaymentService extends paymentService<Pagseguro> {
...
#Override
public void comprar(String payerId, String guid) throws Exception {
...
String response = checkout.register(null, false);
}
...
}
in the method comprar from service class, I need redirect the application to an URL stored in a String variable (response in the example above).
My initial idea is use the library java.net from Java and create a utilitary class like that:
public class Redirect {
public static String url;
public static void redirect() {
...
}
}
Anyone can give me a hint about how to accomplish that?
To perform a simple redirection, you can inject the HttpServletResponse in your Controller layer:
#RequestMapping(value = "comprar", method = RequestMethod.POST)
public void comprar(String payerId, String guid, HttpServletResponse response) throws Exception {
this.payment.comprar(payerId, guid);
}
And then simply do a redirect using that object:
response.sendRedirect("http://newUrl");
Now - as the Luiggi mentions in the comment - I would not do the redirect itself in the service layer, but rather return a boolean which decides if the redirect needs to be done - and then do it here, in the controller layer.
Hope it helps.

Categories