jQuery Ajax – Servlets集成:构建完整的应用程序

网上有很多教程,它们解释了有关使用servlet和JSP页面进行Java Web开发的一些知识,但是,我从来没有找到对于初学者来说足够简洁,简单的教程。 这样的教程应该解释创建一个简单的Web应用程序的整个过程,包括前端,后端,最重要的是,人们可以用来与它们两者交互的方式 。 仅仅展示如何从服务器获取信息还不够,了解如何以结构化方式区分信息以及知道如何通过应用程序环境对后端进行更改也很重要。

我们在本文中希望实现的是指导创建完整的“玩具” Web应用程序的整个过程。 从某种意义上说,它是一个“玩具”应用程序,它只做两件事,并且我们没有使用任何额外的功能来使环境变得漂亮。 该应用程序的目的很简单:

  • 添加一个带有专辑列表的乐队名称(用逗号分隔),然后按“提交”按钮将其添加到数据库中。
  • 按“显示乐队!” 按钮以获取乐队列表,或“显示乐队和专辑!” 按钮以获取带有其专辑的乐队列表。

该应用程序的外观是裸机越好 ,但其背后的代码是你需要开始创建自己的动态Web应用程序,这是最通常称为CRUD应用程序的一切(C reate,R EAD,U PDATE,d elete )。 之所以这样称呼它们是因为它们的所有功能都可以抽象为这些非常基本的命令。

在逐步创建应用程序之前,让我们看一下本示例中将要使用的所有工具:

  • 蚀月神
  • Java 7
  • Tomcat 7(Web应用程序服务器)
  • Gson 2.3(Google Java库)
  • jQuery 2.1.1(JavaScript库)

1.前端(JSP页面)

这里没有太多要说的。 如果遵循其他示例,您将知道如何在Eclipse中轻松创建Dynamic Web Project ,以及如何在文件夹WebContent内创建index.jsp页面。 这将是我们应用程序的主页,并且我们将不会使用任何其他页面。 当然,它总是取决于您需要创建的应用程序的类型,但是对于我们的需求而言,一页就足够了。

index.jsp

<%@ page language="java"
    contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>
	<head>
	    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
	    <title>Ajax - Servlets Integration Example</title>
	    
	    <!-- Load the scripts needed for the application. -->
	    <script type="text/javascript" src="resources/jquery-2.1.1.min.js"></script>
	    <script type="text/javascript" src="resources/buttonEventsInit.js"></script>
	    <script type="text/javascript" src="resources/resultsPrinter.js"></script>
	    <script type="text/javascript" src="resources/insertBandInfo.js"></script>
	</head>
	
	<body>
	    <h1>Ajax - Servlets Integration Example</h1>
	    <p>This is an example of how to use Ajax with a servlet backend.</p></br>
	    
	    <h3>Select a button to get the relevant information.</h3>
	    
	    <!-- Buttons that will call the servlet to retrieve the information. -->
	    <button id="bands" type="button">Show bands!</button>
	    <button id="bands-albums" type="button">Show bands and albums!</button>
	    
	    <!-- We need to have some empty divs in order to add the retrieved information to them. -->
	    <div id="band-results"></div></br></br>
	    <div id="bands-albums-results"></div></br></br>
	    
	    
	    <h3>Add the band information and press submit!</h3>
	    <h4>Band name: </h4><input type="text" id="band-name-input" value=""><br>
        <h4>Albums: </h4><input type="text" id="album-input" value="">(Separated by commas)<br>
        <input type="submit" id="submit-band-info" value="Submit">
	</body>
</html>

因此,您可以看到非常简单的东西。 我们加载所需的javascript文件,其中只有一个是外部JQuery 。 JQuery是一个众所周知的Javascript库,它功能强大 。 它使我们能够轻松获取有关页面各个元素的信息,以及将事件绑定到这些元素。 在此处获取以下代码段作为一个简单示例:

$("#my-button").click(function() {
    alert("My button was clicked!");
});

此代码段的意思是:“ 单击ID为“ my-button”的元素时,我要触发一个函数,该函数会创建一个警告弹出窗口,提示“我的按钮已被单击!”。 ”。 因此,我们将执行某些操作的整个函数作为事件绑定的参数传递 。 稍后我们将解释有关JQuery的更多信息。 您可以在此处下载JQuery 。

这里有些事情要考虑:

  • 我们已为将要使用的所有重要元素指定了ID。 因此, 按钮 , 输入框和空的<div>元素都有唯一的ID。
  • 我们创建了2个包含结果的空<div>元素。 如果您需要一个容器来存放东西并且需要将该容器始终放置在特定位置,通常会遵循此设计模式。 这样,我们就无需检查信息的放置位置,因为页面中为此保留了一个位置。 同样,第二个div(带有专辑的乐队)将始终位于第一个div(仅乐队名称)之下。 当我们按下仅乐队信息的按钮时,它将被添加到带有专辑的乐队顶部。

