¿Cómo debo utilizar servlets y Ajax?

Resuelto Amir Rachum asked hace 14 años • 7 respuestas

Cada vez que imprimo algo dentro del servlet y lo llamo mediante el navegador web, devuelve una nueva página que contiene ese texto. ¿Hay alguna forma de imprimir el texto de la página actual usando Ajax?

Soy muy nuevo en aplicaciones web y servlets.

Amir Rachum avatar Nov 06 '10 17:11 Amir Rachum
Aceptado

De hecho, la palabra clave es "Ajax": JavaScript y XML asincrónicos . Sin embargo, en los últimos años es más común que JavaScript y JSON asincrónicos. . Básicamente, permite que JavaScript ejecute una solicitud HTTP asincrónica y actualice el árbol HTML DOM en función de los datos de respuesta.

Dado que es un trabajo bastante tedioso lograr que funcione en todos los navegadores (especialmente Internet Explorer frente a otros), existen muchas bibliotecas de JavaScript que simplifican esto en funciones únicas y cubren tantos errores/peculiaridades específicos del navegador como sea posible. como jQuery , prototipo , mootools . Dado que jQuery es el más popular hoy en día, lo usaré en los ejemplos siguientes.

Ejemplo de inicio que regresaString como texto sin formato

Crea un /some.jspme gusta a continuación:

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>SO question 4112686</title>
        <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>
        <script>
            const yourServletURL = "${pageContext.request.contextPath}/yourServlet";
            $(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
                $.get(yourServletURL, function(responseText) {  // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response text...
                    $("#somediv").text(responseText);           // Locate HTML DOM element with ID "somediv" and set its text content with the response text.
                });
            });
        </script>
    </head>
    <body>
        <button id="somebutton">press here</button>
        <div id="somediv"></div>
    </body>
</html>

Cree un servlet con un doGet()método similar a este:

@WebServlet("/yourServlet")
public class YourServlet extends HttpServlet {

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String text = "some text";

        response.setContentType("text/plain");  // Set content type of the response so that jQuery knows what it can expect.
        response.setCharacterEncoding("UTF-8"); // You want world domination, huh?
        response.getWriter().write(text);       // Write response body.
    }
}

Obviamente, el patrón de URL de /yourServletes libre de su elección, pero si lo cambia, deberá modificar la /yourServletcadena en elyourServletURL variable JS en consecuencia.

Ahora abra http://localhost:8080/context/test.jsp en el navegador y presione el botón. Verás que el contenido del div se actualiza con la respuesta del servlet.

Volviendo List<String>como JSON

Con JSON en lugar de texto sin formato como formato de respuesta, incluso puedes avanzar algunos pasos. Permite más dinámica. Primero, le gustaría tener una herramienta para convertir entre objetos Java y cadenas JSON. También hay muchos de ellos (consulte la parte inferior de esta página para obtener una descripción general). Mi favorito personal es Google Gson .

A continuación se muestra un ejemplo que se muestra List<String>como <ul><li>. El servlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<String> list = new ArrayList<>();
    list.add("item1");
    list.add("item2");
    list.add("item3");
    String json = new Gson().toJson(list);

    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(json);
}

El código JavaScript:

$(document).on("click", "#somebutton", function() {    // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
    $.get(yourServletURL, function(responseJson) {     // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $ul = $("<ul>").appendTo($("#somediv")); // Create HTML <ul> element and append it to HTML DOM element with ID "somediv".
        $.each(responseJson, function(index, item) {   // Iterate over the JSON array.
            $("<li>").text(item).appendTo($ul);        // Create HTML <li> element, set its text content with currently iterated item and append it to the <ul>.
        });
    });
});

Tenga en cuenta que jQuery analiza automáticamente la respuesta como JSON y le proporciona directamente un objeto JSON ( responseJson) como argumento de función cuando configura el tipo de contenido de la respuesta en application/json. Si olvida configurarlo o confía en un valor predeterminado de text/plaino text/html, entonces el responseJsonargumento no le dará un objeto JSON, sino una cadena simple y necesitará manipularla manualmente JSON.parse()después, lo cual es totalmente innecesario si establezca el tipo de contenido en primer lugar.

Volviendo Map<String, String>como JSON

Aquí hay otro ejemplo que se muestra Map<String, String>como <option>:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Map<String, String> options = new LinkedHashMap<>();
    options.put("value1", "label1");
    options.put("value2", "label2");
    options.put("value3", "label3");
    String json = new Gson().toJson(options);

    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(json);
}

Y el JSP:

$(document).on("click", "#somebutton", function() {               // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
    $.get(yourServletURL, function(responseJson) {                // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $select = $("#someselect");                         // Locate HTML DOM element with ID "someselect".
        $select.find("option").remove();                          // Find all child elements with tag name "option" and remove them (just to prevent duplicate options when button is pressed again).
        $.each(responseJson, function(key, value) {               // Iterate over the JSON object.
            $("<option>").val(key).text(value).appendTo($select); // Create HTML <option> element, set its value with currently iterated key and its text content with currently iterated item and finally append it to the <select>.
        });
    });
});

