9

Based on my question posted a few days ago, I realized that SimpleFormController is inappropriate for handling Ajax requests. Therefore, I'm migrating my application towards annotated controllers.

I'm trying to return a java.util.List from Oracle database using Spring MVC 3.0.2 with Hibernate via Ajax using Jackson 1.9.8 (its download page) but I haven't yet worked with JSON in any technology. I have read up some tutorials/articles but I couldn't get the idea of how to return such complex data structures and parse them using JSON in Spring. I'm trying to learn JSON-like concepts first.

What basically I'm trying is when a country is selected from a country select box, the states corresponding to that country should be populated from the database via Ajax. I don't have precise idea about how to return a java.util.List over an Ajax response, how to parse it and again use it in Java code. I'm only upto the following level.

JS code.

function getStates(countryId)
{
    $.ajax({
        datatype:"json",
        type: "POST",
        url: "/wagafashion/ajax/TempAjax.htm",
        data: "countryId=" + countryId,

        success: function(response)
        {
            $('#msg').html(response);
            $('#stateList').val('');
        },
        error: function(e)
        {
            alert('Error: ' + e);
        }
    });
}

The method in the Spring controller class which is invoked when the Ajax request is made on the onchange event of the country select box.

@RequestMapping(method=RequestMethod.POST, value="ajax/TempAjax")
public @ResponseBody List<StateTable> getStateList(@ModelAttribute("tempBean") TempBean tempBean, BindingResult error, Map model, HttpServletRequest request, HttpServletResponse response)
{
    Session session=NewHibernateUtil.getSessionFactory().getCurrentSession();
    session.beginTransaction();
    List<StateTable>list=session.createQuery("from StateTable where country.countryId=:countryId order by stateId").setParameter("countryId", new BigDecimal(request.getParameter("countryId"))).list();

    session.flush();
    session.getTransaction().commit();
    return list;
}

The state select box I need to populate with the list of states returned by the Ajax response using a <c:forEach></c:forEach> loop of EL.

<form:select path="cmbState" class="validate[required] text-input tooltip" title="Mandatory select field.">
    <form:option value="">Select</form:option>

    <c:forEach items="${stateList}" var="row">
        <c:choose>
            <c:when test="${row.stateId==param['stateId'] and deselectCombo!=1}">
                <form:option value="${row.stateId}" selected="selected">${row.stateName}</form:option>
            </c:when>
            <c:otherwise>
                <form:option value="${row.stateId}">${row.stateName}</form:option>
            </c:otherwise>
        </c:choose>
    </c:forEach>
</form:select>

<font style="color: red"><form:errors path="stateId"/></font><br/>

I could only make Ajax request and response successfully. Nothing more I could understand from those tutorials found over the internet. More precisely, how can I use the Ajax response in the items attribute of the preceding <c:forEach><c:forEach> loop such as items="${stateList}"?

Could you give me some hint/idea how can I return a list of data and use it in the preceding loop to populate the state select box? Could you please lead me some steps ahead from here?

I'm using NetBeans 6.9.1 (not Eclipse). In some tutorials about Marvan projects in Eclipse, it was mentioned that the pom.xml file is required to configure to include <dependencies></dependencies> (Jackson dependency). There is no such thing like pom.xml in my project in NetBeans. Is it required to configure somewhere in some xml file in NetBeans such as the one mentioned here?

Community
  • 1
  • 1
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • I'm not sure I understand the question. the `` is a JSP tag, and therefore executes serverside. When the rendered HTML gets to the client's browser (where an AJAX request would be made) the code will already have executed. – DeejUK Aug 08 '12 at 13:02
  • @Deejay-You're right. Selecting an item from one *select box* and based on the value passed through an Ajax request populating its successor *select box* is a very basic and very usual thing. I'm asking others how do they do such stuff in Spring MVC. It doesn't mean that the thing should happen only in a way that I'm pointing out here. It's the thing that occurred to me and my assumptions might be **wrong**. I could think of the XML response of Ajax but here, I think the thing isn't going to happen because a controller has to be mapped with a JSP page which could return complex data structures – Tiny Aug 08 '12 at 16:59
  • please look at hyness's answer below. You need to alter the HTML using jquery instead of the server side code. An alternative would be to return html instead of json (on ajax) but i would prefer the former approach. – aishwarya Aug 17 '12 at 13:10

