Como usar Servlets e Ajax?

334

Sou muito novo em aplicativos da Web e Servlets e tenho a seguinte pergunta:

Sempre que imprimo algo dentro do servlet e o chamo pelo navegador da web, ele retorna uma nova página contendo esse texto. Existe uma maneira de imprimir o texto na página atual usando o Ajax?

Amir Rachum
fonte

Respostas:

560

De fato, a palavra-chave é "ajax": JavaScript assíncrono e XML . No entanto, nos últimos anos, é mais do que frequentemente JavaScript assíncrono e JSON . Basicamente, você permite que o JS execute uma solicitação HTTP assíncrona e atualize a árvore DOM HTML com base nos dados da resposta.

Como é um trabalho tedioso fazê-lo funcionar em todos os navegadores (especialmente no Internet Explorer e em outros), existem muitas bibliotecas JavaScript que simplificam isso em funções únicas e abrangem o máximo possível de bugs / peculiaridades específicos do navegador, ocultos , como jQuery , Prototype , Mootools . Como o jQuery é o mais popular atualmente, usarei nos exemplos abaixo.

Exemplo de kickoff retornando Stringcomo texto simples

Crie /some.jspcomo abaixo (nota: o código não espera que o arquivo JSP seja colocado em uma subpasta, se você o fizer, altere o URL do servlet de acordo):