con

<select id="someselect"></select>

Volviendo List<Entity>como JSON

Aquí hay un ejemplo que se muestra List<Product>en un <table>donde la Productclase tiene las Long idpropiedades String namey BigDecimal price. El servlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Product> products = someProductService.list();
    String json = new Gson().toJson(products);

    response.setContentType("application/json");
    response.setCharacterEncoding("UTF-8");
    response.getWriter().write(json);
}

El código JS:

$(document).on("click", "#somebutton", function() {          // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
    $.get(yourServletURL, function(responseJson) {           // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response JSON...
        const $table = $("<table>").appendTo($("#somediv")); // Create HTML <table> element and append it to HTML DOM element with ID "somediv".
        $.each(responseJson, function(index, product) {      // Iterate over the JSON array.
            $("<tr>").appendTo($table)                       // Create HTML <tr> element, set its text content with currently iterated item and append it to the <table>.
                .append($("<td>").text(product.id))          // Create HTML <td> element, set its text content with id of currently iterated product and append it to the <tr>.
                .append($("<td>").text(product.name))        // Create HTML <td> element, set its text content with name of currently iterated product and append it to the <tr>.
                .append($("<td>").text(product.price));      // Create HTML <td> element, set its text content with price of currently iterated product and append it to the <tr>.
        });
    });
});

Volviendo List<Entity>como XML

Aquí hay un ejemplo que hace efectivamente lo mismo que el ejemplo anterior, pero con XML en lugar de JSON. Cuando utilice JSP como generador de salida XML, verá que es menos tedioso codificar la tabla y todo. De esta manera, JSTL es mucho más útil, ya que puede usarlo para iterar sobre los resultados y realizar el formateo de datos del lado del servidor. El servlet:

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Product> products = someProductService.list();

    request.setAttribute("products", products);
    request.getRequestDispatcher("/WEB-INF/xml/products.jsp").forward(request, response);
}

El código JSP (nota: si lo coloca <table>en un <jsp:include>, puede ser reutilizable en otro lugar de una respuesta que no sea Ajax):

<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="application/xml" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="jakarta.tags.core" %>
<%@taglib prefix="fmt" uri="jakarta.tags.fmt" %>
<data>
    <table>
        <c:forEach items="${products}" var="product">
            <tr>
                <td>${product.id}</td>
                <td><c:out value="${product.name}" /></td>
                <td><fmt:formatNumber value="${product.price}" type="currency" currencyCode="USD" /></td>
            </tr>
        </c:forEach>
    </table>
</data>

El código JavaScript:

$(document).on("click", "#somebutton", function() {             // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
    $.get(yourServletURL, function(responseXml) {               // Execute Ajax GET request on your servlet URL and execute the following function with Ajax response XML...
        $("#somediv").html($(responseXml).find("data").html()); // Parse XML, find <data> element and append its HTML to HTML DOM element with ID "somediv".
    });
});

Probablemente ya te habrás dado cuenta de por qué XML es mucho más potente que JSON para el propósito particular de actualizar un documento HTML usando Ajax. JSON es curioso, pero después de todo, generalmente sólo es útil para los llamados "servicios web públicos". Los marcos MVC como JSF usan XML en secreto para su magia ajax.

Ajaxificar una forma existente

Puede usar jQuery $.serialize()para ajaxificar fácilmente formularios POST existentes sin tener que perder el tiempo recopilando y pasando los parámetros de entrada del formulario individual. Suponiendo un formulario existente que funciona perfectamente sin JavaScript/jQuery (y por lo tanto se degrada elegantemente cuando el usuario final tiene JavaScript deshabilitado):

<form id="someform" action="${pageContext.request.contextPath}/yourServletURL" method="post">
    <input type="text" name="foo" />
    <input type="text" name="bar" />
    <input type="text" name="baz" />
    <input type="submit" name="submit" value="Submit" />
</form>

Puedes mejorarlo progresivamente con Ajax como se muestra a continuación:

$(document).on("submit", "#someform", function(event) {
    const $form = $(this);

    $.post($form.attr("action"), $form.serialize(), function(response) {
        // ...
    });

    event.preventDefault(); // Important! Prevents submitting the form.
});

En el servlet puede distinguir entre solicitudes normales y solicitudes Ajax como se muestra a continuación:

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    String foo = request.getParameter("foo");
    String bar = request.getParameter("bar");
    String baz = request.getParameter("baz");

    boolean ajax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With"));

    // ...

    if (ajax) {
        // Handle Ajax (JSON or XML) response.
    } else {
        // Handle regular (JSP) response.
    }
}