2 Answers2

13

The strategy you should use is to make the AJAX call from jQuery, take the JSON response and use it to update the form dynamically from jQuery not java. The only use I can see for the JSP tags would be to render the page when it loads. Here is how I would approach this...

  1. Change your controller to use a GET instead of a POST. For one, it is incorrect in REST to use a POST here (you are only retrieving data, not altering it). But, more importantly, it will make it easier for you to test the controller by simply putting the URL into a browser to see the JSON response. Using the @ResponseBody annotation and including Jackson on the classpath should produce a JSON response here (unless you have some Hibernate lazy loading issues).

  2. Once you verify the controller is returning JSON, update your jQuery success handler to dynamically populate the dropdown. This should be relatively easy. Test this in the browser.

  3. Write a new controller to handle this form submission. In this controller, just include a method to return the list and annotate it as @ModelAttribute("stateList"). This will make the list available for use in your <c:forEach> loop to render the page on load. You will have another method that will handle the actual form submission in the same controller.

Another thing to consider is to have better separation of concerns by putting the database code in its own service or repository. It's a bad practice to do data access in a controller in an MVC architecture. As a bonus, you won't need to duplicate any code to load the list in two different controllers.

Also, look into Spring's @Transactional declarative transaction handling. That way you won't need to write any code for transaction handling. You can also simply inject the SessionFactory instead of writing your own HibernateUtils.

Hope that helps

Edit : In REST, here are HTTP methods mapped to their corresponding CRUD actions.

  • POST - Create
  • GET - Retrieve
  • PUT - Update
  • DELETE - Delete
Tiny
  • 27,221
  • 105
  • 339
  • 599
hyness
  • 4,785
  • 1
  • 22
  • 24
  • Is it appropriate to use the `POST` method while altering data in a RESTful controller (or annotated controller), while performing `INSERT`, `UPDATE` or `DELETE` as an example? And what about the retrieval of data (with `SELECT`)? Is only the `GET` method appropriate? Shouldn't be they (`GET` and `POST`) used interchangeably? By the way, I already succeeded in implementing the task mentioned in the question. Thank you. – Tiny Nov 04 '12 at 12:28
  • I'm very glad to hear you got it working. I've added the HTTP methods and how they correlate to CRUD methods in my answer above taken from [wikipedia](https://en.wikipedia.org/wiki/Representational_state_transfer) – hyness Nov 06 '12 at 16:47
4

you should try to your option list in ajax response instead of json like below one

<option value="1">Mumbai</option>
<option value="2">Delhi</option>
<option value="3">Kerala</option>
<option value="4">Rajasthan</option>

and then your should add it to your select box liek below one

function getStates(countryId)
{
    $.ajax({
    datatype:"html",
    type: "POST",
    url: "/wagafashion/ajax/TempAjax.htm",
    data: "countryId=" + countryId,

    success: function(response)
    {
        $('#stateList').html(response);
    },
    error: function(e)
    {
        alert('Error: ' + e);
    }
  });
}

or you can create json on serverside like below one

[{"key":1, "value": "Mumbai"}, {"key":2, "value":"Delhi"}....]

and in javascript code

function getStates(countryId)
{
    $.ajax({
    datatype:"html",
    type: "POST",
    url: "/wagafashion/ajax/TempAjax.htm",
    data: "countryId=" + countryId,

    success: function(response)
    {
         if(response !=''){
              jQuery("#stateList").html("");
              jQuery.each(response, function(index,item) {
                jQuery("#stateList").append(jQuery("<option />")
                .attr("value",item.value)
                .text(item.key)); 
            });
         }

    },
    error: function(e)
    {
        alert('Error: ' + e);
    }
  });
}
rajesh kakawat
  • 10,826
  • 1
  • 21
  • 40