title: Day20-会话技术&JSP
date: 2020-08-03 17:47:51
author: 子陌
会话技术
- 会话:一次会话中包含多次请求和响应
- 一次会话:浏览器第一次给服务器资源发送请求,会话建立,直到有一方断开为止
- 功能:在一次会话的范围内的多次请求间,共享数据
- 方式:
- 客户端会话技术:Cookie
- 服务器端会话技术:Session
Cookie
客户端会话数据,将数据保存到客户端
-
步骤:
-
创建Cookie对象,绑定数据
new Cookie(String name, String value)
-
发送Cookie对象
response.addCookie(Cookie cookie)
-
获取Cookie,拿到数据
Cookie[] request.getCookies()
-
@WebServlet("/CookieServletDemo")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. 创建Cookie对象,绑定数据
Cookie cookie = new Cookie("msg", "hello");
// 2. 发送Cookie对象
response.addCookie(cookie);
}
@WebServlet("/CookieServletDemo1")
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 3. 获取Cookie,拿到数据
Cookie[] re = request.getCookies();
if (re != null){
for (Cookie cookie1 : re) {
System.out.println(cookie1.getName() + ":" + cookie1.getValue());
}
}
}
Cookie实现原理
Cookie细节:
-
一次可以发送多个cookie,创建多个cookie,调用多次addcookie对象即可
-
cookie在浏览器中能保存多长时间
- 默认情况下,当浏览器关闭后,Cookie数据被销毁
- 持久化存储:
setMaxAge(int seconds)
- second,正数:将Cookie数据写到硬盘的文件中,持久化存储,存活时间为second
- second,负数:默认值
- second,0:删除cookie信息
-
cookie能不能存中文
- 在tomcat 8之前,不能存储
- 需要将中文数据转码–一般采用URL编码(%E3)
- 在tomcat 8之后,可以支持
- 在tomcat 8之前,不能存储
-
cookie获取范围
-
前提:在同一个Tomcat服务器中,多个web项目
- 默认情况下cookie不能共享,默认设置当前目录
setPath(String path)
如果要共享,设为setPath("/")目录下
-
前提:不同Tomcat服务器中,多个web项目
-
setDomain(String path)
如果设置一级域名相同,那么多个服务器之间cookie可以共享例如:setDomain(".baidu.com"),那么tieba.baidu.com和news.baidu.com中cookie可以共享
-
-
-
Cookie的特点和作用
- cookie存储数据在客户端浏览器
- 浏览器对于单个cookie的大小有限制(4KB)以及对用一个域名下的总cookie数量也有限制(20个)
- 作用:
- cookie一般用于存储少量不太敏感的数据
- 在不登录的情况下,完成服务器对客户端的身份识别
- 案例:记住上一次的访问时间
- 需求:
- 访问一个servlet,如果是第一次访问,提示:您好,欢迎首次访问
- 如果不是第一次访问,提示:欢迎回来,您上次访问时间为:显示时间字符串
- 分析:
- 可以采用Cookie完成
- 在服务器servlet中判断是否有名为lastTime的cookie
- 有:欢迎回来
- 没有:首次访问
- 需求:
package com.zimo.cookie;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.crypto.Data;
import java.io.IOException;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.SimpleFormatter;
/**
* cookie快速入门
*/
@WebServlet("/CookieServletDemo2")
public class CookieServletDemo2 extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
// 1. 获取所有的cookie
Cookie[] cookies = request.getCookies();
// 2. 遍历cookie数组
boolean flag = false;
if (cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
// 3. 获取cookie名称
String name = cookie.getName();
if ("lastTime".equals(name)){
flag = true;
// 响应数据
String value = cookie.getValue();
String decode = URLDecoder.decode(value, "utf-8");
response.getWriter().write("欢迎回来,您上次访问时间为:" + decode);
// 设置新的cookie
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = simpleDateFormat.format(date);
String encode = URLEncoder.encode(format, "utf-8");
cookie.setValue(encode);
// 设置存活时间
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
break;
}
}
}
if (cookies == null || cookies.length == 0 || !flag){
// 设置新的cookie
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = simpleDateFormat.format(date);
String encode = URLEncoder.encode(format, "utf-8");
Cookie cookie = new Cookie("lastTime", encode);
// 设置存活时间
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
response.getWriter().write("您好,欢迎首次访问!");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request,response);
}
}
- 使用jsp进行修改案例
<%@ page import="java.net.URLDecoder" %>
<%@ page import="java.util.Date" %>
<%@ page import="java.text.SimpleDateFormat" %>
<%@ page import="java.net.URLEncoder" %><%--
Created by IntelliJ IDEA.
User: zimo
Date: 2020/8/4
Time: 11:22
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>home</title>
</head>
<body>
<%
response.setContentType("text/html;charset=utf-8");
// 1. 获取所有的cookie
Cookie[] cookies = request.getCookies();
// 2. 遍历cookie数组
boolean flag = false;
if (cookies != null && cookies.length > 0){
for (Cookie cookie : cookies) {
// 3. 获取cookie名称
String name = cookie.getName();
if ("lastTime".equals(name)){
flag = true;
// 响应数据
String value = cookie.getValue();
String decode = URLDecoder.decode(value, "utf-8");
out.write("欢迎回来,您上次访问时间为:" + decode);
// 设置新的cookie
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = simpleDateFormat.format(date);
String encode = URLEncoder.encode(format, "utf-8");
cookie.setValue(encode);
// 设置存活时间
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
break;
}
}
}
if (cookies == null || cookies.length == 0 || !flag){
// 设置新的cookie
Date date = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String format = simpleDateFormat.format(date);
String encode = URLEncoder.encode(format, "utf-8");
Cookie cookie = new Cookie("lastTime", encode);
// 设置存活时间
cookie.setMaxAge(60*60*24*30);
response.addCookie(cookie);
out.write("您好,欢迎首次访问!");
}
%>
</body>
</html>
Session
服务器端会话技术,在一次会话的多次请求间共享数据,将数据保存在服务器的对象中。HttpSession
- 快速入门:
- 获取HttpSession对象:
HttpSession session = request.getSession();
- 使用HttpSession对象:
Object getAttribute(String name)
void setAttribute(String name, Object value)
void removeAttribute(String name)
- 获取HttpSession对象:
Session原理
服务器如何确保在一次会话范围内,多次获取的Session对象是同一个
Session是依赖Cookie的
Session细节
- 当客户端关闭后,服务器不关闭,两次获取session是否为同一个
- 默认情况下,不是。
- 可以通过创建Cookie,键为JSESSIONID,设置最大存活时间,让cookie持久化保存
Cookie c = new Cookie("JSESSIONID", session.getId())
c.setMaxAge(60*60)
response.addCookie(c)
- 当客户端不关闭后,服务器关闭,两次获取session是否为同一个
- 不是同一个,关闭后session被销毁
- 要确保数据不丢失,如何实现?
- session的钝化:正常关闭之前,将session对象序列化到硬盘上
- session的活化:服务器启动后,将session文件转化为内存中的session对象即可
- tomcat会自动钝化和活化而idea不会
- session的销毁或失效时间
- 服务器关闭
- session对象调用invalidate()。
- session默认失效时间:30分钟
- 选择性配置修改:web.xml
<session-config> <session-timeout>30</session-timeout> </session-config>
- session的特点:
- session用于存储一次会话的多次请求的数据,存在服务器端
- session可以存储任意类型,任意大小的数据
- session和cookie的区别:
- session存储数据在服务器端,而cookie在客户端
- session没有数据大小限制,cookie有
- session数据安全,cookie相对于不安全
- 案例:验证码
- 需求:
- 访问带有验证码的登录页面login.jsp
- 用户输入用户名,密码及验证码
- 如果用户名和密码输入有误,跳转登录页面,提示:用户名或密码错误
- 如果验证码输入有误,跳转登录页面,提示:验证码错误
- 如果全部输入正确,则跳转到主页success.jsp,显示:用户名,欢迎您
- 分析:
- 设置request的编码
- 获取参数map集合
- 获取验证码
- 用户信息封装到User对象
- 判断验证码和用户输入的验证码是否一致
- 从session获取程序生成的验证码
- 一致,判断用户名密码是否一致,
- 一致:存储数据session,跳转success.jsp重定向
- 不一致:跳转登录页面
- 不一致,跳转登录页面
- 需求:
<%--
Created by IntelliJ IDEA.
User: zimo
Date: 2020/8/4
Time: 16:43
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>login</title>
<script>
window.onload = function(){
document.getElementById("img").onclick = function () {
this.src = "/zimo/checkCodeDemo?time="+new Date().getTime();
}
}
</script>
</head>
<body>
<form action="/zimo/LoginServlet" method="post">
<table>
<tr>
<td>用户名:</td>
<td><input type="text" name="username"></td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>验证码:</td>
<td><input type="text" name="checkcode"></td>
</tr>
<tr>
<td colspan="2"><img id="img" src="/zimo/checkCodeDemo"></td>
</tr>
<tr>
<td colspan="2"><input type="submit" name="登录"></td>
</tr>
</table>
</form>
<div><%=request.getAttribute("cc_err") == null ? "" : request.getAttribute("cc_err")%></div>
<div style="color: red"><%=request.getAttribute("login_err") == null ? "" : request.getAttribute("login_err")%></div>
</body>
</html>
<%--
Created by IntelliJ IDEA.
User: zimo
Date: 2020/8/4
Time: 17:51
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>home</title>
</head>
<body>
<h1><%=request.getSession().getAttribute("user")%>,欢迎你</h1>
</body>
</html>
package com.zimo.checkCode;
import javax.imageio.ImageIO;
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.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;
@WebServlet("/checkCodeDemo")
public class CheckCodeServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int width = 100;
int height = 50;
// 1.创建对象,在内存中画图(验证码图片对象)
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 2.美化图片
// 2.1 填充背景色
Graphics graphics = image.getGraphics(); // 获取画笔对象
graphics.setColor(Color.PINK); // 设置填充颜色
graphics.fillRect(0, 0, width, height); // 填充范围
// 2.2 画边框
graphics.setColor(Color.blue); // 设置画笔颜色
graphics.drawRect(0, 0, width-1, height-1);
// 2.3 写验证码
String checkCode = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
StringBuilder code = new StringBuilder(); // 存储生成的验证码
Random random = new Random();
for (int i = 1;i <= 4; i++) {
int tmp = random.nextInt(checkCode.length()); // 生成随机角标
char c = checkCode.charAt(tmp); // 随机字符
code.append(c);
graphics.drawString(c+"", width/5*i, height/2);
}
String codeString = code.toString();
// 将验证码存入session
req.getSession().setAttribute("checkCode", codeString);
// 2.4 画干扰线
graphics.setColor(Color.GREEN);
for (int i=0; i< 10; i++){
// 随机生成坐标点
int x1 = random.nextInt(width);
int x2 = random.nextInt(width);
int y1 = random.nextInt(height);
int y2 = random.nextInt(height);
graphics.drawLine(x1,y1,x2,y2);
}
// 3.将图片输出页面展示
ImageIO.write(image, "jpg", resp.getOutputStream());
}
}
package com.zimo.checkCode;
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("/LoginServlet")
public class LoginServlet extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1.设置request编码
request.setCharacterEncoding("utf-8");
// 2.获取参数map
String username = request.getParameter("username");
String password = request.getParameter("password");
String checkcode = request.getParameter("checkcode");
// 3.先判断验证码是否正确
// 获取生成的验证码
String sessionCheck = (String)request.getSession().getAttribute("checkCode");
// 让验证码失效,下次不能使用
request.getSession().removeAttribute("checkCode");
if (null != sessionCheck && sessionCheck.equalsIgnoreCase(checkcode)){
// 忽略大小写
if ("admin".equals(username) && "123456".equals(password)){
response.sendRedirect(request.getContextPath() + "/login/success.jsp");
request.getSession().setAttribute("user", username);
}else {
request.setAttribute("login_err", "用户名或密码错误!");
request.getRequestDispatcher("/login/login.jsp").forward(request, response);
}
}else {
// 验证失败
// 存储提示信息
request.setAttribute("cc_err", "验证码错误!");
// 转发到登录页面
request.getRequestDispatcher("/login/login.jsp").forward(request, response);
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
}
JSP入门
Java Server Page: Java服务器端页面,一个特殊的页面,既可以写html标签,又可以写Java代码
- 用于简化书写!
JSP原理:
jsp本质上就是一个servlet
JSP脚本
- jsp定义Java代码的方式:
<% java code %>
:定义在service方法中,在service方法中可以定义什么,该脚本就可以定义什么<%! java code %>
:定义的Java代码,在jsp转换后的Java类的成员位置<%= java code %>
:定义的Java代码,会输出到页面上。输出语句中可以定义什么,该脚本就可以定义什么
JSP内置对象
-
在jsp页面中不需要创建和获取,可以直接使用的对象
-
指令:
- 作用:用于配置jsp页面,导入资源文件
- 格式:
<%@ 指令名称 属性名1=属性值1 属性名2=属性值2... %>
- 分类:
- page:用于配置jsp页面
- contentType:等同于response.setContentType(),设置响应体的mime类型及字符集,设置当前jsp页面的编码
- import:导包
- errorPage:当前页面发生异常后,会自动跳转到指定的错误页面
- isErrorPage:
- true:是,可以使用exception对象
- false:否。默认值。不可以使用内置对象exception
- include:页面包含的。导入页面的资源文件
<%@include file="top.jsp"%>
- taglib:导入资源
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
- prefix:前缀,自定义的
- page:用于配置jsp页面
-
注释:
- html注释:
<!-- -->
,只能注释html代码片段 - jsp注释:
<%-- --%>
,可以注释所有
- html注释:
-
jsp一共有9个内置对象:
不需要创建直接使用
- request(类型:HttpServletRequest):一次请求访问的多个资源(转发)
- response(类型:HttpServletResponse):响应对象
- out(类型:JspWriter):字符输出流对象。可以讲数据输出到页面上,和response.getWriter()类似
- response.getWriter()和out.write()区别:tomcat服务器再给客户端做出响应之前,会先找response缓冲区数据,再找out缓冲区数据
- response.getWriter()数据永远在out.write()之前
- pageContext(类型:PageContext):当前页面共享数据,还可以获取其他八个内置对象
- session(类型:HttpSession):一次会话的多个请求间
- application(类型:ServletContext):所有用户间共享数据
- page(类型:Object):当前页面(servlet)的对象 this
- config(类型:ServletConfig):servlet的配置对象
- exception(类型:Throwable):异常对象
MVC开发模式
-
jsp演变历史
- 早期只有servlet,只能使用response输出标签数据,非常麻烦
- 后来有jsp,简化了servlet的开发,如果过度使用jsp,造成难于维护分工协作
- 再后来,Javaweb开发,借鉴mvc开发模式,使得程序的设计更加合理性
-
MVC:
- M:Model,模型(JavaBean)
- 完成具体的业务操作,如:查询数据库,封装对象
- V:View,视图(JSP)
- 展示数据
- C:Controller,控制器(Servlet)
- 获取客户端的输入
- 调用模型
- 将数据交给视图展示
-
优缺点:
优点:
- 耦合性低,方便维护,可以利于分工协作
- 重用性高
缺点:
- 使得项目架构变得复杂,对开发人员要求高
- M:Model,模型(JavaBean)
EL表达式
-
概念:Expression Language表达式语言
-
作用:替换和简化jsp页面中Java代码的编写
-
语法:
${表达式}
-
注意:jsp默认支持EL表达式
- 忽略EL表达式:
<%@ page isELIgnored="true"%>
\${表达式}
:忽略这个表达式
- 忽略EL表达式:
-
使用:
-
运算:
-
算术运算符【+,-,*,/(div),%(mod)】
-
比较运算符【>,<,>=,<=,==,!=】
-
逻辑运算符【&&(and),||(or),!(not)】
-
空运算符:empty
-
**功能:**用于判断字符串、集合、数组对象是否为null并且长度是否为0
-
用法:
${empty str}
判断str是否为空,或长度是否为0${not empty str}
判断str不为空,且长度是否为不0
-
-
-
获取值:
-
el表达式只能从域对象中获取值
-
语法:
${域名称.键名}
:从指定域中获取指定键的值- 域名称:
- pageScope:pageContext对象中获取
- requestScope:request对象中获取
- sessionScope:session对象中获取
- applicationScope:application对象中获取
- 例如:再request域中存储name = “张三”
- 获取:
${request.name}
- 域名称:
${键名}
:表示依次从最小的域中查找是否有该对应的值,直到找到为止- 获取:
${name}
- 获取:
- 获取对象、List集合、Map集合的值
- 对象:
${域名称.键名.属性名}
本质上会去调用getter方法 - List集合:
${域名称.键名[索引]}
- Map集合:
${域名称.键名["key名称"]}
或${域名称.键名.key名称}
- 对象:
-
隐式对象:el表达式有11个隐式对象
-
${pageContext.属性}
:同样可以获取到其他的8个对象再jsp动态获取虚拟目录
${pageContext.request.contextPath}
-
-
-
JSTL标签
-
概念:JavaServer Page Tag Library JSP标准标签库
是由Apache组织提供的开源的免费的jsp标签
-
作用:用于简化和替换jsp页面上的Java代码
-
使用步骤:
- 导入jstl相关jar包
- 引入标签库:taglib指令:
<%@ taglib %>
- 使用标签
-
常用的JSTL标签
- if:相当于Java if语句
- 属性:test必须属性,接收boolean表达式,如果结果为true,则显示标签内容
- 一般情况下根据el表达式一起使用
- 该标签没有else情况
- choose:相当于Java switch语句
- choose:相当于switch
- when:相当于case
- otherwise:相当于default
- foreach:相当于Java for循环
- begin:开始值(包含)
- end:结束值(包含)
- var:临时遍历(相当于i)
- step:步长1(相当于i++)
- varStatus:循环状态对象
- index:容器中元素的索引,从0开始
- count:循环的次数,从1开始
- 容器对象遍历:
- items:容器对象
- var:容器临时变量
- if:相当于Java if语句
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSTL标签</title>
</head>
<bdoy>
<%--
c:if标签
1.属性:
* test必须属性,接收boolean表达式,如果结果为true,则显示标签内容
--%>
<c:if test="true">aaaaaaaaaaaa</c:if>
<%
List list = new ArrayList();
list.add("aaaa");
request.setAttribute("list",list)
%>
<c:if test="${not empty list}">遍历集合</c:if>
<%-- choose标签 --%>
<%
request.setAttribute("week", 3);
%>
<c:chooes>
<c:when test="${number ==1}">星期一</c:when>
<c:when test="${number ==2}">星期二</c:when>
<c:when test="${number ==3}">星期三</c:when>
<c:when test="${number ==4}">星期四</c:when>
<c:when test="${number ==5}">星期五</c:when>
<c:when test="${number ==6}">星期六</c:when>
<c:when test="${number ==7}">星期日</c:when>
<c:otherwise>非法日期</c:otherwise>
</c:chooes>
<%--
c:foreach标签
1.属性:
* begin:开始值(包含开始)
* end:结束值(包含结束)
* var:临时变量相当于i
* stee:步长
* varStatus:.index元素索引 .count循环次数
--%>
<c:forEach begin="1" end="10" step="1" var="i" varStatus="s">
${i} <span>${s.index}</span><br/>
</c:forEach>
<%--
for(User u : uList)
c:foreach标签遍历容器
1.属性:
* items:容器对象 uList
* var:容器中元素临时变量 u
--%>
<%
List list = new ArrayList();
list.add("aaa");list.add("bbb");list.add("ccc");
request.setAttribute("list",list);
%>
<c:forEach items=${list} var="str" varStatus="s">
${str}<span>${s.index}${s.count}</span><br/>
</c:forEach>
</bdoy>
</html>
三层架构
软件设计架构
- 界面层(表示层):用户看得见得界面。用户可以通过界面上的组件和服务器进行交互
- 业务逻辑层:处理业务逻辑的
- 数据访问层:操作数据存储文件
案例:用户信息列表展示
-
需求:用户信息的增删改查操作
-
设计:
- 技术选型:Servlet+JSP+MySQL+JDBCTemplate+Druid+BeanUtils+Tomcat
- 数据库设计:user表创建
CREATE DATABASE test; USE test; CREATE TABLE USER ( id INT PRIMARY KEY AUTO_INCREMENT, NAME VARCHAR(20) NOT NULL, gender VARCHAR(5), age INT, addr VARCHAR(32), qq VARCHAR(20), email VARCHAR(50) );
-
开发:
- 环境搭建:创建数据库环境
- 创建项目:导入需要的jar包
- 编码
-
测试
-
部署
- 添加
- 删除
- 删除选中
- 修改
- 分页功能
Filter:过滤器
当访问服务器资源时,过滤器可以将请求拦截下来,完成一些特殊功能。
- 过滤器的作用:
- 一般用于完成通用的资源:如登录验证、设置编码、敏感字符过滤等…
- 步骤:
- 定义一个类,实现接口Fileter
- 复写方法
- 配置:拦截路径
- web.xml
- 注解:
@WebFilter("/*"):访问所有资源之前都会执行该过滤器
package com.zimo.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* Filter快速入门
*/
@WebFilter("/*") // 访问所有资源之前都会执行该过滤器
public class FilterDemo implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
// 对request对象请求消息增强
System.out.println("我来了");
// 放行
chain.doFilter(req, resp);
// 对response对象请求消息增强
System.out.println("我走了");
}
@Override
public void destroy() {
}
}
过滤器细节:
-
web.xml配置
<filter> <filter-name>filterDemo1</filter-name> <filter-class>com.zimo.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>filterDemo1</filter-name> <url-pattern>/*</url-pattern> <!-- 拦截路径 --> </filter-mapping>
-
过滤器执行流程
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { // 对request对象请求消息增强 System.out.println("before"); // 放行 chain.doFilter(req, resp); // 对response对象请求消息增强 System.out.println("after"); }
-
过滤器生命周期方法
@Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("服务器启动,创建Filter对象时,只执行一次,一般用于加载资源"); } @Override public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) { System.out.println("多次请求,多次拦截,每次拦截执行一次"); } @Override public void destroy() { System.out.println("服务器关闭后,Filter对象被销毁,只执行一次,一般用于释放资源"); }
-
过滤器配置详解
-
拦截路径配置:
- 具体资源路径:/index.jsp,只有访问index.jsp资源时,过滤器才会被执行
- 拦截目录:/user/*,访问/user下的所有资源时,过滤器都会执行
- 后缀名拦截:*.jsp,访问所有jsp资源时,过滤器都会被执行
- 拦截所有资源:/*,访问所有资源时,过滤器都会被执行
-
拦截方式:资源被访问的方式
-
注解配置:设置dispatcherTypes属性
-
REQUEST:默认值。浏览器直接请求资源
@WebFilter(value="/index.jsp", dispatcherTypes=Dispatcher.REQUEST)
-
FORWARD:转发访问资源
@WebFilter(value="/index.jsp", dispatcherTypes=Dispatcher.FORWARD)
-
INCLUDE:包含访问资源
-
ERROR:错误跳转资源
-
ASYNC:异步访问资源
-
-
web.xml:
<filter> <filter-name>filterDemo1</filter-name> <filter-class>com.zimo.filter.FilterDemo1</filter-class> </filter> <filter-mapping> <filter-name>filterDemo1</filter-name> <url-pattern>/*</url-pattern> <!-- 拦截路径 --> <dispatcher>REQUEST</dispatcher> </filter-mapping>
-
-
-
过滤器链(配置多个过滤器)
- 执行顺序:如果有n个过滤器,执行方式跟递归类似,123 资源 321
- 先后顺序:
- 注解配置:按类名的字符串比较规则,值小先执行
- xml配置:谁定义(
<filter-mapping>
)在上面,谁先执行
Listener:监听器
web三大组件之一:Servlet、Filter、Listener
-
事件监听机制:
- 事件:一件事
- 事件源:事件发生的地方
- 监听器:一个对象
- 注册监听:将事件、事件源、监听器绑定在一起。当事件源上发生某个事件后,执行监听器代码
-
ServletContextListener:监听ServletContext对象的创建和销毁
void contextDestroyed(ServletContextEvent sce)
:ServletContext对象被销毁之前调用该方法void contextInitialized(ServletContextEnent sce)
:ServletContext对象创建后会调用该方法
-
步骤:
-
定义一个类,实现ServletContextListener接口
-
复写方法
-
配置
-
web.xml:
<!-- 注册监听器 --> <listener> <listener-class>com.zimo.listener.ContextLoaderListener</listener-class> </listener> <!-- 指定初始化参数 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/classes/applicationContext.xml</param-value> </context-param>
-
注解:
@WebListener
package com.zimo.listener; import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener; import java.io.FileInputStream; import java.io.FileNotFoundException; @WebListener public class ContextLoaderListener implements ServletContextListener { @Override public void contextInitialized(ServletContextEvent servletContextEvent) { System.out.println("ServletContextEvent对象被创建了"); // 加载资源文件 // 1.获取ServletContext对象 ServletContext servletContext = servletContextEvent.getServletContext(); // 2.加载资源文件 String contextConfigLocation = servletContext.getInitParameter("contextConfigLocation"); // 3.获取真实路径 String realPath = servletContext.getRealPath(contextConfigLocation); // 4.加载进内存 try { FileInputStream fileInputStream = new FileInputStream(realPath); } catch (FileNotFoundException e) { e.printStackTrace(); } } @Override public void contextDestroyed(ServletContextEvent servletContextEvent) { System.out.println("ServletContextEvent对象被销毁了"); } }
-
-