2.向服务器询问数据(前端和后端)

2.1从前端使用Ajax发出GET请求。

因此,我们需要做的第一件事是找到一种方法来询问服务器所需的数据,在这种情况下为乐队名称或乐队和专辑。 我们已经在各自的按钮上添加了两个ID( “乐队”和“乐队和专辑” ),因此我们需要将事件绑定到它们,以便每次按下按钮时都可以调用服务器 。 为此,我们将使用一些Javascript,包含在buttonEventsInit.js文件中。

注意:每个Javascipt文件都保存在目录WebContent / resources下,以便授予访问浏览器的权限。

buttonEventsInit.js

// When the page is fully loaded...
$(document).ready(function() {
	
	// Add an event that triggers when ANY button
	// on the page is clicked...
    $("button").click(function(event) {
    	
    	// Get the button id, as we will pass it to the servlet
    	// using a GET request and it will be used to get different
    	// results (bands OR bands and albums).
    	var buttonID = event.target.id;
    	
    	// Basic JQuery Ajax GET request. We need to pass 3 arguments:
    	// 		1. The servlet url that we will make the request to.
    	//		2. The GET data (in our case just the button ID).
    	//		3. A function that will be triggered as soon as the request is successful.
    	// Optionally, you can also chain a method that will handle the possibility
    	// of a failed request.
    	$.get('DBRetrievalServlet', {"button-id": buttonID},
            function(resp) { // on sucess
    			// We need 2 methods here due to the different ways of 
    			// handling a JSON object.
    			if (buttonID === "bands")
    				printBands(resp);
    			else if (buttonID === "bands-albums")
    				printBandsAndAlbums(resp); 
            })
            .fail(function() { // on failure
                alert("Request failed.");
            });
    });  
});

让我们解释一下这里发生的情况。 页面加载后 (我们这样做是为了确保所有元素都就位),我们将click事件绑定到页面中的每个按钮元素。 从现在开始, 每单击一个按钮 ,GET请求就会发送到服务器,其中包含按下了哪个按钮的信息。 服务器将发送回正确的响应(以JSON对象的形式,稍后我们将对此进行说明),并且我们将根据所按下的按钮对该对象执行不同的操作(因为每个按钮将接收结构不同的 JSON)宾语)。

查看上面示例中有关向服务器发出GET请求的正确方法的注释。 您将需要提供URL(也可以是servlet的URL),数据和将被触发的功能,并将服务器的响应(JSON对象)作为参数 。

2.2处理请求并将数据发送回客户端。

那么,当我们发出请求时,服务器会发生什么? 我们在这里使用了许多类,因此让我们再次记住,我们正在构建一个包含两种目录的应用程序:乐队和带有专辑的乐队。 因此,我们正在使用:

  • MusicDatabase.java:使用Singleton模式以提供一个持久对象的类,该对象将包含需要发送回客户端的信息。
  • DBRetrievalServlet.java:将用于处理GET请求和使用其他类的servlet, 提供带有查询信息的响应 。
  • BandWithAlbums.java:一个用于创建新的“数据保存对象”的类 ,在我们的例子中,该类包含乐队名称和专辑列表。

因此,让我们检查这些类中的每一个并解释它们的用法。

DBRetrievalServlet.java

package servlets;
import informationClasses.MusicDatabase;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/DBRetrievalServlet")
public class DBRetrievalServlet extends HttpServlet {
    
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
         
        // We set a specific return type and encoding
        // in order to take advantage of the browser capabilities.
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");

        
        // Depending on the GET parameters, passed from the Ajax call,
        // we are able to differentiate the requests and call the appropriate
        // method. We can always use more classes for more use-cases.
        
        // The response object returns the information (as a JSON object in String form)
        // to the browser.
        String buttonID = request.getParameter("button-id");
        switch (buttonID) {
            case "bands":
                response.getWriter().write(MusicDatabase
                        .getInstance()
                        .getBands());
                break;
                
            case "bands-albums":
                response.getWriter().write(MusicDatabase
                        .getInstance()
                        .getBandsAndAlbums());
                break;
        }
    }
}

我们得到参数“ button-id” ,该参数包含在从客户端发送的信息中(在请求对象中),并且根据我们按下的按钮的类型,我们需要通过调用MusicDatabase实例来获得不同类型的信息。并每次调用不同的方法。

注意:单例模式

