79

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?

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 14
    Why don't you move your LONG CODE to a separate method? – Narendra Pathai Aug 01 '13 at 07:11
  • And if it's so long, you should even split it into several short methods – JB Nizet Aug 01 '13 at 07:19
  • Because I'm looking for a more elegant and general solution. I don't think I's good to have a method `booksLogic` that is the only thing I call in the two methods. –  Aug 01 '13 at 07:19
  • 1
    @MilanMilanov: this would be the most elegant solution. Having short methods that do one thing well and delegate to other short methods is what you should strive for. – JB Nizet Aug 01 '13 at 07:21
  • 2
    Generally you use GET for things that do not change the server, and POST for things that change the server. They are the equivalent http operations of READ and WRITE in database. So its ideal to separate them and split the common logic to a different method – Dhanush Gopinath Aug 01 '13 at 07:22
  • The LONG CODE is actually not that long, its just the logic for my controller. I wanted you to see the point the I don't want to copy and paste the same code. –  Aug 01 '13 at 07:34

3 Answers3

120
@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
}
Radek Postołowicz
  • 4,506
  • 2
  • 30
  • 47
Prabhakaran Ramaswamy
  • 25,706
  • 10
  • 57
  • 64
9

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....);
}
Jayesh
  • 6,047
  • 13
  • 49
  • 81
  • I'm asking exactly for the signature of that common method.. how can it accept both `HttpServletRequest` and `BindingResult`? –  Aug 01 '13 at 07:33
  • 1
    By default, if you not mention any mapping method < @RequestMapping(value = "/books") > then it will accept both GET and POST request, only part you need to check is BindingResult. Need to Explore that. i think it can handle that part still need to check – Jayesh Aug 01 '13 at 07:56
  • you can accept HttpServletRequest inside parameter, Also, if you have less data on BindingResult then accept your parameter using request.getParameter("paramName") and check by conditions which would work for both. (try this if BindingResult is giving you issues then only otherwise it will work by removing RequestMethod mapping i think) – Jayesh Aug 01 '13 at 08:00
3
@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

MPPNBD
  • 1,566
  • 4
  • 20
  • 36