金缕衣
无名氏

劝君莫惜金缕衣,

劝君惜取少年时。

花开堪折直须折,

莫待无花空折枝。

WEB资源

WEB资源分为静态资源动态资源

  1. 静态资源
    • 在web 页面中供人们浏览的数据始终是不变。例如:html页面
  2. 动态资源
    • 可以发生变化,可以和根据用户的请求而发生变化的。例如:Servlet,PHP

BS和CS

  1. BS(Browser/Service 浏览器/服务器)
    • 兼容性 , 因为浏览器的种类很多,发现你写的程序,在某个浏览器会出现问题,其它浏览器正常
    • 安全性, 通常情况下,BS 安全性不如 CS 好控制
    • 易用性, BS 好于 CS, 浏览器电脑有
    • 扩展性, BS 相对统一,只需要写 Server
  2. CS(Client/Service 客户端/服务器)

JavaWeb服务器软件

常见的JavaWeb服务软件

  1. Tomcat :由 Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费)
  2. Jboss :是一个遵从 JavaEE 规范的、它支持所有的 JavaEE 规范(免费)
  3. GlassFish :由 Oracle 公司开发的一款 JavaWeb 服务器,是一款商业服务器,达到产品级质量(应用很少)
  4. Resin :是 CAUCHO 公司的产品,是一个非常流行的服务器,对 servlet 和 JSP 提供了良好的支持, 性能也比较优良(收费)。
  5. WebLogic :是 Oracle 公司的产品,支持 JavaEE 规范, 而且不断的完善以适 应新的开发要求,适合大型项目(收费,用的不多,适合大公司)。

Tomcat

概念

​ Tomcat是Apache 组织提供的一种 Web 服务器,提供对 jsp 和 Servlet 的支持。它是一种轻量级的 javaWeb 容器(服务器),也是当前应用最广的 JavaWeb 服务器(免费)。

说明:zip是windows系统,tar.gz是Linux系统

Tomcat配置环境变量

Tomcat 本质是一个 Java 程序

  1. 环境变量添加JAVA_HOME使用指定jdk,不需要带上bin目录。如下图:
配置JAVA_HOME
  1. JAVA_HOME 必须是大写
  2. 8080端口不能被占用,tomcat默认端口是8080
  3. 端口修改

Tomcat目录解读

Tomcat目录结构
  1. Tomcat默认端口是8080,使用http://localhost:8080
  2. webapps文件夹详解
    • 在webapps下创建存放资源的文件夹
    • 文件夹下创建常见WEN-INF文件夹(WEB-INF文件名也必须大写)
    • WEB-INF目录下存放web.xml配置文件
    • WEB-INF目录下的文件资源,外部无法访问到
  3. WEB-INF目录结构


修改Tomcat端口

tomcat安装目录下的conf目录中找到server.xml,修改里边的内容,如下图:修改prot

  1. 端口号范围1-65535
  2. 建议修改端口大于1024,因为系统软件也占用了很多端口,太小容易冲突
  3. 修改后,重启tomcat生效

Web应用的概念

  1. 什么是Web应用
  • WEB应用是多个web资源的集合。简单的说,可以把web应用理解为硬盘上的一个目录, 这个目录用于管理多个web资源。
  • Web应用通常也称之为web应用程序,或web工程,通俗的说 就是网站。
  1. Web应用组成
  • 一个 WEB 应用由多个 WEB 资源或其它文件组成,包括 html 文件、css 文件、js 文件、动 态 web 页面、java 程序、支持 jar 包、配置文件等。开发人员在开发 web 应用时,按照规 定目录结构存放这些文件。否则,在把 web 应用交给 web 服务器管理时,不仅可能会使 web 应用无法访问,还会导致 web 服务器启动报错。
  1. 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的生命周期

  1. init()初始化阶段
    • Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用 init()方法,init()方法只会调用一次
  2. service()处理浏览器请求阶段
    • 每收到一个 http 请求,服务器就会产生一个新的线程去处理,处理请求的时候就会调用service方法
    • service()方法由两个参数ServletRequest封装HTTP请求,ServletResponse封装HTTP响应
  3. destroy()终止
    • 当web 应用被终止,或者Servlet 容器终止运行,或者Servlet 类重新装载时,会调用 destroy()方法, 比如重启 tomcat ,或者 redeploy web 应用

GTE和POST分发处理

常用的表单提交方法GETPOST

  1. GET请求
<form action="/test" method="get">
    用户名:<input type="text" name="username"></br>
    密 码:<input type="password" name="password"></br>
    <input type="submit">
</form>
  • 请求参数带在url后边
  1. 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

  1. HttpServlet继承图

  1. 演示(这里不再截图控制台信息,自己运行)
