2

As part of learning Ajax, I have created a little servlet + some HTML page + Javascript code. The page contains a couple of buttons. The idea is to pass a parameter value in a request according to the pressed button and return the value in the response. Nothing crazy.

Here is the function making the request (button are linked to this function on click):

function loadXMLDoc2() {
    var xmlhttp;
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp=new XMLHttpRequest();
    } else {
        // code for IE6, IE5
        xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
        }
    }
    xmlhttp.open("GET","/WebFront/Ajaxlet",true);
    var retr = this.id;
    var param = "cmd=" + retr;
    document.getElementById("L1_LEFT").innerHTML = param;
    xmlhttp.send(param);
}

The L1_LEFT element allows me to check the constructed parameter (for example: cmd=bd_info).

The following method is called on the servlet side to proceed the request and response:

private void setAnswer2(HttpServletRequest req, HttpServletResponse res) throws IOException {

    Enumeration<String> iter = req.getParameterNames();

    System.out.println("Parameters=");
    while (iter.hasMoreElements()) {
        String next = iter.nextElement();
        System.out.println(next);
    }

    ...

}

However, each time I click on buttons, I get an extra parameter line printed:

Parameters=
Parameters=
Parameters=
Parameters=
...

Why? What am I doing wrong?

EDIT

Following BalusC's solution, I modified my code as following:

var retr = this.id;
var param = "cmd=" + encodeURIComponent(retr);
document.getElementById("L1_LEFT").innerHTML = param;
xmlhttp.open("POST","/WebFront/Ajaxlet",true);
xmlhttp.send(param);

and

    Map<String, String[]> en = req.getParameterMap();

    System.out.println("Parameters=");
    for (String next : en.keySet()) {
        System.out.println(next);
    }

The GET solution works, but the POST solution does not work (same issue). I read that POST is preferable to GET. Anyone knows why POST would not work?

EDIT II

Here is the servlet code:

@WebServlet(name="Ajaxlet", urlPatterns={"/Ajaxlet"}, asyncSupported=false)
public class Ajaxlet extends HttpServlet {

    private void setAnswer2(HttpServletRequest req, HttpServletResponse res) throws IOException {

        Map<String, String[]> en = req.getParameterMap();

        System.out.println("Parameters=");
        for (String next : en.keySet()) {
            System.out.println(next);
        }

        res.setContentType("text/html");
        PrintWriter out = res.getWriter();
        out.println(System.currentTimeMillis());
        out.close();        

    }

    @Override
    public void doPost(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {

        System.out.println("doPost");
        setAnswer2(req, res);

    }

}

EDIT III

Here is my web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd">
    <servlet>
        <display-name>Ajaxlet</display-name>
        <servlet-name>Ajaxlet</servlet-name>
        <servlet-class>net.test.Ajaxlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Ajaxlet</servlet-name>
        <url-pattern>/Ajaxlet/*</url-pattern>
    </servlet-mapping>
    <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>
</web-app>

and my context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/WebFront"/>

EDIT IV

Updated my web.xml to:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
      version="3.0"> 

    <welcome-file-list>
            <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

</web-app>

Still having the same issue with POST.

Jérôme Verstrynge
  • 57,710
  • 92
  • 283
  • 453

2 Answers2

2

Had exactly this same problem, for documentations sake the solution was in my Javascript code,

When sending "form data" in your AJAX Post, you need to set a header like so..

xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded") xmlhttp.send("paramName=paramValue")

source: http://www.w3schools.com/ajax/ajax_xmlhttprequest_send.asp

danofa
  • 21
  • 3
2

You're creating a GET request and then sending the parameter in the request body. This isn't going to work. In order to send data in the request body, you have to create a POST request (and do the server side request processing job in servlet's doPost() method instead of doGet()):

xmlhttp.open("POST", "/WebFront/Ajaxlet", true);
xmlhttp.send(param);

On GET requests, you normally append the query string with the parameters to the request URL, not the request body:

xmlhttp.open("GET", "/WebFront/Ajaxlet?" + param, true);
xmlhttp.send(null);

Regardless of the request method, you should ensure that parameter names and values are properly URL encoded! You can use JS' builtin encodeURIComponent() function for this:

var param = "cmd=" + encodeURIComponent(retr);

Unrelated to the concrete problem, I know that you're learning Ajax, but I suggest to after all take a look at an existing JavaScript library which takes all the nasty and cross browser sensitive details of sending Ajax requests and traversing/manipulating the HTML DOM from your hands, such as jQuery. In this related question you can find some nice examples how to get started with jQuery + Servlets: How to use Servlets and Ajax?

Another unrelated note, you should prefer getParameterMap() to iterate over parameter names and values. It returns a Map instead of an old fashioned Enumeration; a Map allows you to use the enhanced for loop.

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • I am using/learning JQuery too. I got your GET solution to work, but the POST still does not work. I have updated my question. If you or anyone know why, I am interested. Thanks. – Jérôme Verstrynge Oct 16 '11 at 23:37
  • Did you implement the `doPost()` method? – BalusC Oct 16 '11 at 23:39
  • Yes, and I double-checked it is called by adding an explicit print statement. I have been googling for other code examples, and it seems yours is correct. It could be something different at the Tomcat/NetBeans level. – Jérôme Verstrynge Oct 16 '11 at 23:48
  • Do you have an `@Override` annotation on the method? Does it compile with that annotation? Did you rebuild/redeploy/restart after editing the servlet class? – BalusC Oct 16 '11 at 23:49
  • Yes, I have the override, it compiles, I clean/rebuild/redeploy and restarted Tomcat. Still the same issue. I put my servlet code in my question. – Jérôme Verstrynge Oct 16 '11 at 23:58
  • Well, maybe something in the request-response chain has consumed your request body (the one as obtained by `request.getReader()` or `request.getInputStream()`) before the servlet had any chance to parse the parameters out of it. Perhaps an overzealous logging filter or something? I'd also check with a HTTP traffic checker like Firebug's *Net* panel if the client has really sent the proper POST request body. – BalusC Oct 17 '11 at 00:02
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/4314/discussion-between-jverstry-and-balusc) – Jérôme Verstrynge Oct 17 '11 at 00:07