<!DOCTYPE html>
<html lang="en">
    <head>
        <title>SO question 4112686</title>
        <script src="http://code.jquery.com/jquery-latest.min.js"></script>
        <script>
            $(document).on("click", "#somebutton", function() { // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
                $.get("someservlet", function(responseText) {   // Execute Ajax GET request on URL of "someservlet" 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>

Crie um servlet com um doGet()método parecido com este:

@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.
}

Mapeie este servlet em um padrão de URL igual /someservletou /someservlet/*abaixo (obviamente, o padrão de URL é livre para sua escolha, mas você precisará alterar o someservletURL nos exemplos de código JS em todos os lugares adequadamente):

@WebServlet("/someservlet/*")
public class SomeServlet extends HttpServlet {
    // ...
}

Ou, quando você ainda não estiver em um contêiner compatível com Servlet 3.0 (Tomcat 7, Glassfish 3, JBoss AS 6, etc ou mais recente), mapeie- web.xmlo da maneira antiga (consulte também a página wiki de Servlets ):

<servlet>
    <servlet-name>someservlet</servlet-name>
    <servlet-class>com.example.SomeServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>someservlet</servlet-name>
    <url-pattern>/someservlet/*</url-pattern>
</servlet-mapping>

Agora abra o http: // localhost: 8080 / context / test.jsp no navegador e pressione o botão Você verá que o conteúdo da div é atualizado com a resposta do servlet.

Retornando List<String>como JSON

Com o JSON, em vez de texto sem formatação, como formato de resposta, você pode ainda dar mais alguns passos. Permite mais dinâmica. Primeiro, você gostaria de ter uma ferramenta para converter entre objetos Java e sequências JSON. Também existem muitos deles (consulte a parte inferior desta página para uma visão geral). Meu favorito pessoal é o Google Gson . Faça o download e coloque o arquivo JAR na /WEB-INF/libpasta do seu aplicativo da web.

Aqui está um exemplo que é exibido List<String>como <ul><li>. O 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);
}

O 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("someservlet", function(responseJson) {    // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
        var $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>.
        });
    });
});

Observe que o jQuery analisa automaticamente a resposta como JSON e fornece diretamente um objeto JSON ( responseJson) como argumento de função quando você define o tipo de conteúdo da resposta como application/json. Se você esquecer de configurá-lo ou confiar em um padrão de text/plainor text/html, o responseJsonargumento não fornecerá um objeto JSON, mas uma sequência simples de baunilha e você precisará mexer manualmente comJSON.parse() posteriormente, o que é totalmente desnecessário se você defina o tipo de conteúdo em primeiro lugar.

Retornando Map<String, String>como JSON

Aqui está outro exemplo que é exibido 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);
}

E o JSP:

$(document).on("click", "#somebutton", function() {               // When HTML DOM "click" event is invoked on element with ID "somebutton", execute the following function...
    $.get("someservlet", function(responseJson) {                 // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
        var $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>.
        });
    });
});

com

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

Retornando List<Entity>como JSON

Aqui está um exemplo que exibe List<Product>em um <table>onde a Productclasse tem as propriedades Long id, String namee BigDecimal price. O 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);
}

O 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("someservlet", function(responseJson) {          // Execute Ajax GET request on URL of "someservlet" and execute the following function with Ajax response JSON...
        var $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>.
        });
    });
});

Retornando List<Entity> como XML

Aqui está um exemplo que efetivamente é igual ao exemplo anterior, mas depois com XML em vez de JSON. Ao usar JSP como gerador de saída XML, você verá que é menos tedioso codificar a tabela e tudo. O JSTL é muito mais útil, pois você pode usá-lo para iterar sobre os resultados e executar a formatação de dados do lado do servidor. O 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);
}

O código JSP (nota: se você inserir o <table>em a <jsp:include>, pode ser reutilizável em outro lugar em uma resposta não-ajax):

<?xml version="1.0" encoding="UTF-8"?>
<%@page contentType="application/xml" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/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>

O 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("someservlet", function(responseXml) {                // Execute Ajax GET request on URL of "someservlet" 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".
    });
});

Você provavelmente já perceberá por que o XML é muito mais poderoso que o JSON com o objetivo específico de atualizar um documento HTML usando o Ajax. O JSON é engraçado, mas, afinal, geralmente só é útil para os chamados "serviços públicos da web". Estruturas MVC como JSF usam XML nos bastidores para sua mágica no ajax.

Ajaxificando um formulário existente

Você pode usar o jQuery $.serialize()para facilitar ajaxificar os formulários POST existentes sem se preocupar em coletar e passar os parâmetros de entrada de formulários individuais. Supondo que um formulário existente funcione perfeitamente sem JavaScript / jQuery (e, portanto, seja degradado normalmente quando o usuário final estiver com o JavaScript desativado):

<form id="someform" action="someservlet" 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>

Você pode aprimorá-lo progressivamente com ajax, como abaixo:

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

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

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

É possível distinguir no servlet entre solicitações normais e solicitações de ajax, conforme abaixo:

@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.
    }
}

O plugin jQuery Form faz menos ou mais o mesmo exemplo acima do jQuery, mas possui suporte transparente adicional paramultipart/form-data formulários, conforme exigido pelos uploads de arquivos.

Envio manual de parâmetros de solicitação ao servlet

Se você não possui um formulário, mas apenas deseja interagir com o servlet "em segundo plano" no qual deseja postar alguns dados, pode usar o jQuery $.param()para converter facilmente um objeto JSON em um codificado em URL string de consulta.

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

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

O mesmo doPost()método mostrado aqui acima pode ser reutilizado. Observe que a sintaxe acima também funciona $.get()no jQuery e doGet()no servlet.

Enviando Objeto JSON Manualmente para Servlet

Se você no entanto a intenção de enviar o objeto JSON como um todo em vez de como parâmetros de solicitação individuais, por algum motivo, então você precisa para serializar-lo para uma string usando JSON.stringify()(não faz parte da jQuery) e instruir jQuery ao pedido conjunto de tipo de conteúdo a application/jsonvez de (padrão) application/x-www-form-urlencoded. Isso não pode ser feito através da $.post()função de conveniência, mas precisa ser feito $.ajax()conforme abaixo.

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

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

Note que um monte de entradas misturar contentTypecom dataType. O contentTyperepresenta o tipo do corpo da solicitação . O dataTyperepresenta o tipo (esperado) do corpo da resposta , o que geralmente é desnecessário, já que o jQuery já o detecta automaticamente com base no Content-Typecabeçalho da resposta .

Em seguida, para processar o objeto JSON no servlet que não está sendo enviado como parâmetros de solicitação individuais, mas como uma string JSON inteira da maneira acima, você só precisa analisar manualmente o corpo da solicitação usando uma ferramenta JSON em vez de usar getParameter()o usual caminho. Ou seja, servlets não suportam application/jsonsolicitações formatadas, mas apenas application/x-www-form-urlencodedou multipart/form-datasolicitações formatadas. O Gson também suporta a análise de uma string JSON em um 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();
// ...

Observe que tudo isso é mais desajeitado do que apenas usar $.param(). Normalmente, você deseja usar JSON.stringify()apenas se o serviço de destino for, por exemplo, um serviço JAX-RS (RESTful) que, por algum motivo, possa apenas consumir cadeias JSON e não parâmetros de solicitação regulares.

Enviando um redirecionamento do servlet

É importante perceber e entender que qualquer chamada sendRedirect()e forward()pelo servlet em uma solicitação ajax encaminharia ou redirecionaria apenas a solicitação ajax em si e não o documento / janela principal em que a solicitação ajax se originou. Nesse caso, o JavaScript / jQuery recuperaria apenas a resposta redirecionada / encaminhada como responseTextvariável na função de retorno de chamada. Se ele representa uma página HTML inteira e não uma resposta XML ou JSON específica do ajax, tudo o que você pode fazer é substituir o documento atual por ele.

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

Observe que isso não altera o URL como o usuário vê na barra de endereços do navegador. Portanto, há problemas com a capacidade de marcação. Portanto, é muito melhor retornar uma "instrução" para JavaScript / jQuery para executar um redirecionamento em vez de retornar todo o conteúdo da página redirecionada. Por exemplo, retornando um booleano ou uma 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;
    }

    // ...
}

Veja também:

BalusC
fonte
precisa analisar o json no último exemplo.
Shinzou 12/10/16
4
@kuhaku: não. Se você ler as postagens de cima para baixo, aprenderá o porquê.
BalusC
11
Essa resposta tem sido minha tábua de salvação há mais ou menos um mês, lol. Aprendendo muito com isso. Eu amo o exemplo XML. Obrigado por montar isso! Uma pergunta noob embora se você tiver tempo. Existe um motivo para colocar a pasta xml no WEB-INF?
Jonathan Laliberte
11
@ JonathanLaliberte: Portanto, os usuários não podem baixá-los.
BalusC
@BalusC, seu exemplo XML é ótimo, obrigado. Mas estou recebendo "Não é possível obter a propriedade 'substituir' de referência indefinida ou nula" para $("#somediv").html($(responseXml).find("data").html())esta linha. Ele também diz "Número incorreto de argumentos ou atribuição de propriedade inválida". Também posso ver que meu XML é preenchido com dados quando eu depuro. Alguma ideia ?
629
14

A maneira correta de atualizar a página atualmente exibida no navegador do usuário (sem recarregá-la) é fazer com que algum código em execução no navegador atualize o DOM da página.

Esse código geralmente é javascript incorporado ou vinculado da página HTML, daí a sugestão do AJAX. (De fato, se assumirmos que o texto atualizado vem do servidor por meio de uma solicitação HTTP, esse é o AJAX clássico.)

Também é possível implementar esse tipo de coisa usando algum plug-in ou complemento do navegador, embora possa ser complicado para um plug-in acessar as estruturas de dados do navegador para atualizar o DOM. (Os plug-ins de código nativo normalmente gravam em algum quadro gráfico incorporado na página.)

Stephen C
fonte
13

Vou mostrar um exemplo inteiro de servlet e como o ajax chama.

Aqui, vamos criar o exemplo simples para criar o formulário de login usando o servlet.

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>  

Aqui está uma amostra do ajax

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

Código do 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
fonte
8
$.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
fonte
7

Ajax (também AJAX), sigla para JavaScript assíncrono e XML) é um grupo de técnicas de desenvolvimento da Web inter-relacionadas, usadas no lado do cliente para criar aplicativos da Web assíncronos. Com o Ajax, os aplicativos da Web podem enviar e recuperar dados de um servidor de forma assíncrona. Abaixo está um código de exemplo:

Função de script java da página Jsp para enviar dados ao servlet com duas variáveis ​​firstName e lastName:

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 ler dados enviados de volta para jsp no formato xml (você também pode usar texto. Você só precisa alterar o conteúdo da resposta para texto e renderizar dados na função 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
fonte
5

Normalmente você não pode atualizar uma página de um servlet. O cliente (navegador) precisa solicitar uma atualização. O cliente Eiter carrega uma página totalmente nova ou solicita uma atualização para uma parte de uma página existente. Essa técnica é chamada Ajax.

Peter Knego
fonte
4

Usando a seleção múltipla de autoinicialização

Ajax

function() { $.ajax({
    type : "get",
    url : "OperatorController",
    data : "input=" + $('#province').val(),
    success : function(msg) {
    var arrayOfObjects = eval(msg); 
    $("#operators").multiselect('dataprovider',
    arrayOfObjects);
    // $('#output').append(obj);
    },
    dataType : 'text'
    });}
}

No servlet

request.getParameter("input")
Thakhani Tharage
fonte