<?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说明及注意事项

  1. Servlet 是一个供其他 Java 程序(Servlet 引擎)调用的 Java 类,不能独立运行
  2. 针对浏览器的多次 Servlet 请求,通常情况下,服务器只会创建一个 Servlet 实例对象,也就是说 Servlet 实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web 容器退出/或者 redeploy 该 web 应用,servlet 实例对象才会销毁
  3. 在 Servlet 的整个生命周期内,init 方法只被调用一次。而对每次请求都导致 Servlet 引擎调用一次 servlet 的 service 方法
  4. 对于每次访问请求,Servlet 引擎都会创建一个新的 HttpServletRequest 请求对象和一个新的 HttpServletResponse 响应对象,然后将这两个对象作为参数传递给它调用的 Servlet的 service()方法,service 方法再根据请求方式分别调用 doXXX 方法
  5. 如果在元素中配置了一个元素,那么 WEB 应用程序在启动时,就会装载并创建 Servlet 的实例对象、以及调用 Servlet 实例对象的 init()方法

注解方式

  1. 用法演示
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

基本介绍

  1. ServletConfig 类是为 Servlet 程序的配置信息的类
  2. Servlet 程序和 ServletConfig 对象都是由 Tomcat 负责创建
  3. Servlet 程序默认是第 1 次访问的时候创建,ServletConfig 在 Servlet 程序创建时,就创建一个对应的 ServletConfig 对 象

功能

  1. 获取 Servlet 程序的servlet-name的值
  2. 获取初始化参数init-param
  3. 获取 ServletContext对象

ServletContext

基本介绍

  1. ServletContext 是一个接口,它表示 Servlet 上下文对象
  2. 一个 web 工程,只有一个 ServletContext 对象实例
  3. ServletContext 对象是在 web 工程启动的时候创建,在 web 工程停止的时销毁
  4. ServletContext 对象可以通过 ServletConfig.getServletContext 方法获得对 ServletContext对象的引用,也可以通过 this.getServletContext()来获得其对象的引用。
  5. 由于一个 WEB 应用中的所有 Servlet 共享同一个 ServletContext 对象,因此 Servlet 对象之间可以通过 ServletContext 对象来实现多个 Servlet 间通讯。ServletContext 对象通常也被称之为域对象

说明:多个Servlet共用一个ServletContext

功能

  1. 获取 web.xml 中配置的上下文参数context-param(信息和整个 web 应用相关,而不是属于某个 Servlet)
  2. 获取当前的工程路径,格式: /工程路径,比如 /servlet
  3. 获 取 工 程 部 署 后 在 服 务 器 硬 盘 上 的 绝 对 路 径 ( 比 如 :D:\com\servlet\out\artifacts\servlet_war_exploded)
  4. 像 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继承图

基本介绍

  1. HttpServletRequest对象代表客户端的请求
  2. 当客户端/浏览器通过 HTTP 协议访问服务器时,HTTP 请求头中的所有信息都封装在这个对象中
  3. 通过这个对象的方法,可以获得客户端这些信息。

常用的方法

  1. getRequestURI() 获取请求的资源路径 servlet/loginServlet

  2. getRequestURL() 获 取 请 求 的 统 一 资 源 定 位 符 ( 绝 对 路 径 )http://localhost:8080/servlet/loginServlet

  3. getRemoteHost() 获取客户端的 主机

  4. getHeader() 获取请求头

  5. getParameter() 获取请求的参数

  6. getParameterValues() 获取请求的参数(多个值的时候使用) , 比如 checkbox, 返回的数组

  7. getMethod() 获取请求的方式 GET 或 POST

  8. setAttribute(key, value); 设置域数据

  9. getAttribute(key); 获取域数据

  10. getRequestDispatcher() 获取请求转发对象, 请求转发的核心对象

请求转发的一些细节:

  1. 浏览器地址不会变化(地址会保留在第 1 个 servlet 的 url)

  2. 在同一次 HTTP 请求中,进行多次转发,仍然是一次 HTTP 请求

  3. 在同一次 HTTP 请求中,进行多次转发,多个 Servlet 可以共享 request 域/对象的数据(因为始终是同一个 request 对象)

  4. 可以转发到 WEB-INF 目录下

  5. 不能访问当前 WEB 工程外的资源

HttpServletResponse

继承关系

基本介绍

  1. 每次 HTTP 请求,Tomcat 会创建一个 HttpServletResponse 对象传递给 Servlet 程序去使用。
  2. HttpServletRequest 表示请求过来的信息,HttpServletResponse 表示所有响应的信息,如果需要设置返回给客户端的信息,通过 HttpServletResponse 对象来进行设置即可

常用方法

