6

I'm currently learning using Spring MVC. During development, I used four different kind of form handling with Ajax & jQuery. Now, I'm wondering what are advantages and disadventages of each methods. Are there any others?

Let's say we have a really simple form with just 2 inputs

<input id="name" type="text" value"Name">
<input id="active" type="checkbox">
<input type="button" onclick="submitForm()">

Let's assume that we are not validating data either on client and server site. We will also omitt handling data returned. I'm just interested in sending data to server. Now how can we handle submit? My solutions were:

1. Request based on PathVariable

JS sending request would look sth like this:

function submitForm() {
    var name = jQuery("#name").val();
    var active = jQuery("#active").is("checked");

    jQuery.ajax("/Submit/Name/" + name + "/Active/"+ active + "/",
    {
        type:"POST"
    });   
}

And also Controller:

 @RequestMapping(value="/Submit/Name/{name}/Active/{active}/",method=RequestMethod.POST)
 publis void submitForm(@PathVariable String name, @PathVariable Boolean active)
 { //something not important here }

Pros in my opinion

  • quick way to recieve data in Controller, simple annotation make it works
  • type maching for basic types of data (String, Boolean, Numeric)

Cons

  • request address grows with data needed
  • problem with special characters in url? Not sure about this one, but I remember my teammate had problem with / used as char in data sended to server

2. Request with data

I haven't got clue how name it, but this is the idea in JS file:

function submitForm() {
    var name = jQuery("#name").val();
    var active = jQuery("#active").is("checked");

    var object = {name:name,active:active};

    jQuery.ajax("/Submit/",
    {
        type:"POST",
        data: object
    });   
}

And Controller:

 @RequestMapping(value="/Submit/",method=RequestMethod.POST)
 publis void submitForm(@RequestParam(value="name") String name, @RequestParam(value="active") Boolean active)
 { //something not important here }

In my opinion, not much different from first method, but:

Pros

  • shorter request address

Cons

  • method declaration with many parameters may be huge

3.Sending JSON to server as PathVariable

In JS file:

function submitForm() {
    var name = jQuery("#name").val();
    var active = jQuery("#active").is("checked");

    var object = {name:name,active:active};

    jQuery.ajax("/Submit/" + JSON.stringify(object),
    {
        type:"POST"
    });   
}

And Controller

 @RequestMapping(value="/Submit/{json}",method=RequestMethod.POST)
 publis void submitForm(@RequestParam(value="name") String name, @RequestParam(value="active") Boolean active)
 { 
    //now we are actually doing sth important here, cause we need to parse JSON
 }

Pros

  • short request address
  • short method declaration

Cons

  • JSON parsing on my own

4.JSON as RequestBody with class mapped

My favourite method, but not always possible as we need to write multiple class just for wrapping sent data, JS:

function submitForm() {
    var name = jQuery("#name").val();
    var active = jQuery("#active").is("checked");

    var object = {name:name,active:active};

    jQuery.ajax("/Submit/",
    {
        type:"POST",
        data:JSON.stringify(object)
    });

And Java code:

public class Wrapper {
    private String name;
    private Boolean active;    
    //getters and setters
}

 @RequestMapping(value="/Submit/",method=RequestMethod.POST)
 publis void submitForm(@RequestBody Wrapper wrapper)
 { 
    //all data available with Wrapper class
 }

Pros

  • mapping into desired object
  • quick and simple

Cons

  • we need to write wrappers for every data sent to server

That would be all I know currently. I would appreciate and critism, suggestions for better solutions or anything. Thanks!

kamil
  • 3,482
  • 1
  • 40
  • 64
  • In my humble opinion this is not a question fit for Q&A, you asking a lot of things at ones of which most if not even all are very subjective. – Nope Aug 24 '12 at 23:25
  • @FrançoisWahl, I agree it's a borderline case, but it's still an interesting questions which I believe SO is best fit for. – Johan Sjöberg Aug 24 '12 at 23:34
  • I don't believe that the "Con" for approach 4 is a "Con". Your wrapper object could be considered to be your domain `M`odel(s) - the `M` of SpringMVC, which you will probably have a use for already, perhaps to persist somewhere? Spring (and Jackson) can already convert/bind nested JSON into objects - see http://stackoverflow.com/questions/5900840/post-nested-object-to-spring-mvc-controller-using-json. I think you should read up on RESTful services as that will probably help in determining the best way. I tend to use 1. and 4. in projects. – andyb Aug 24 '12 at 23:45
  • @JohanSjöberg: You don't think it falls under `Chatty, open-ended questions`? specially asking for`. I would appreciate and critism, suggestions for better solutions or anything.`? Ah, well if it helps OP and you can provide an answer. it's all good :) – Nope Aug 25 '12 at 00:03

3 Answers3

2

(1) Request based on PathVariable

As you said you will get problems with special characters (such as /). Path-based URLs are most readable if left short. E.g., /hotel/{h}/room/{r}. Sometimes, a combination of path and request parameters are used to denote mandatory vs optional parameters.

(2) Request with data

This would be a great approach giving you flexibility to easily add/remove Request Parameters as well as managing different combinations of parameters.

(3) Sending JSON to server as PathVariable

I see the same technical problems with this approach as (1). Without proper escaping (and Spring at the current time of writing can't handle / in any form) this option is not viable. (4) is the way to do this.

(4) JSON as RequestBody with class mapped

This would be preferable for complex objects. Typically spring can help you map json to Java objects directly. The tradeoff is that it cannot be tested as easily from a browser. I believe this is a common pattern in RESTful services, although it doesn't necessarily dictate a transmission technology.


In summary,

  • using query parameters is simple, and enables users to test the service directly from the browsers address bar.

  • using objects in the request body is useful to get flexibility in handling complex data but cannot as easily be tested from the browser.

The path-variable options don't fair well with spring unless well-formed data withouth special characters such as / are submitted.

Johan Sjöberg
  • 47,929
  • 21
  • 130
  • 148
2

I do very often the (2) and the (4) methods. The (2) because of its flexibility. The (4) when I need high coupled datas and want to validate input easily i.e. with @Valid annotation added to the Controller's method parameter I use to bind the datas sent.

BendaThierry.com
  • 2,080
  • 1
  • 15
  • 17
2

I mostly do 1, 2, and 4.

Spring Roo will and does autogenerate code for 1, 2 and 4.

1, 2, and 4 largely depend on whether or not your doing a POST, GET, PUT, DELETE (CRUD respectively).

Number 1 - Path Variable

Is almost always GET for a single item. It is the READ in CRUD.

Number 2 - Request Parameter

For true REST this should be for optional parameters like paging a list or filters for search using GET. There should be no request body.

For POST its also used for old school REST and most importantly for traditional HTML FORMS (aka application/x-www-form-urlencoded.

This is important because its much easier for people do this one (#2) for POST than #4.

Number 3 - Don't do this.

Others have stated why.

Number 4 - JSON Request Body

This is almost always done for a POST and PUT (aka C and U of the CRUD). Its usually combined with a PathVariable to specify which item(s).

This is hard to test in a browser and requires your clients know the valid format to make updates. ie. Name Value pairs are easier to doc and understand then JSON/XML schema.

What I do

Lately I have been doing number #2 so that I can support both HTML full loads or data only loads of JSON for Single Page Applications.

I do it through a custom view resolver so that I don't have to write two methods for every request.

Otherwise you'll have to make two methods for each request (one with application/json and the other one for HTML).

@RequestMapping(method = RequestMethod.POST, headers = "Accept=application/json")
public Object doJson() {}

@RequestMapping(method = RequestMethod.POST)
public Object doHtml() { //after processing redirect. }
Adam Gent
  • 47,843
  • 23
  • 153
  • 203