关于MusicDatabase实例…我们使用的是Singleton模式 ,这意味着因为我们只希望有1个该类的实例,所以我们不会通过自己调用new关键字来创建新实例。 相反,我们从MusicDatabase类本身调用一个方法,并要求一个实例。

  1. 如果尚未创建该实例,我们将创建一个实例并将其返回。
  2. 如果已创建,则返回现有实例。

无法从外部访问构造函数 ,也无法意外创建另一个实例。 您可以在线找到有关Singleton模式的更多信息。

MusicDatabase.java

package informationClasses;

import java.util.ArrayList;
import java.util.List;

import jsonObjects.BandWithAlbums;

import com.google.gson.Gson;

public class MusicDatabase {
    
    private List bandNames;
    private List bandsAndAlbums;
    
    
    // Singleton methods
    private static MusicDatabase dbInstance = null;
    
    protected MusicDatabase() {
        bandNames = new ArrayList<>();
        bandsAndAlbums = new ArrayList<>();
    }
    
    public static MusicDatabase getInstance() {
       if(dbInstance == null) {
          dbInstance = new MusicDatabase();
       }
       
       return dbInstance;
    }
    
    
    public void setBandAndAlbums(String bandName, ArrayList bandAlbums) {
        bandNames.add(bandName);
        bandsAndAlbums.add(new BandWithAlbums(bandName, bandAlbums));
    }
    
    public String getBands() {
        return new Gson().toJson(bandNames);
    }
    
    public String getBandsAndAlbums() {
        return new Gson().toJson(bandsAndAlbums);
    }
}

我们将在这里检查的方法是getBands()和getBandsAndAlbums() 。 我们只需要这两种方法,它们就非常简单,因为这里有一些可以帮助我们的事情:

  • Gson是Google的Java库,它使我们能够从Java对象轻松创建JSON对象。 该对象可以是任何东西,从简单的数据结构到包含信息的对象,其他数据结构等。在我们的例子中,我们有2个这样的数据结构:
    • A List<String> bandNames ,仅包含A List<String> bandNames形式的乐队名称。
    • A List<BandWithAlbums> ,其中包含对象,对象又包含乐队名称和其专辑列表。
  • BandWithAlbumsç±» ,它使我们能够保存有关乐队的更多信息。 它是一个数据保存类,其中包含乐队名称作为String和其乐队List<String>作为List<String> 。 通过返回此对象,您还将返回所有关联的信息。

总而言之,使用命令new Gson().toJson(Object obj)的Gson库可以将大多数对象和数据结构转换为JSON格式,浏览器可以通过Javascript轻松使用。

注意:您需要将Gson库添加到类路径中才能起作用。

BandWithAlbums.java

package jsonObjects;

import java.util.ArrayList;

public class BandWithAlbums {

    String bandName;
    ArrayList bandAlbums;
    
    public BandWithAlbums(String bandName, ArrayList bandAlbums) {
        this.bandName = bandName;
        this.bandAlbums = bandAlbums;
    }
}

正如我们之前已经说过的,这是一个简单的数据保存类。 从某种意义上说,它代表“乐队”,其中包含乐队的名称和专辑。

2.3将数据呈现给浏览器。

因此,一旦有了所需的数据,就可以在buttonEventsInit.js文件中看到,我们可以选择调用两种不同的方法,具体取决于进行调用的按钮的ID。 我们将展示这两种方法在做什么,以及如何将数据展示给浏览器 。

resultsPrinter.js

// Both those functions get a json object as an argument,
// which itself also holds other objects.

// 1. The first function is supposed to get an object 
// 	containing just a list of band names.
// 2. The second function is supposed to get an object containing
// 	bands with albums, which essentially means a list of objects
// 	which hold (1) a band name and (2) a list of albums.

function printBands(json) {
	
	// First empty the <div> completely and add a title.
	$("#band-results").empty()
		.append("<h3>Band Names</h3>");
		
	// Then add every band name contained in the list.	
	$.each(json, function(i, name) {
		$("#band-results").append(i + 1, ". " + name + " </br>");
	});
};

function printBandsAndAlbums(json) {
	
	// First empty the <div> completely and add a title.
	$("#bands-albums-results").empty()
		.append("<h3>Band Names and Albums</h3>");
	
	// Get each band object...
	$.each(json, function(i, bandObject) {
		
		// Add to the <div> every band name...
		$("#bands-albums-results").append(i + 1, ". " + bandObject.bandName + " </br>");
		// And then for every band add a list of their albums.
		$.each(bandObject.bandAlbums, function(i, album) {
			$("#bands-albums-results").append("--" + album + "</br>");
		});
	});
};

为了了解这些功能如何工作,我们必须看一下服务器返回给客户端的响应对象。 在第一种情况下,我们期望仅列出乐队名称,因此期望的对象将只是列表:

