javaWeb
劝君莫惜金缕衣,
劝君惜取少年时。
花开堪折直须折,
莫待无花空折枝。
WEB资源
WEB资源分为静态资源和动态资源
- 静态资源
- 在web 页面中供人们浏览的数据始终是不变。例如:html页面
- 动态资源
- 可以发生变化,可以和根据用户的请求而发生变化的。例如:Servlet,PHP
BS和CS
- BS(Browser/Service 浏览器/服务器)
- 兼容性 , 因为浏览器的种类很多,发现你写的程序,在某个浏览器会出现问题,其它浏览器正常
- 安全性, 通常情况下,BS 安全性不如 CS 好控制
- 易用性, BS 好于 CS, 浏览器电脑有
- 扩展性, BS 相对统一,只需要写 Server
- CS(Client/Service 客户端/服务器)
JavaWeb服务器软件
常见的JavaWeb服务软件
- Tomcat :由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费)
- Jboss :是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)
- GlassFish :由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)
- Resin :是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了良好的支持, 性能也比较优良(收费)。
- WebLogic :是 Oracle 公司的产品,支持 JavaEE 规范, 而且不断的完善以适 应新的开发要求,适合大型项目(收费,用的不多,适合大公司)。
Tomcat
概念
Tomcat是Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费)。
说明:zip是windows系统,tar.gz是Linux系统
Tomcat配置环境变量
Tomcat 本质是一个 Java 程序
- 环境变量添加JAVA_HOME使用指定jdk,不需要带上bin目录。如下图:
- JAVA_HOME 必须是大写
- 8080端口不能被占用,tomcat默认端口是8080
- 端口修改
Tomcat目录解读
- Tomcat默认端口是8080,使用http://localhost:8080
webapps文件夹
详解- 在webapps下创建存放资源的文件夹
- 文件夹下创建常见
WEN-INF
文件夹(WEB-INF文件名也必须大写) - WEB-INF目录下存放
web.xml
配置文件 - WEB-INF目录下的文件资源,外部无法访问到
- WEB-INF目录结构
修改Tomcat端口
tomcat安装目录下的conf
目录中找到server.xml
,修改里边的内容,如下图:修改prot
- 端口号范围1-65535
- 建议修改端口大于1024,因为系统软件也占用了很多端口,太小容易冲突
- 修改后,重启tomcat生效
Web应用的概念
- 什么是Web应用
- WEB应用是多个web资源的集合。简单的说,可以把web应用理解为硬盘上的一个目录, 这个目录用于管理多个web资源。
- Web应用通常也称之为web应用程序,或web工程,通俗的说 就是网站。
- Web应用组成
- 一个 WEB 应用由多个 WEB 资源或其它文件组成,包括 html 文件、css 文件、js 文件、动 态 web 页面、java 程序、支持 jar 包、配置文件等。开发人员在开发 web 应用时,按照规 定目录结构存放这些文件。否则,在把 web 应用交给 web 服务器管理时,不仅可能会使 web 应用无法访问,还会导致 web 服务器启动报错。
Web应用目录
结构
- web目录的资源访问方式,以8080端口为例:http://localhost:8080/web目录名称/资源名称
- 直接访问http://localhost:8080的时候,tomcat默认访问的是
ROOT
工程(web应用目录)下的index.jsp
资源
浏览器访问服务器的过程
Servlet
这里使用的集成开发工具是IDEA
- 作用:提供动态网页技术,即:可以动态的处理用户请求。
有关IDEA配置Tomcat请点击这里
Servlet所处的位置
IDEA
使用Servlet的前置准备
- 在
WEB-INF/lib
目录下导入Servlet.jar
- Servlet.jar在
Tomcat安装目录/lib
目录下 - 在
IDEA
下还需右键点击Add as Library... - Servlet添加到工程前后对比
- 出现上图左边的小箭头,表示成功jar包成功引入工程
Servlet的基本使用
servlet有两种配置方式,
XML文件
方式和注解(Servlet版本>=3.0)
方式
XML方式
演示
- Servlet是一个动态的,他不能和访问静态页面一样,直接
XXX.html
- 浏览器想要访问Servlet,就需要在
web.xml
配置文件中提供,供外部访问的地址url-pattern
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>myServlet</servlet-name>
<servlet-class>com.jl.MyServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet</servlet-name>
<url-pattern>/test</url-pattern>
</servlet-mapping>
</web-app>
package com.jl;
import javax.servlet.*;
import java.io.IOException;
/**
* @author long
* @date 2022/9/8
*/
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
/**
* service是专门处理请求的方法
* @param servletRequest
* @param servletResponse
* @throws ServletException
* @throws IOException
*/
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
System.out.println("success");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
浏览器调用Servlet流程
Servlet的生命周期
- init()初始化阶段
- Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init()方法,init()方法只会调用一次
- service()处理浏览器请求阶段
- 每收到一个 http 请求,服务器就会产生一个新的线程去处理,处理请求的时候就会调用service方法
- service()方法由两个参数
ServletRequest
封装HTTP请求,ServletResponse
封装HTTP响应
- destroy()终止
- 当web 应用被终止,或者Servlet 容器终止运行,或者Servlet 类重新装载时,会调用 destroy()方法, 比如重启 tomcat ,或者 redeploy web 应用
GTE和POST分发处理
常用的表单提交方法GET
和POST
- GET请求
<form action="/test" method="get">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit">
</form>
- 请求参数带在url后边
- POST请求
<form action="/test" method="post">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit">
</form>
- 请求参数带在
请求体
里边
请求方法的演示
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
</head>
<body>
<form action="/myServlet/test" method="post">
用户名:<input type="text" name="username"></br>
密 码:<input type="password" name="password"></br>
<input type="submit">
</form>
</body>
</html>
package com.jl;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
/**
* @author long
* @date 2022/9/8
*/
public class MyServlet implements Servlet {
@Override
public void init(ServletConfig servletConfig) throws ServletException {
}
@Override
public ServletConfig getServletConfig() {
return null;
}
@Override
public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
if ("GET".equals(((HttpServletRequest)servletRequest).getMethod())){
doGet(servletRequest, servletResponse);
}
if ("POST".equals(((HttpServletRequest)servletRequest).getMethod())){
doPost(servletRequest, servletResponse);
}
}
public void doGet(ServletRequest servletRequest, ServletResponse servletResponse){
System.out.println("get...");
}
public void doPost(ServletRequest servletRequest, ServletResponse servletResponse){
System.out.println("post...");
}
@Override
public String getServletInfo() {
return null;
}
@Override
public void destroy() {
}
}
通过继承HttpServlet来开发Servlet
HttpServlet
继承图
- 演示(这里不再截图控制台信息,自己运行)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>myServlet02</servlet-name>
<servlet-class>com.jl.MyServlet02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet02</servlet-name>
<url-pattern>/test02</url-pattern>
</servlet-mapping>
</web-app>
package com.jl;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author long
* @date 2022/9/8
*/
public class MyServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get()");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post()");
}
}
Servlet说明及注意事项
- Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
- 针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象,也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁
- 在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引擎调用一次 servlet 的 service 方法
- 对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet的 service()方法,service 方法再根据请求方式分别调用 doXXX 方法
- 如果在
元素中配置了一个 元素,那么 WEB 应用程序在启动时,就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法
注解方式
- 用法演示
package com.jl;
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;
/**
* @author long
* @date 2022/9/8
*/
@WebServlet(urlPatterns = "/test03")
public class MyAnnotationServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("get...");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("post...");
}
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javax.servlet.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebServlet {
String name() default "";
String[] value() default {};
String[] urlPatterns() default {};
int loadOnStartup() default -1;
WebInitParam[] initParams() default {};
boolean asyncSupported() default false;
String smallIcon() default "";
String largeIcon() default "";
String description() default "";
String displayName() default "";
}
- 在XML配置文件里边配的参数,在注解里边都可以
- 按照需要在注解后边添加即可
注解方式比较简单,这里不再赘述。
ServletConfig
基本介绍
- ServletConfig 类是为 Servlet 程序的配置信息的类
- Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
- Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig 对 象
功能
- 获取 Servlet 程序的
servlet-name
的值 - 获取初始化参数
init-param
- 获取
ServletContext
对象
ServletContext
基本介绍
- ServletContext 是一个接口,它表示 Servlet 上下文对象
- 一个 web 工程,只有一个 ServletContext 对象实例
- ServletContext 对象是在 web 工程启动的时候创建,在 web 工程停止的时销毁
- ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。
- 由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext
对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个
Servlet 间通讯。ServletContext
对象通常也被称之为
域对象
。
说明:多个Servlet共用一个ServletContext
功能
- 获取 web.xml
中配置的上下文参数
context-param
(信息和整个 web 应用相关,而不是属于某个 Servlet) - 获取当前的工程路径,格式: /工程路径,比如 /servlet
- 获 取 工 程 部 署 后 在 服 务 器 硬 盘 上 的 绝 对 路 径 ( 比 如 :D:\com\servlet\out\artifacts\servlet_war_exploded)
- 像 Map 一样存取数据
功能使用示例
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<context-param>
<param-name>userName</param-name>
<param-value>123</param-value>
</context-param>
<servlet>
<servlet-name>review</servlet-name>
<servlet-class>com.jl.ReviewServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>review</servlet-name>
<url-pattern>/test04</url-pattern>
</servlet-mapping>
</web-app>
package com.jl;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author long
* @date 2022/9/9
*/
public class ReviewServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = req.getServletContext();
// 使用ServletContext获取上下文参数 context-param
String userName = servletContext.getInitParameter("userName");
// 获取当前工程的绝对路径
String realPath = servletContext.getRealPath("/");
// 获取当前的工程路径
String contextPath = servletContext.getContextPath();
// 设置域对象
servletContext.setAttribute("Parameter","6666");
System.out.println(userName);
System.out.println(realPath);
System.out.println(contextPath);
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
}
ServletContext的域对象可以设置多个,setAttribute()的参数类型为key=String,value=Object
HttpServletRequest
继承关系
基本介绍
HttpServletRequest
对象代表客户端的请求- 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
- 通过这个对象的方法,可以获得客户端这些信息。
常用的方法
getRequestURI() 获取请求的资源路径 servlet/loginServlet
getRequestURL() 获 取 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 )http://localhost:8080/servlet/loginServlet
getRemoteHost() 获取客户端的 主机
getHeader() 获取请求头
getParameter() 获取请求的参数
getParameterValues() 获取请求的参数(多个值的时候使用) , 比如 checkbox, 返回的数组
getMethod() 获取请求的方式 GET 或 POST
setAttribute(key, value); 设置域数据
getAttribute(key); 获取域数据
getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象
请求转发的一些细节:
浏览器地址不会变化(地址会保留在第 1 个 servlet 的 url)
在同一次 HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求
在同一次 HTTP 请求中,进行多次转发,多个 Servlet 可以共享 request 域/对象的数据(因为始终是同一个 request 对象)
可以转发到 WEB-INF 目录下
不能访问当前 WEB 工程外的资源
HttpServletResponse
继承关系
基本介绍
- 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。
- HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可
常用方法
这里只介绍几种,其他的自行查看API文档
- 字节流 getOutputStream(); 常用于下载(处理二进制数据)
- 字符流 getWriter(); 常用于回传字符串
注意:两个流同时只能使用一个。否则会报错
- sendRedirect(); 请求重定向
重定向的一些细节:
最佳应用场景:网站迁移
浏览器地址会发生变化,本质是两次 http 请求
不能共享
Request 域
中的数据,本质是两次 http 请求,会生成两个HttpServletRequest
对象不能重定向到 /WEB-INF 下的资源
可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com
重定向的方式有两种方式:
// 第一种 resp.sendRedirect("http://www.baidu.com"); // 第二种 resp.setStatus(302); resp.setHeader("Location","http://www.baidu.com");
浏览器中文乱码解决方案
- 方案1(推荐)
resp.setContentType("text/html;charset=UTF-8");
- 方案2
resp.setCharacterEncoding("UTF-8");
resp.setHeader("Content-Type","text/html;charset=UTF-8");
Web会话技术
概念
会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然 后关闭浏览器,整个过程称之为一个会话。
在发生一次会话的过程中,需要解决的问题:
- 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服 务器要想办法为每个用户保存这些数据
- 例如:多个用户点击超链接通过一个 servlet 各自购买了一个商品,服务器应该想办法 把每一个用户购买的商品保存在各自的地方,以便于这些用户点结帐 servlet 时,结帐 servlet 可以得到用户各自购买的商品为用户结帐。
分类
会话技术包括两个:Cookie和Session
Cookie
场景运用
当我们登录校园网或者其他网页,是否提示你的用户名,即浏览器保存了你的登录信息。
Cookie技术可以解决这个问题。
过程
服务器把每个用户的数据以 cookie 的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样,web 资源处理的就是用户各自的数据了。
Cookie常用的方法
首先我们得有一个Cookie
对象:
// 创建Cookie对象
Cookie cookie = new Cookie("USer","123");
// 也可以从浏览器获取(Cookie数组)
Cookie[] cookies = req.getCookies();
Cookie的Key和Value都是String类型
- addCookie
将创建的Cookie对象保存到浏览器
- setMaxAge
设置Cookie的保存时间
- 单位是秒
- 正数:表示在指定的秒数后过期
- 负数:表示在浏览器关闭的时候,Cookie会被删除(默认值是-1)
- 0:表示马上删除Cookie
注意:setMaxAge()之后必须使用addCookie(),才会在浏览器端生效
- getCookies()
获取Cookie数组
应用示例
方式一:
Cookie[] cookies = req.getCookies();
for(Cookie cookie: cookies){
if("User".equals(cookie.getName())){
cookie.setValue("要修改的值");
}
}
方式二:
// 创建同名Cookie
Cookie cookie = new Cookie("User","要修改的值");
resp.addCookie(cookie);
Cookie[] cookies = req.getCookies();
for(Cookie cookie: cookies){
if("User".equals(cookie.getName())){
cookie.setMaxAge(0);
resp.addCookie(cookie);
}
}
// 因为是删除,所以在Cookie在浏览器里边就删除了
这里区分一下过期
和删除
两个概念:
过期:当我们使用setMaxAge()设置作用时间之后,该Cookie会在设置的时间之后过期。过期是不会在浏览器存储中删除该Cookie字段的,但他在发送HTTP请求的时候不会携带该Cookie字段
删除:会直接删除浏览器存储中的Cookie字段
Cookie不能直接存储中文,否则访问页面的时候会报java.lang.IllegalArgumentException
错误;
解决方案:使用一种编码过度,即:使用URL编码
// 使用URL对中文进行编码
String name = URLEncoder.encode("名称", "utf-8");
Cookie user = new Cookie(name, name);
resp.addCookie(user);
// 因为存储的是URL编码,所以读取之后也要对其解码
String decode = URLDecoder.decode(name, "utf-8");
Cookie的注意事项和细节
一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。
一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。
cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。
注意,删除 cookie 时,
path
必须一致,否则不会删除
Session
场景应用
当我们浏览淘宝的时候,访问不同的页面,但浏览器显示的始终是同一个用户(即:你自己的这个账户),这是如何做到的?
解决方案:Session。Session可以用来唯一的标识用户(浏览器)。
除了上面说到的,Session还可以用来做:
网上商城中的购物车
保存登录用户的信息
将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据
防止用户非法登录到某个页面
原理
- Session
是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其
独享的session 对象/集合
- 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务
- 可以将Session理解为一个类似HashMap的容器,key和value的值类型分别是
String
和Object
Session常用方法
- getSession()
获取Session对象。和Cookie不同的是,Seesion是通过getSession()来获取对象。第一次调用getSession的时候,他是创建Session,之后是调用创建好的Session对象
- setAttribute()
给Session添加属性
- getAttribute(String name)
从Seesion作用域
中获取某个属性
- removeAttribute(String name)
从Session作用域中删除某个属性
- getId()
获取Session的唯一标识Id。(该Id是服务器自动分配给浏览器的)
Session底层原理
Session生命周期
- session.setMaxInactiveInterval();设置Seesion的有效时间(和Cookie一样,以秒为单位),超过指定的时间,Session就会被销毁
- 值为负数的时候,表示永不超时
- session.getMaxInactiveInterval();获取Seeion的有效时长
- seesion.session.invalidate();这会让当前的Seesion立即失效
- 如果没有调用 setMaxInactiveInterval() 来指定 Session
的生命时长,Tomcat 会以 Session默认时长为准,Session 默认的超时为 30
分钟, 可以在
tomcat/conf/web.xml
设置
<!-- ==================== Default Session Configuration ================= -->
<!-- You can set the default session timeout (in minutes) for all newly -->
<!-- created sessions by modifying the value below. -->
<session-config>
<session-timeout>30</session-timeout>
</session-config>
- 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁
Seesion生命周期的说明:
- 指的是两次访问 session 的最大间隔时间
- 如果你在 session 没有过期的情况下,操作 session, 则会重新开始计算生命周期
- session 是否过期,是由服务器来维护和管理
- 如我们调用了 invaliate() 会直接将该 session 删除/销毁
监听器(Listener)
简介
Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb
的三大组件分别是:Servlet 程序
、Listener 监听器
、Filter 过滤器
。监听器的作用是,监听某种变化(一般就是对象创建/销毁,
属性变化),
触发对应方法完成相应的任务。javaWeb中监听器一共有八个,常用的是ServletContextListener
ServletContextListener
作用
监听 ServletContext 创建或销毁(当我们 Web 应用启动时,就会创建 ServletContext),即生命周期监听,比如:(1)加载初始化的配置文件;任务调度(配合定时器 Timer/TimerTask)
常用的方法
- contextInitialized(ServletContextEvent sce) 创建 Servletcontext 时 触 发
- contextDestroyed(ServletContextEvent sce) 销毁 Servletcontext 时触发
示例:
package com.jl;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* @author long
* @date 2022/9/12
*/
public class MyServletContextListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext创建完成");
}
@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext销毁完成");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.jl.MyServletContextListener</listener-class>
</listener>
</web-app>
ServletContextAttributeListener
作用
监听 ServletContext 属性变化
常用的方法
- void attributeAdded(ServletContextAttributeEvent event) 添加属性时调用
- void attributeReplaced(ServletContextAttributeEvent event) 替换属性时调用
- void attributeRemoved(ServletContextAttributeEvent event) 移除属性时调用
示例:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<listener>
<listener-class>com.jl.MyServletContextAttributeListener</listener-class>
</listener>
</web-app>
package com.jl;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
/**
* @author long
* @date 2022/9/12
*/
public class MyServletContextAttributeListener implements ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext添加了属性");
}
@Override
public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext删除了属性");
}
@Override
public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) {
System.out.println("ServletContext替换了属性");
}
}
package com.jl;
import com.sun.javafx.property.adapter.PropertyDescriptor;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* @author long
* @date 2022/9/8
*/
public class MyServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
ServletContext servletContext = getServletConfig().getServletContext();
servletContext.setAttribute("key","user");
servletContext.setAttribute("key","666");
servletContext.removeAttribute("key");
System.out.println("ok");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
其他的监听器的使用方法差不多,不再示例演示
HttpSessionListener
作用
监听 Session 创建或销毁,即生命周期监听
这个监听器可以用于监控用户上线,离线
常用的方法
- void sessionCreated(HttpSessionEvent se) 创 建 session 时调用 void
- sessionDestroyed(HttpSessionEvent se)销毁 session 时调用
HttpSessionAttributeListener
作用
监听 Session 属性的变化
常用方法
- void attributeAdded(ServletRequestAttributeEvent srae) 添加属性时
- void attributeReplaced(ServletRequestAttributeEvent srae) 替换属性时
- void attributeRemoved(ServletRequestAttributeEvent srae) 移除属性时
ServletRequestListener
作用
监听 Request 创建或销毁,即 Request 生命周期监听
可以用来监控, 某个 IP 访问我们网站的频率, 日志记录 ,访问资源的情况.
常用方法
void requestInitialized(ServletRequestEvent sre) 创建 request 时
void requestDestroyed(ServletRequestEvent sre) 销毁 request 时
ServletRequestAttributeListener
作用
监听 Request 属性变化
常用方法
- void attributeAdded(ServletRequestAttributeEvent srae) 添加属性时
- void attributeReplaced(ServletRequestAttributeEvent srae) 替换属性时
- void attributeRemoved(ServletRequestAttributeEvent srae)移除属性时
HttpSessionBindingListener
HttpSessionActivationListener
这两种监听器和上面的使用方法差不多
过滤器
JavaWeb的三大组件之一
作用
拦截请求,过滤响应
应用场景
- 权限检查
- 日志操作
- 事务管理
Filter过滤器基本原理
基本使用
Filter接口提供了三个方法,用来处理我们的业务
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.jl.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/test03</url-pattern>
</filter-mapping>
</web-app>
-
url-pattern
配置的是拦截路径 - url-pattern : Filter 的拦截路径, 即浏览器在请求什么位置的资源时,过滤器会进行拦截过滤
- 精确匹配 <url-pattern>/a.jsp</url-pattern> 对应的 请求地址 http://ip[域名]:port/工程路径/a.jsp 会拦截
- 目录匹配 <url-pattern>/manage/*</url-pattern>对应的 请求地址 http://ip[域名]:port/工程路径/manage/xx , 即 web 工程 manage 目录下所有资源都会拦截
-
后缀名匹配
.jsp 后缀名可变,比如 .action *.do 等等对应 的 请求地址 http://ip[域名]:port/工程路径/xx.jsp , 后缀名为 .jsp 请求会拦截 - Filter 过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在
package com.jl;
import javax.servlet.*;
import java.io.IOException;
/**
* @author long
* @date 2022/9/12
*/
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("初始化完成");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("前置处理");
doFilter(servletRequest, servletResponse, filterChain);
System.out.println("后置处理");
}
@Override
public void destroy() {
System.out.println("销毁");
}
}
Filter的生命周期
Filter的生命周期分别对应Filter接口的三个方法
- init():当web工程启动时,会执行构造器和init方法
- doFilter():当浏览器请求Tomcat的时候,如果匹配到Filter设置的
url-pattern
,doFilter()方法就会被调用 - destroy():停止web工程的时候,销毁Filter实例,就会调用destroy()
FilterConfig
- FilterConfig 是 Filter 过滤器的配置类
- Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
- FilterConfig对象作用是获取 filter 过滤器的配置内容
示例:
<filter>
<filter-name>myFilter</filter-name>
<filter-class>com.jl.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>myFilter</filter-name>
<url-pattern>/test03</url-pattern>
</filter-mapping>
package com.jl;
import javax.servlet.*;
import java.io.IOException;
/**
* @author long
* @date 2022/9/12
*/
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
String user = filterConfig.getInitParameter("user");
String filterName = filterConfig.getFilterName();
ServletContext servletContext = filterConfig.getServletContext();
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
}
@Override
public void destroy() {
System.out.println("销毁");
}
}
FilterChain过滤连
概念
在处理某些复杂业务时,一个过滤器不够,可以设计多个过滤器共同完成过滤任务,形成过滤器链。
使用示例
AFilter前置通知
BFilter前置通知
ok
BFilter后置通知
AFilter后置通知
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>myServlet02</servlet-name>
<servlet-class>com.jl.MyServlet02</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>myServlet02</servlet-name>
<url-pattern>/test02</url-pattern>
</servlet-mapping>
<filter>
<filter-name>Afilter</filter-name>
<filter-class>com.jl.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Afilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>Bfilter</filter-name>
<filter-class>com.jl.BFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Bfilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
AFilter
<div class='content'>
package com.jl;
import javax.servlet.*;
import java.io.IOException;
/**
* @author long
* @date 2022/9/12
*/
public class AFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("AFilter前置通知");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("AFilter后置通知");
}
@Override
public void destroy() {
}
}
</div>
</details>
BFilter
<div class='content'>
package com.jl;
import javax.servlet.*;
import java.io.IOException;
/**
* @author long
* @date 2022/9/12
*/
public class BFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("BFilter前置通知");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("BFilter后置通知");
}
@Override
public void destroy() {
}
}
</div>
</details>
MyServlet02
<div class='content'>
package com.jl;
import com.sun.javafx.property.adapter.PropertyDescriptor;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextListener;
import javax.servlet.ServletException;
import javax.servlet.http.*;
import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
/**
* @author long
* @date 2022/9/8
*/
public class MyServlet02 extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("ok");
}
@Override
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
</div>
</details>
FilterChain注意事项和细节
多个 filter 和目标资源在一次 http 请求,在同一个线程中
当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行, 如果有多个匹配上,就会顺序执行,形成一个 filter 调用链
多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象
多个 filter 执行顺序,和 web.xml 配置顺序保持一致(匹配同一个地址)
chain.doFilter(req, resp)方法 将执行下一个过滤器的 doFilter 方法, 如果后面没有过滤器,则执行目标资源
小结:注意执行过滤器链时, 顺序是(用前面的案例分析) Http请求 -> A 过滤器 dofilter()-> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 dofilter() -> B 过滤器前置代码 -> B过滤器 chain.doFilter() -> 目标文件 -> B过滤器后置代码 -> A过滤器后置代码 ->返回给浏览器页面/数据