Filter
1 Filter过滤器
1.1 Filter概述
- Filter 表示过滤器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一。
- 过滤器可以吧对资源的请求拦截下来,从而实现一些特殊的功能
- 过滤器一般完成一些通用的操作,比如权限控制、统一字符编码、敏感字符处理
1.2 快速入门
-
定义类,实现 Filter接口,并重写其所有方法,注意:导Filter包要选javax.servlet
-
配置Filter拦截资源的路径:在类上定义 @WebFilter 注解,注解的 value 属性值 /* 表示拦截所有的资源
-
在doFilter方法中输出一句话,并放行
1.3 Filter执行流程
思考:
- 放行后访问对应资源,资源访问完成后,还会回到Filter中吗?会
- 如果回到Filter中, 是重头执行还是执行放行后的逻辑呢?放行后逻辑
可以将对请求request进行处理的代码放在放行之前进行处理,而如果请求完资源后还要对响应reponse的数据进行处理时可以在放行后进行逻辑处理
1.4 Filter使用细节
1.4.1 Filter拦截路径配置
-
Filter可以根据需求,配置不同的拦截资源路径
拦截具体的资源:/index.jsp:只有访问index.jsp时才会被拦截
目录拦截:/user/*:访问/user下的所有资源,都会被拦截
后缀名拦截:*.jsp:访问后缀名为jsp的资源,都会被拦截
拦截所有:/*:访问所有资源,都会被拦截
1.4.2 过滤器链
- 一个Web应用可以配置多个过滤器,这多个过滤器称为过滤器链
- 过滤器链中的过滤器的优先级根据类名(字符串)字母序排列。
上图中的过滤器链执行是按照以下流程执行:
执行 Filter1 的放行前逻辑代码
执行 Filter1 的放行代码
执行 Filter2 的放行前逻辑代码
执行 Filter2 的放行代码
访问到资源
执行 Filter2 的放行后逻辑代码
执行 Filter1 的放行后逻辑代码
1.5 案例–登录验证
需求:访问服务器资源时,需要先进行登录验证,如果没有登录,则自动跳转到登录页面
注意:一定要先判断拦截内容是不是登录注册相关资源,例如登录页面的css、js、img等资源要放行。
LoginFilter:
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//1. 判断session中是否有user
HttpSession session = req.getSession();
Object user = session.getAttribute("user");
//2. 判断user是否为null
if(user != null){
// 登录过了
//放行
chain.doFilter(request, response);
}else {
// 没有登陆,存储提示信息,跳转到登录页面
req.setAttribute("login_msg","您尚未登陆!");
req.getRequestDispatcher("/login.jsp").forward(req,response);
}
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
完成后测试代码。
清除浏览器缓存后,在浏览器上输入 http://localhost:8080/brand-demo/ ,看不到任何图片的信息和网页渲染
因为在请求css等资源时被过滤器拦截,就相当于没有加载到样式文件导致的。解决这个问题,只需要对所以的登陆、注册相关的资源进行放行即可。
修改后的LoginFilter代码:
@WebFilter("/*")
public class LoginFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
HttpServletRequest req = (HttpServletRequest) request;
//判断访问的资源路径是否和登录注册相关
String[] urls = {"/login.jsp","/imgs/","/css/","/loginServlet","/register.jsp","/registerServlet","/checkCodeServlet"};
//获取当前访问的资源路径
String url = req.getRequestURL().toString();
//遍历数组,获取到每一个需要放行的资源路径
for (String u : urls) {
//判断当前访问的资源路径字符串是否包含要放行的的资源路径字符串
/*
比如当前访问的资源路径是 /brand-demo/login.jsp
而字符串 /brand-demo/login.jsp 包含了字符串 /login.jsp ,所以这个字符串就需要放行
*/
if (url.contains(u)) {
//找到了,放行
chain.doFilter(request, response);
//break;
return;
}
}
//1.判断session中是否有user
HttpSession session = req.getSession();
Object user = session.getAttribute("user");
//2.判断user是否为null
if (user != null){
//登录过了
//放行
chain.doFilter(request, response);
}else {
//未登录,存储提示信息,并跳转到登录页面
req.setAttribute("login_msg","您尚未登录!!");
req.getRequestDispatcher("login.jsp").forward(req,response);
}
}
public void init(FilterConfig config) throws ServletException {
}
public void destroy() {
}
}
2 Listener监听器(了解)
2.1 Listener概述
- Listener 表示监听器,是 JavaWeb 三大组件(Servlet、Filter、Listener)之一
- 监听器可以监听就是在 application,session,request 三个对象创建、销毁或者往其中添加修改删除属性时自动执行代码的功能组件
- Listener分类:JavaWeb 提供了8个监听器
2.1 ServletContextListener使用
- 定义一个类,实现ServletContextListener 接口
- 在类上添加 @WebListener 注解
【示例】
@WebListener
//实现ServletContextListener 接口,用于对ServletContext对象的创建和销毁进行监听,
//ServletContext代表整个web应用,在服务器启动的时候,tomcat会自动创建该对象。在服务器关闭时会自动销毁该对象。
public class ContextLoaderListener implements ServletContextListener {
@Override
//ServletContext对象创建时执行方法
public void contextInitialized(ServletContextEvent sce) {
//加载资源
System.out.println("ContextLoaderListener...");
}
@Override
//ServletContext对象销毁时执行方法
public void contextDestroyed(ServletContextEvent sce) {
//释放资源
}
}
3 AJAX
3.1 AJAX概述
-
AJAX (Asynchronous JavaScript And XML):异步的 JavaScript 和 XML
-
AJAX作用:
1.与服务器进行数据交换:通过AJAX可以给服务器发送请求,服务器将数据直接响应回给浏览器。
使用AJAX和服务器进行通信,以达到使用 HTML+AJAX来替换JSP页面了
2.可以在不重新加载整个页面的情况下,与服务器交换数据并更新部分网页的技术,如:搜索联想、用户名是否可用校验,等等… -
同步与异步
3.2 AJXA快速入门
- 编写AjaxServlet,并使用response输出字符串
- 创建XMLHttpRequest对象:用于和服务器交换数据
- 向服务器发送请求
- 获取服务器响应数据
服务端实现:AjaxServlet
@WebServlet("/ajaxServlet")
public class AjaxServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 响应数据
response.getWriter().write("hello ajax~");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
客户端实现: 01-ajax-demo1.html 参考官方文档
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<script>
//1. 创建核心对象
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2. 发送请求
xhttp.open("GET", "http://localhost:8080/ajax-demo/ajaxServlet");
xhttp.send();
//3. 获取响应
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
alert(this.responseText);
}
};
</script>
</body>
</html>
测试代码:
3.3 案例
需求:在完成用户注册时,当用户名输入框失去焦点时,校验用户名是否在数据库已存在
SelectUserServlet:
@WebServlet("/selectUserServlet")
public class SelectUserServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.接收用户名
String username = request.getParameter("username");
//2.调用service查询user对象
boolean flag = true; //模拟对象存在
//3.响应标记
response.getWriter().write(""+flag);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
在 register.html 页面的 body 结束标签前编写 script 标签,在该标签中实现如下逻辑:
第一步:给用户名输入框绑定光标失去焦点事件 onblur
//1. 给用户名输入框绑定 失去焦点事件
document.getElementById("username").onblur = function () {
}
第二步:发送 ajax请求,携带username参数
在 第一步 绑定的匿名函数中书写发送 ajax 请求的代码
//2. 发送ajax请求
//2.1. 创建核心对象
var xhttp;
if (window.XMLHttpRequest) {
xhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
//2.2. 发送请求
xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUserServlet);
xhttp.send();
//2.3. 获取响应
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
//处理响应的结果
}
};
由于我们发送的是 GET 请求,所以需要在 URL 后拼接从输入框获取的用户名数据。而我们在 第一步 绑定的匿名函数中通过以下代码可以获取用户名数据
// 获取用户名的值
var username = this.value; //this : 给谁绑定的事件,this就代表谁
携带数据需要将 URL 修改为:
xhttp.open("GET", "http://localhost:8080/ajax-demo/selectUserServlet?username="+username);
处理响应:是否显示提示信息
当 this.readyState == 4 && this.status == 200 条件满足时,说明已经成功响应数据了。
此时需要判断响应的数据是否是 “true” 字符串,如果是说明用户名已经占用给出错误提示;如果不是说明用户名未被占用清除错误提示。代码如下
//判断
if(this.responseText == "true"){
//用户名存在,显示提示信息
document.getElementById("username_err").style.display = '';
}else {
//用户名不存在 ,清楚提示信息
document.getElementById("username_err").style.display = 'none';
}
3.5 Axios异步框架
- Axios 对原生的AJAX进行封装,简化书写
- Axios官网是:https://www.axios-http.cn
3.5.1 Axios快速入门
- 引入 axios 的 js 文件
- 使用Axios发送请求并获取响应结果
【示例】
- 引入 axios 的 js 文件
<script src="js/axios-0.18.0.js"></script>
- 使用axios 发送请求,并获取响应结果
axiosServlet
@WebServlet("/axiosServlet")
public class AxiosServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("get...");
//1.接收请求参数
String username = request.getParameter("username");
System.out.println(username);
//2. 响应数据
response.getWriter().write("hello axios~");
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("post...");
this.doGet(request, response);
}
}
<script>
//1.get
/*axios({
method:"get",
url:"http://localhost:8080/ajax-demo/axiosServlet?username=zhangsan"
}).then(function (resp) {
alert(resp.data);
})*/
//2.post
axios({
method:"post",
url:"http://localhost:8080/ajax-demo/axiosServlet",
data:"username=zhangsan"
}).then(function (resp) {
alert(resp.data);
})
</script>
测试结果
3.5.2 Axios请求方式别名
- get 请求 : axios.get(url[,config])
- post 请求:axios.post(url[,data[,config])
- delete 请求 : axios.delete(url[,config])
- head 请求 : axios.head(url[,config])
- options 请求 : axios.option(url[,config])
- put 请求:axios.put(url[,data[,config])
- patch 请求:axios.patch(url[,data[,config])
主要了解get请求和post请求
4 JSON
- JavaScript Object Notation。JavaScript 对象表示法
- JSON作用:由于其语法格式简单,层次结构鲜明,现多用于作为数据载体,在网络中进行数据传输。
JavaScript和JSON:
js 对象中的键可以使用引号(可以是单引号,也可以是双引号);而 json 格式中的键要求必须使用双引号括起来,这是 json 格式的规定。
4.1 JSON基本语法
value 的数据类型:
- 数字(整数或浮点数)
- 字符串(使用双引号括起来)
- 逻辑值(true或者false)
- 数组(在方括号中)
- 对象(在花括号中)
- null
4.2 JSON数据和Java对象转换
- 请求数据:JSON字符串转为Java对象
- 响应对象:Java对象转为JSON字符串
- Fastjson 是阿里巴巴提供的一个Java语言编写的高性能功能完善的 JSON 库,是目前Java语言中最快的 JSON 库,可以实现 Java 对象和 JSON 字符串的相互转换。
- 使用:
【示例】
- 引入坐标
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.62</version>
</dependency>
- 创建一个类,测试 Java 对象和 JSON 串的相互转换
import com.alibaba.fastjson.JSON;
public class FastJsonDemo {
public static void main(String[] args) {
User user = new User();
user.setId(1);
user.setUsername("zhangsan");
user.setPassword("123");
//将Java对象转为JSON字符串
String jsonString = JSON.toJSONString(user);
System.out.println(jsonString);
//将JSON字符串转为Java对象
User u = JSON.parseObject("{\"id\":1,\"password\":\"123\",\"username\":\"zhangsan\"}", User.class);
System.out.println(u);
}
}
4.3 案例–品牌列表数据
使用Axios+JSON完成品牌列表数据查询和添加
4.3.1 查询所有
后端实现:
在 com.itheima.web 包下创建名为 SelectAllServlet 的 servlet,具体的逻辑如下:
调用 service 的 selectAll() 方法进行查询所有的逻辑处理
将查询到的集合数据转换为 json 数据。我们将此过程称为 序列化;如果是将 json 数据转换为 Java 对象,我们称之为 反序列化
将 json 数据响应回给浏览器。这里一定要设置响应数据的类型及字符集 response.setContentType(“text/json;charset=utf-8”);
具体实现:
项目目录结构:
SelectAllServlet
@WebServlet("/selectAllServlet")
public class SelectAllServlet extends HttpServlet {
private BrandService brandService = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 调用Service查询
List<Brand> brands = brandService.selectAll();
//2. 将集合转换为JSON数据 序列化
String jsonString = JSON.toJSONString(brands);
//3. 响应数据 application/json text/json
response.setContentType("text/json;charset=utf-8");
//后端发JSON串,前端then里的响应数据是json数组
response.getWriter().write(jsonString);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.doGet(request, response);
}
}
brand.html
<!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>
//1. 当页面加载完成后,发送ajax请求
window.onload = function () {
//2. 发送ajax请求
axios({
method:"get",
url:"http://localhost:8080/brand-demo/selectAllServlet"
}).then(function (resp) {
//获取数据
let brands = resp.data;
//先这样循环渲染,后面用vue后会优化
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>";
//后端发JSON串,前端then里的响应数据是json数组
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>
4.3.2 新增品牌
后端实现:
在 com.itheima.web 包下创建名为 AddServlet 的 servlet,具体的逻辑如下:
获取请求参数
由于前端提交的是 json 格式的数据,所以我们不能使用 request.getParameter() 方法获取请求参数
如果提交的数据格式是 username=zhangsan&age=23 ,后端就可以使用 request.getParameter() 方法获取
如果提交的数据格式是 json,后端就需要通过 request 对象获取输入流,再通过输入流读取数据
将获取到的请求参数(json格式的数据)转换为 Brand 对象
调用 service 的 add() 方法进行添加数据的逻辑处理
将 json 数据响应回给浏览器。
AddServlet :
@WebServlet("/addServlet")
public class AddServlet extends HttpServlet {
private BrandService brandService = new BrandService();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1. 接收数据,request.getParameter 不能接收json的数据
/* String brandName = request.getParameter("brandName");
System.out.println(brandName);*/
// 获取请求体数据
BufferedReader br = request.getReader();
String params = br.readLine();
// 将JSON字符串转为Java对象
Brand brand = JSON.parseObject(params, Brand.class);
//2. 调用service 添加
brandService.add(brand);
//3. 响应成功标识
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>
//1. 给按钮绑定单击事件
document.getElementById("btn").onclick = function () {
// 将表单数据转为json
var formData = {
brandName:"",
companyName:"",
ordered:"",
description:"",
status:"",
};
// 获取表单数据
let brandName = document.getElementById("brandName").value;
// 设置数据
formData.brandName = brandName;
// 获取表单数据
let companyName = document.getElementById("companyName").value;
// 设置数据
formData.companyName = companyName;
// 获取表单数据
let ordered = document.getElementById("ordered").value;
// 设置数据
formData.ordered = ordered;
// 获取表单数据
let description = document.getElementById("description").value;
// 设置数据
formData.description = description;
let status = document.getElementsByName("status");
for (let i = 0; i < status.length; i++) {
if(status[i].checked){
//
formData.status = status[i].value ;
}
}
//console.log(formData);
//2. 发送ajax请求
axios({
method:"post",
url:"http://localhost:8080/brand-demo/addServlet",
//data后放JSON,js会自动转成JSON字符串
data:formData
}).then(function (resp) {
// 判断响应数据是否为 success
if(resp.data == "success"){
location.href = "http://localhost:8080/brand-demo/brand.html";
}
})
}
</script>
</body>
</html>
submit提交表单:<input type=“submit”>,是同步的
button提交表单:点击事件提交,是异步的