这里只介绍几种,其他的自行查看API文档

  1. 字节流 getOutputStream(); 常用于下载(处理二进制数据)
  2. 字符流 getWriter(); 常用于回传字符串

注意:两个流同时只能使用一个。否则会报错

  1. sendRedirect(); 请求重定向

重定向的一些细节:

  1. 最佳应用场景:网站迁移

  2. 浏览器地址会发生变化,本质是两次 http 请求

  3. 不能共享 Request 域中的数据,本质是两次 http 请求,会生成两个HttpServletRequest对象

  4. 不能重定向到 /WEB-INF 下的资源

  5. 可以重定向到 Web 工程以外的资源, 比如 到 www.baidu.com

  6. 重定向的方式有两种方式:

    // 第一种
    resp.sendRedirect("http://www.baidu.com");
    // 第二种
    resp.setStatus(302);
    resp.setHeader("Location","http://www.baidu.com");

浏览器中文乱码解决方案

  1. 方案1(推荐)
resp.setContentType("text/html;charset=UTF-8");
  1. 方案2
resp.setCharacterEncoding("UTF-8");
resp.setHeader("Content-Type","text/html;charset=UTF-8");

Web会话技术

概念

会话可简单理解为:用户开一个浏览器,点击多个超链接,访问服务器多个 web 资源,然 后关闭浏览器,整个过程称之为一个会话。

在发生一次会话的过程中,需要解决的问题:

  • 每个用户在使用浏览器与服务器进行会话的过程中,不可避免各自会产生一些数据,服 务器要想办法为每个用户保存这些数据
  • 例如:多个用户点击超链接通过一个 servlet 各自购买了一个商品,服务器应该想办法 把每一个用户购买的商品保存在各自的地方,以便于这些用户点结帐 servlet 时,结帐 servlet 可以得到用户各自购买的商品为用户结帐。

分类

会话技术包括两个:Cookie和Session

场景运用

当我们登录校园网或者其他网页,是否提示你的用户名,即浏览器保存了你的登录信息。

Cookie技术可以解决这个问题。

过程

服务器把每个用户的数据以 cookie 的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的 web 资源时,就会带着各自的数据去。这样,web 资源处理的就是用户各自的数据了。

Cookie常用的方法

首先我们得有一个Cookie对象:

// 创建Cookie对象
Cookie cookie = new Cookie("USer","123");

// 也可以从浏览器获取(Cookie数组)
Cookie[] cookies = req.getCookies();

Cookie的Key和Value都是String类型

  1. addCookie

将创建的Cookie对象保存到浏览器

  1. setMaxAge

设置Cookie的保存时间

  • 单位是秒
  • 正数:表示在指定的秒数后过期
  • 负数:表示在浏览器关闭的时候,Cookie会被删除(默认值是-1)
  • 0:表示马上删除Cookie

注意:setMaxAge()之后必须使用addCookie(),才会在浏览器端生效

  1. 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的注意事项和细节

  1. 一个 Cookie 只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。

  2. 一个 WEB 站点可以给一个浏览器发送多个 Cookie,一个浏览器也可以存储多个 WEB 站点提供的 Cookie。

  3. cookie 的总数量没有限制,但是每个域名的 COOKIE 数量和每个 COOKIE 的大小是有限制的 (不同的浏览器限制不同, 知道即可) , Cookie 不适合存放数据量大的信息。

  4. 注意,删除 cookie 时,path必须一致,否则不会删除

Session

场景应用

当我们浏览淘宝的时候,访问不同的页面,但浏览器显示的始终是同一个用户(即:你自己的这个账户),这是如何做到的?

解决方案:Session。Session可以用来唯一的标识用户(浏览器)。

除了上面说到的,Session还可以用来做:

  1. 网上商城中的购物车

  2. 保存登录用户的信息

  3. 将数据放入到 Session 中,供用户在访问不同页面时,实现跨页面访问数据

  4. 防止用户非法登录到某个页面

原理

  1. Session 是服务器端技术,服务器在运行时为每一个用户的浏览器创建一个其独享的session 对象/集合
  2. 由于 session 为各个用户浏览器独享,所以用户在访问服务器的不同页面时,可以从各自的 session 中读取/添加数据, 从而完成相应任务

  1. 可以将Session理解为一个类似HashMap的容器,key和value的值类型分别是StringObject

Session常用方法

  1. getSession()

获取Session对象。和Cookie不同的是,Seesion是通过getSession()来获取对象。第一次调用getSession的时候,他是创建Session,之后是调用创建好的Session对象

  1. setAttribute()

给Session添加属性

  1. getAttribute(String name)

Seesion作用域中获取某个属性

  1. removeAttribute(String name)

从Session作用域中删除某个属性

  1. getId()

获取Session的唯一标识Id。(该Id是服务器自动分配给浏览器的)