El complemento jQuery Form hace más o menos lo mismo que el ejemplo anterior de jQuery, pero tiene soporte transparente adicional para multipart/form-dataformularios según lo requiera la carga de archivos.

Envío manual de parámetros de solicitud al servlet

Si no tiene ningún formulario, pero solo desea interactuar con el servlet "en segundo plano" mediante el cual desea PUBLICAR algunos datos, puede usar jQuery $.param()para convertir fácilmente un objeto JSON a un objeto codificado en URL. cadena de consulta según el application/x-www-form-urlencodedtipo de contenido, exactamente como se usa en los formularios HTML normales, para que pueda continuar usándola request.getParameter(name)para extraer los datos.

const params = {
    foo: "fooValue",
    bar: "barValue",
    baz: "bazValue"
};

$.post(yourServletURL, $.param(params), function(response) {
    // ...
});

Es $.post()esencialmente una abreviatura de la siguiente $.ajax()llamada.

$.ajax({
    type: "POST",
    url: yourServletURL,
    data: $.param(params),
    success: function(response) {
        // ...
    }
});

doPost()Se puede reutilizar el mismo método que se muestra en la sección anterior. Tenga en cuenta que $.post()la sintaxis anterior también funciona $.get()en jQuery y doGet()en servlet.

Enviar manualmente un objeto JSON al servlet

Sin embargo, si por algún motivo tiene la intención de enviar el objeto JSON como un todo en lugar de como parámetros de solicitud individuales, entonces deberá serializarlo en una cadena usando JSON.stringify()(que no forma parte de jQuery) e indicarle a jQuery que establezca el tipo de contenido de la solicitud application/jsonen su lugar. de (predeterminado) application/x-www-form-urlencoded. Esto no se puede hacer a través de $.post()la función de conveniencia, pero debe hacerse $.ajax()como se muestra a continuación.

const data = {
    foo: "fooValue",
    bar: "barValue",
    baz: "bazValue"
};

$.ajax({
    type: "POST",
    url: yourServletURL,
    contentType: "application/json", // NOT dataType!
    data: JSON.stringify(data),
    success: function(response) {
        // ...
    }
});

Tenga en cuenta que muchos entrantes se mezclan contentTypecon dataType. Representa el contentTypetipo de cuerpo de la solicitud . Representa dataTypeel tipo (esperado) de cuerpo de respuesta , que generalmente es innecesario ya que jQuery ya lo detecta automáticamente según el Content-Typeencabezado de la respuesta.

Luego, para procesar el objeto JSON en el servlet que no se envía como parámetros de solicitud individuales sino como una cadena JSON completa de la manera anterior, solo necesita analizar manualmente el cuerpo de la solicitud usando una herramienta JSON en lugar de usar getParameter()la herramienta habitual. forma. Es decir, los servlets no admiten application/jsonsolicitudes formateadas, sino solo application/x-www-form-urlencodedsolicitudes multipart/form-dataformateadas. Gson también admite el análisis de una cadena JSON en un objeto JSON.

JsonObject data = new Gson().fromJson(request.getReader(), JsonObject.class);
String foo = data.get("foo").getAsString();
String bar = data.get("bar").getAsString();
String baz = data.get("baz").getAsString();
// ...

Tenga en cuenta que todo esto es más complicado que simplemente usar $.param(). Normalmente, solo desea utilizarlo JSON.stringify()si el servicio de destino es, por ejemplo, un servicio JAX-RS (RESTful) que, por alguna razón, solo es capaz de consumir cadenas JSON y no parámetros de solicitud regulares.

Enviar una redirección desde servlet

Es importante darse cuenta y comprender que cualquier sendRedirect()llamada forward()del servlet en una solicitud ajax solo reenviará o redirigirá la solicitud Ajax en sí y no el documento/ventana principal donde se originó la solicitud Ajax. En tal caso, JavaScript/jQuery solo recuperaría la respuesta redirigida/reenviada como responseTextvariable en la función de devolución de llamada. Si representa una página HTML completa y no una respuesta XML o JSON específica de Ajax, entonces todo lo que puede hacer es reemplazar el documento actual con ella.

document.open();
document.write(responseText);
document.close();

Tenga en cuenta que esto no cambia la URL que ve el usuario final en la barra de direcciones del navegador. Entonces hay problemas con la capacidad de marcar. Por lo tanto, es mucho mejor simplemente devolver una "instrucción" para que JavaScript/jQuery realice una redirección en lugar de devolver todo el contenido de la página redirigida. Por ejemplo, devolviendo un valor booleano o una URL.

String redirectURL = "http://example.com";

Map<String, String> data = new HashMap<>();
data.put("redirect", redirectURL);
String json = new Gson().toJson(data);

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
function(responseJson) {
    if (responseJson.redirect) {
        window.location = responseJson.redirect;
        return;
    }

    // ...
}