["The Beatles", "Metallica"]

另一方面,在第二种情况下,我们希望接收全波段信息,在这种情况下,json对象将如下所示:

[
    {
        bandName: "The Beatles",
        bandAlbums: ["White Album", "Let it be"]
    },
    {
        bandName: "Metallica",
        bandAlbums: ["St Anger", "The Black Album"]
    }
]

因此,我们需要两种不同的方式处理请求。 但是,在每种情况下,我们将要使用的div empty() ,并使用一些非常方便的JQuery函数添加从服务器获取的信息。

这样,我们的应用程序的第一部分就完成了。 查看屏幕快照以查看结果。

jQuery Ajax – Servlets集成:构建完整的应用程序

结果显示在浏览器中。

3.从用户输入(前端和后端)更新服务器

3.1使用Ajax发出POST请求。

在这一部分中,我们将研究如何将数据发送到服务器 。 在本教程的上半部分,我们已经通过处理GET请求了解了工作原理,并且这里的步骤并没有什么不同,唯一的例外是允许用户为应用程序提供输入 。 让我们看一下我们正在使用的代码以及每个文件的功能。

insertBandInfo.js

$(document).ready(function() {
	
	// Add an event that triggers when the submit
	// button is pressed.
    $("#submit-band-info").click(function() {
    	
    	// Get the text from the two inputs.
    	var bandName = $("#band-name-input").val();
    	var albumName = $("#album-input").val();
    	
    	// Fail if one of the two inputs is empty, as we need
    	// both a band name and albums to make an insertion.
    	if (bandName === "" || albumName === "") {
    		alert("Not enough information for an insertion!");
    		return;
    	}
    	
    	// Ajax POST request, similar to the GET request.
    	$.post('DBInsertionServlet',{"bandName": bandName, "albumName": albumName},
            function() { // on success
                alert("Insertion successful!");
            })
            .fail(function() { //on failure
                alert("Insertion failed.");
            });
    });  
});

如果您遵循了教程的上一部分,那么很容易理解我们在这里所做的事情。 另一个单击事件,现在仅针对“ 提交”按钮的特定ID,在检查两个输入框是否确实有输入之后,该事件会发出POST请求(向为此目的专门使用的新Servlet)发送数据我们想要的(乐队名称和专辑列表)。

3.2将用户输入保存在我们的“数据库”中。

DBInsertionServlet.java

package servlets;

import informationClasses.MusicDatabase;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet("/DBInsertionServlet")
public class DBInsertionServlet extends HttpServlet {

    @Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        
        Map<String, String[]> bandInfo = request.getParameterMap();
        
        // In this case here we are not using the data sent to just do different things.
        // Instead we are using them as information to make changes to the server,
        // in this case, adding more bands and albums.
        String bandName = Arrays.asList(bandInfo.get("bandName")).get(0);
        String albums = Arrays.asList(bandInfo.get("albumName")).get(0);

        MusicDatabase.getInstance()
            .setBandAndAlbums(bandName, getAlbumNamesFromString(albums)); 
        
        // return success
        response.setStatus(200); 
    }

    // Split the album String in order to get a list of albums.
    private ArrayList getAlbumNamesFromString(String albums) {
        return new ArrayList(Arrays.asList(albums.split(",")));
    }
}

当Servlet收到请求时,它将从请求映射中提取bandName,并包含包含唱片集名称的String 。 当找到逗号时,我们通过将String分成多个部分来创建专辑列表。 最后,我们调用MusicDatabase实例,在该实例中添加乐队名称和专辑列表,如果您从以前检查一下类定义,则可以看到:

  • 我们将乐队名称添加到bandNames列表中。
  • 我们创建一个新的Band对象(使用名称和专辑列表),并将其添加到bandsWithalbums列表中。

之后,该servlet完成,并将成功状态响应发送回客户端。 我们已将所有内容添加到列表中,并且可以随时按JSON格式发送。 举例来说,让我们看看如果我自己添加一个新乐队会发生什么。

jQuery Ajax – Servlets集成:构建完整的应用程序

添加新乐队。

jQuery Ajax – Servlets集成:构建完整的应用程序

这个新乐队已经在我的“数据库”中,并要求再次查看该信息后,它就在那里!

4.下载项目

这是Ajax – Servlets集成的示例。 我想想我可以帮助您全面了解如何实现Web应用程序的每个部分(前端-后端),以及将各个部分连接在一起以创建允许用户在其上进行输入和更改的软件的最简单方法。服务器以及客户端!

您可以在此处下载此示例的完整源代码: AjaxServletsIntegration

翻译自: https://www.javacodegeeks.com/2014/09/jquery-ajax-servlets-integration-building-a-complete-application.html