Session底层原理

Session生命周期

  1. session.setMaxInactiveInterval();设置Seesion的有效时间(和Cookie一样,以秒为单位),超过指定的时间,Session就会被销毁
  2. 值为负数的时候,表示永不超时
  3. session.getMaxInactiveInterval();获取Seeion的有效时长
  4. seesion.session.invalidate();这会让当前的Seesion立即失效
  5. 如果没有调用 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>
  1. 底层: Tomcat 用一个线程来轮询会话状态,如果某个会话的空闲时间超过设定的最大值,则将该会话销毁

Seesion生命周期的说明:

  1. 指的是两次访问 session 的最大间隔时间
  2. 如果你在 session 没有过期的情况下,操作 session, 则会重新开始计算生命周期
  3. session 是否过期,是由服务器来维护和管理
  4. 如我们调用了 invaliate() 会直接将该 session 删除/销毁

监听器(Listener)

简介

Listener 监听器它是 JavaWeb 的三大组件之一。JavaWeb 的三大组件分别是:Servlet 程序Listener 监听器Filter 过滤器。监听器的作用是,监听某种变化(一般就是对象创建/销毁, 属性变化), 触发对应方法完成相应的任务。javaWeb中监听器一共有八个,常用的是ServletContextListener

ServletContextListener

作用

监听 ServletContext 创建或销毁(当我们 Web 应用启动时,就会创建 ServletContext),即生命周期监听,比如:(1)加载初始化的配置文件;任务调度(配合定时器 Timer/TimerTask)

常用的方法

  1. contextInitialized(ServletContextEvent sce) 创建 Servletcontext 时 触 发
  2. 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 属性变化

常用的方法

  1. void attributeAdded(ServletContextAttributeEvent event) 添加属性时调用
  2. void attributeReplaced(ServletContextAttributeEvent event) 替换属性时调用
  3. 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 创建或销毁,即生命周期监听

这个监听器可以用于监控用户上线,离线

常用的方法

  1. void sessionCreated(HttpSessionEvent se) 创 建 session 时调用 void
  2. sessionDestroyed(HttpSessionEvent se)销毁 session 时调用

HttpSessionAttributeListener

作用

监听 Session 属性的变化

常用方法

  1. void attributeAdded(ServletRequestAttributeEvent srae) 添加属性时
  2. void attributeReplaced(ServletRequestAttributeEvent srae) 替换属性时
  3. void attributeRemoved(ServletRequestAttributeEvent srae) 移除属性时

ServletRequestListener

作用

监听 Request 创建或销毁,即 Request 生命周期监听

可以用来监控, 某个 IP 访问我们网站的频率, 日志记录 ,访问资源的情况.

常用方法

  1. void requestInitialized(ServletRequestEvent sre) 创建 request 时

  2. void requestDestroyed(ServletRequestEvent sre) 销毁 request 时

ServletRequestAttributeListener

作用

监听 Request 属性变化

常用方法

  1. void attributeAdded(ServletRequestAttributeEvent srae) 添加属性时
  2. void attributeReplaced(ServletRequestAttributeEvent srae) 替换属性时
  3. 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接口的三个方法

  1. init():当web工程启动时,会执行构造器和init方法
  2. doFilter():当浏览器请求Tomcat的时候,如果匹配到Filter设置的url-pattern,doFilter()方法就会被调用
  3. destroy():停止web工程的时候,销毁Filter实例,就会调用destroy()

FilterConfig

  1. FilterConfig 是 Filter 过滤器的配置类
  2. Tomcat 每次创建 Filter 的时候,也会创建一个 FilterConfig 对象,这里包含了 Filter 配置文件的配置信息。
  3. 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注意事项和细节

  1. 多个 filter 和目标资源在一次 http 请求,在同一个线程中

  2. 当一个请求 url 和 filter 的 url-pattern 匹配时, 才会被执行, 如果有多个匹配上,就会顺序执行,形成一个 filter 调用链

  3. 多个 filter 共同执行时,因为是一次 http 请求, 使用同一个 request 对象

  4. 多个 filter 执行顺序,和 web.xml 配置顺序保持一致(匹配同一个地址)

  5. chain.doFilter(req, resp)方法 将执行下一个过滤器的 doFilter 方法, 如果后面没有过滤器,则执行目标资源

  6. 小结:注意执行过滤器链时, 顺序是(用前面的案例分析) Http请求 -> A 过滤器 dofilter()-> A 过滤器前置代码 -> A 过滤器 chain.doFilter() -> B 过滤器 dofilter() -> B 过滤器前置代码 -> B过滤器 chain.doFilter() -> 目标文件 -> B过滤器后置代码 -> A过滤器后置代码 ->返回给浏览器页面/数据