Ver también:

  • Llame a Servlet e invoque el código Java desde JavaScript junto con los parámetros
  • Acceda a variables Java/Servlet/JSP/JSTL/EL en JavaScript
  • ¿Cómo puedo cambiar fácilmente entre un sitio web basado en Ajax y un sitio web HTML básico?
  • ¿Cómo puedo cargar archivos a un servidor usando JSP/Servlet y Ajax?
BalusC avatar Nov 06 '2010 13:11 BalusC

La forma correcta de actualizar la página que se muestra actualmente en el navegador del usuario (sin recargarla) es ejecutar algún código en el navegador que actualice el DOM de la página.

Ese código suele ser JavaScript que está incrustado o vinculado desde la página HTML, de ahí la sugerencia de Ajax. (De hecho, si asumimos que el texto actualizado proviene del servidor a través de una solicitud HTTP, esto es Ajax clásico).

También es posible implementar este tipo de cosas utilizando algún complemento o complemento del navegador, aunque puede resultar complicado para un complemento acceder a las estructuras de datos del navegador para actualizar el DOM. (Los complementos de código nativo normalmente escriben en algún marco gráfico que está incrustado en la página).

Stephen C avatar Nov 06 '2010 10:11 Stephen C

Les mostraré un ejemplo completo de un servlet y cómo realizar una llamada Ajax.

Aquí, vamos a crear un ejemplo simple para crear el formulario de inicio de sesión usando un servlet.

Archivo index.html

<form>
   Name:<input type="text" name="username"/><br/><br/>
   Password:<input type="password" name="userpass"/><br/><br/>
   <input type="button" value="login"/>
</form>

Una muestra de Ajax

$.ajax
({
    type: "POST",
    data: 'LoginServlet=' + name + '&name=' + type + '&pass=' + password,
    url: url,
    success:function(content)
    {
        $('#center').html(content);
    }
});

Código de servlet LoginServlet:

package abc.servlet;

import java.io.File;

public class AuthenticationServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException
    {
        doPost(request, response);
    }

    protected void doPost(HttpServletRequest request,
                          HttpServletResponse response)
                          throws ServletException, IOException {

        try{
            HttpSession session = request.getSession();
            String username = request.getParameter("name");
            String password = request.getParameter("pass");

            /// Your Code
            out.println("sucess / failer")
        }
        catch (Exception ex) {
            // System.err.println("Initial SessionFactory creation failed.");
            ex.printStackTrace();
            System.exit(0);
        }
    }
}
Mitul Maheshwari avatar Feb 05 '2014 11:02 Mitul Maheshwari
$.ajax({
    type: "POST",
    url: "URL to hit on servelet",
    data: JSON.stringify(json),
    dataType: "json",
    success: function(response){
        // We have the response
        if(response.status == "SUCCESS"){
            $('#info').html("Info  has been added to the list successfully.<br>" +
            "The details are as follws: <br> Name: ");
        }
        else{
            $('#info').html("Sorry, there is some thing wrong with the data provided.");
        }
    },
    error: function(e){
        alert('Error: ' + e);
    }
});
SUBZ avatar Mar 20 '2014 05:03 SUBZ

Ajax (también AJAX), acrónimo de JavaScript asincrónico y XML, es un grupo de técnicas de desarrollo web interrelacionadas que se utilizan en el lado del cliente para crear aplicaciones web asincrónicas. Con Ajax, las aplicaciones web pueden enviar y recuperar datos de un servidor de forma asincrónica.

A continuación se muestra el código de ejemplo:

Una función JavaScript de página JSP para enviar datos a un servlet con dos variables, nombre y apellido:

function onChangeSubmitCallWebServiceAJAX()
{
    createXmlHttpRequest();
    var firstName = document.getElementById("firstName").value;
    var lastName = document.getElementById("lastName").value;
    xmlHttp.open("GET", "/AJAXServletCallSample/AjaxServlet?firstName="
    + firstName + "&lastName=" + lastName, true)
    xmlHttp.onreadystatechange = handleStateChange;
    xmlHttp.send(null);
}

Servlet para leer los datos enviados a JSP en formato XML (también puede usar texto. Solo necesita cambiar el contenido de la respuesta a texto y representar los datos en la función JavaScript).

/**
 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
 */
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String firstName = request.getParameter("firstName");
    String lastName = request.getParameter("lastName");

    response.setContentType("text/xml");
    response.setHeader("Cache-Control", "no-cache");
    response.getWriter().write("<details>");
    response.getWriter().write("<firstName>" + firstName + "</firstName>");
    response.getWriter().write("<lastName>" + lastName + "</lastName>");
    response.getWriter().write("</details>");
}
user3468976 avatar Apr 02 '2014 23:04 user3468976