Listener监听器与Ajax
Listener
概念
-
Listener 表示监听器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。 -
监听器可以监听就是在 application ,session ,request 三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件。 request 和 session 我们学习过。而 application 是 ServletContext 类型的对象。 ServletContext 代表整个web应用,在服务器启动的时候,tomcat会自动创建该对象。在服务器关闭时会自动销毁该对象。
分类
JavaWeb 提供了8个监听器:
这里面只有 ServletContextListener 这个监听器后期我们会接触到,ServletContextListener 是用来监听 ServletContext 对象的创建和销毁。
ServletContextListener 接口中有以下两个方法
void contextInitialized(ServletContextEvent sce) :ServletContext 对象被创建了会自动执行的方法void contextDestroyed(ServletContextEvent sce) :ServletContext 对象被销毁时会自动执行的方法
代码演示
- 定义一个类,实现
ServletContextListener 接口 - 重写所有的抽象方法
- 使用
@WebListener 注解进行配置
package com.zcl.webs.listener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
@WebListener
public class ContextLoaderListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("加载资源");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("释放资源");
}
}
Ajax
概念:
AJAX (Asynchronous JavaScript And XML):异步的 JavaScript 和 XML。
JavaScript 表明该技术和前端相关;XML 是指以此进行数据交换。
两方面作用:
- 与服务器进行数据交换:通过AJAX可以给服务器发送请求,服务器将数据直接响应回给浏览器。如下图
我们先来看之前做功能的流程,如下图:
如上图,Servlet 调用完业务逻辑层后将数据存储到域对象中,然后跳转到指定的 jsp 页面,在页面上使用 EL表达式 和 JSTL 标签库进行数据的展示。
学习了AJAX 后,就可以使用AJAX和服务器进行通信,以达到使用 HTML+AJAX来替换JSP页面了。如下图,浏览器发送请求servlet,servlet 调用完业务逻辑层后将数据直接响应回给浏览器页面,页面使用 HTML 来进行数据展示。
2、异步交互:可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用校验,等等…
同步和异步
同步发送请求过程如下
浏览器页面在发送请求给服务器,在服务器处理请求的过程中,浏览器页面不能做其他的操作。只能等到服务器响应结束后才能,浏览器页面才能继续做其他的操作。
异步发送请求过程如下
浏览器页面发送请求给服务器,在服务器处理请求的过程中,浏览器页面还可以做其他的操作。
简单总结:同步需要等上一个资源请求完成才会处理下一个请求,需要排队
异步不需要排队等待
ajax快速入门
1、编写AjaxServley服务器,并使用response输出字符串
package com.zcl.webs;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
@WebServlet("/ajaxServlet")
public class AjaxServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.getWriter().write("hellow");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
2、创建XMLHttpRequest对象,用于和服务器交换数据
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
3、向服务器发送请求
请求路径写绝对路径
xhttp.open("GET", "http://localhost:8080/ajax-demo/ajaxServlet");
xhttp.send();
4、获取服务器响应数据
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
};
Axios异步框架
Axios 对原生的AJAX进行封装,简化书写。
Axios官网是:https://www.axios-http.cn
Axios快速入门
axios 使用是比较简单的,分为以下两步:
1、引入 axios 的 js 文件【官网下载】
<script src="js/axios-0.18.0.js"></script>
2、使用axios 发送请求,并获取响应结果
-
发送 get 请求 axios({
method:"get",
url:"http://localhost:8080/ajax-demo1/aJAXDemo1?username=zhangsan"
}).then(function (resp){
alert(resp.data);
})
-
发送 post请求 axios({
method:"post",
url:"http://localhost:8080/ajax-demo1/aJAXDemo1",
data:"username=zhangsan"
}).then(function (resp){
alert(resp.data);
});
-
后端服务器代码 package com.zcl.webs;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebServlet("/axiosServlet")
public class AxiosServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get...");
String username = request.getParameter("username");
System.out.println(username);
response.getWriter().write("hellow axios");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post...");
this.doGet(request, response);
}
}
axios() 是用来发送异步请求的,小括号中使用 js 对象传递请求相关的参数:
method 属性:用来设置请求方式的。取值为 get 或者 post 。url 属性:用来书写请求的资源路径。如果是 get 请求,需要将请求参数拼接到路径的后面,格式为: url?参数名=参数值&参数名2=参数值2 。data 属性:作为请求体被发送的数据。也就是说如果是 post 请求的话,数据需要作为 data 属性的值。
then() 需要传递一个匿名函数。我们将 then() 中传递的匿名函数称为 回调函数,意思是该匿名函数在发送请求时不会被调用,而是在成功响应后调用的函数。而该回调函数中的 resp 参数是对响应的数据进行封装的对象,通过 resp.data 可以获取到响应的数据。
执行流程:启动服务器,直接访问页面,页面会通过axios请求服务器获取数据
请求方法别名
为了方便起见, Axios 已经为所有支持的请求方法提供了别名。如下:
-
get 请求 : axios.get(url[,config]) -
delete 请求 : axios.delete(url[,config]) -
head 请求 : axios.head(url[,config]) -
options 请求 : axios.option(url[,config]) -
post 请求:axios.post(url[,data[,config]) -
put 请求:axios.put(url[,data[,config]) -
patch 请求:axios.patch(url[,data[,config])
而我们只关注 get 请求和 post 请求。
axios.get("http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan").then(function (resp) {
alert(resp.data);
});
post请求
axios.post("http://localhost:8080/ajax-demo/axiosServlet","username=zhangsan").then(function (resp) {
alert(resp.data);
})
JSON 基础语法
概念:JavaScript Object Notation 。JavaScript 对象表示法.
如下是 JavaScript 对象的定义格式:
{
name:"zhangsan",
age:23,
city:"北京"
}
接下来我们再看看 JSON 的格式:
{
"name":"zhangsan",
"age":23,
"city":"北京"
}
作用:由于其语法格式简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输。
JSON 本质就是一个字符串,但是该字符串内容是有一定的格式要求的。 定义格式如下:
var 变量名 = '{"key":value,"key":value,...}';
JSON 串的键要求必须使用双引号括起来,而值根据要表示的类型确定。value 的数据类型分为如下
- 数字(整数或浮点数)
- 字符串(使用双引号括起来)
- 逻辑值(true或者false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
示例:
var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'
如果它是一个 js 对象,我们就可以通过 js对象.属性名 的方式来获取数据。JS 提供了一个对象 JSON ,该对象有如下两个方法:
parse(str) :将 JSON串转换为 js 对象。使用方式是: var jsObject = JSON.parse(jsonStr); stringify(obj) :将 js 对象转换为 JSON 串。使用方式是:var jsonStr = JSON.stringify(jsObject)
演示代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
var jsonStr = '{"name":"zhangsan","age":23,"addr":["北京","上海","西安"]}'
alert(jsonStr);
let jsObject = JSON.parse(jsonStr);
alert(jsObject)
alert(jsObject.name)
let jsonStr2 = JSON.stringify(jsObject);
alert(jsonStr2)
</script>
</body>
</html>
JSON串和Java对象的相互转换
前端发送请求时,如果是复杂的数据就会以 json 提交给后端;而后端如果需要响应一些复杂的数据时,也需要以 json 格式将数据响应回给浏览器。
- 请求数据:JSON字符串转为Java对象
- 响应数据:Java对象转为JSON字符串
使用的api是Fastjson
Fastjson 概述
Fastjson 是阿里巴巴提供的一个Java语言编写的高性能功能完善的 JSON 库,是目前Java语言中最快的 JSON 库,可以实现 Java 对象和 JSON 字符串的相互转换。
Fastjson 使用
Fastjson 使用也是比较简单的,分为以下三步完成
1、导入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
2、Java对象转JSON
String jsonStr = JSON.toJSONString(obj);
将 Java 对象转换为 JSON 串,只需要使用 Fastjson 提供的 JSON 类中的 toJSONString() 静态方法即可。
3、JSON字符串转Java对象
User user = JSON.parseObject(jsonStr, User.class);
将 json 转换为 Java 对象,只需要使用 Fastjson 提供的 JSON 类中的 parseObject() 静态方法即可。
代码演示
public class FastjsonDemo {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setName("展会上");
user.setAge(56);
String s = JSON.toJSONString(user);
System.out.println(s);
User u = JSON.parseObject("{\"id\":1,\"name\":\"123\",\"age\":56}", User.class);
System.out.println(u);
}
}
案例
需求:使用Axios + JSON 完成品牌列表数据查询和添加。页面效果还是下图所示:
1、查询所有功能
如上图所示就该功能的整体流程。前后端需以 JSON 格式进行数据的传递;由于此功能是查询所有的功能,前端发送 ajax 请求不需要携带参数,而后端响应数据需以如下格式的 json 数据
2、后端实现
在 com.zcl.web 包下创建名为 SelectAllServlet 的 servlet ,具体的逻辑如下:
- 调用 service 的
selectAll() 方法进行查询所有的逻辑处理 - 将查询到的集合数据转换为 json 数据。我们将此过程称为 序列化;如果是将 json 数据转换为 Java 对象,我们称之为 反序列化
- 将 json 数据响应回给浏览器。这里一定要设置响应数据的类型及字符集
response.setContentType("text/json;charset=utf-8");
SelectAllServlet 代码如下:
package com.itheima.webs;
import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.List;
@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
private BrandService brandService = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
List<Brand> brands = brandService.selectAll();
String jsonString = JSON.toJSONString(brands);
response.setContentType("text/json;charset=utf-8");
response.getWriter().write(jsonString);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
3、前端实现
- 引入 js 文件
在 brand.html 页面引入 axios 的 js 文件
<script src="js/axios-0.18.0.js"></script>
- 绑定
页面加载完毕 事件
在 brand.html 页面绑定加载完毕事件,该事件是在页面加载完毕后被触发,代码如下
window.onload = function() {
}
- 发送异步请求
在页面加载完毕事件绑定的匿名函数中发送异步请求,代码如下:
axios({
method:"get",
url:"http://localhost:8080/brand-demo/selectAllServlet"
}).then(function (resp) {
});
- 处理响应数据
在 then 中的回调函数中通过 resp.data 可以获取响应回来的数据,而数据格式如下
现在我们需要拼接字符串,将下面表格中的所有的 tr 拼接到一个字符串中,然后使用 document.getElementById("brandTable").innerHTML = 拼接好的字符串 就可以动态的展示出用户想看到的数据
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="addBrand.html"><input type="button" value="新增"></a><br>
<hr>
<table id="brandTable" border="1" cellspacing="0" width="100%">
</table>
<script src="js/axios-0.18.0.js"></script>
<script>
window.onload = function () {
axios({
method:"get",
url:"http://localhost:8080/brand-demo/selectAllServlet"
}).then(function (resp) {
let brands = resp.data;
let tableData = " <tr>\n" +
" <th>序号</th>\n" +
" <th>品牌名称</th>\n" +
" <th>企业名称</th>\n" +
" <th>排序</th>\n" +
" <th>品牌介绍</th>\n" +
" <th>状态</th>\n" +
" <th>操作</th>\n" +
" </tr>";
for (let i = 0; i < brands.length ; i++) {
let brand = brands[i];
tableData += "\n" +
" <tr align=\"center\">\n" +
" <td>"+(i+1)+"</td>\n" +
" <td>"+brand.brandName+"</td>\n" +
" <td>"+brand.companyName+"</td>\n" +
" <td>"+brand.ordered+"</td>\n" +
" <td>"+brand.description+"</td>\n" +
" <td>"+brand.status+"</td>\n" +
"\n" +
" <td><a href=\"#\">修改</a> <a href=\"#\">删除</a></td>\n" +
" </tr>";
}
document.getElementById("brandTable").innerHTML = tableData;
})
}
</script>
</body>
</html>
输出效果
添加品牌功能
点击 新增 按钮,会跳转到 addBrand.html 页面。在 addBrand.html 页面输入数据后点击 提交 按钮,就会将数据提交到后端,而后端将数据保存到数据库中。
具体的前后端交互的流程如下:
说明:
前端需要将用户输入的数据提交到后端,这部分数据需要以 json 格式进行提交,数据格式如下:
后端实现
在 com.zcl.web 包下创建名为 AddServlet 的 servlet ,具体的逻辑如下:
-
获取请求参数 由于前端提交的是 json 格式的数据,所以我们不能使用 request.getParameter() 方法获取请求参数
- 如果提交的数据格式是
username=zhangsan&age=23 ,后端就可以使用 request.getParameter() 方法获取 - 如果提交的数据格式是 json,后端就需要通过 request 对象获取输入流,再通过输入流读取数据
-
将获取到的请求参数(json格式的数据)转换为 Brand 对象 -
调用 service 的 add() 方法进行添加数据的逻辑处理 -
将 json 数据响应回给浏览器。
AddServlet 代码如下:
java中不可以直接接收json数据,需要获取字符输入流对象来转转
package com.itheima.webs;
import com.alibaba.fastjson.JSON;
import com.itheima.pojo.Brand;
import com.itheima.service.BrandService;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.BufferedReader;
import java.io.IOException;
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
private BrandService brandService = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
BufferedReader reader = request.getReader();
String s = reader.readLine();
Brand brand = JSON.parseObject(s, Brand.class);
brandService.add(brand);
response.getWriter().write("success");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
前端实现
在 addBrand.html 页面给 提交 按钮绑定点击事件,并在绑定的匿名函数中发送异步请求,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>添加品牌</title>
</head>
<body>
<h3>添加品牌</h3>
<form action="" method="post">
品牌名称:<input id="brandName" name="brandName"><br>
企业名称:<input id="companyName" name="companyName"><br>
排序:<input id="ordered" name="ordered"><br>
描述信息:<textarea rows="5" cols="20" id="description" name="description"></textarea><br>
状态:
<input type="radio" name="status" value="0">禁用
<input type="radio" name="status" value="1">启用<br>
<input type="button" id="btn" value="提交">
</form>
<script src="js/axios-0.18.0.js"></script>
<script>
document.getElementById("btn").onclick = function () {
var forData = {
brandName: "",
companyName: "",
ordered: "",
description: "",
status: ""
}
forData.brandName = document.getElementById("brandName").value;
forData.companyName = document.getElementById("companyName").value;
forData.ordered = document.getElementById("ordered").value;
forData.description = document.getElementById("description").value;
let status = document.getElementsByName("status");
for (let i = 0; i < status.length; i++) {
if (status[i].checked) {
forData.status = status[i].value;
}
}
console.log(forData)
axios({
method: 'post',
url: 'http://localhost:8080/brand-demo/addServlet',
data: forData
}).then(function (rep) {
if (rep.data == "success") {
location.href = "http://localhost:8080/brand-demo/brand.html";
}
});
}
</script>
</body>
</html>
|