EL&JSTL&Filter&Listener day24-EL&JSTL&Filter&Listener 第一章 EL表达式 第二章 JSTL的核心标签库使用 第三章 过滤器Filter 第四章 监听器Listener(了解)

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

第一章 EL表达式

1.概述

EL(Express Lanuage) 表达式可以嵌入在jsp页面内部,减少jsp脚本的编写,EL出现的目的主要是代替jsp页面中输出脚本<%= 数据%>的编写

2.格式和作用

EL表达式的格式

${EL表达式内容}

EL表达式的作用:

  1. 从域对象中查找制定的数据
    1. ServletContext 作用域整个web程序
    2. session 一次会话
    3. request 一次请求
    4. pageContext 当前JSP页面
  2. EL内置对象的使用
  3. 执行运算符

3.表达式的基本使用(从域中取数据)

1.EL表达式取数据

格式XXXXScope.key

  1. ${applicationScope.键名} ServletContext 域对象存储键值对
  2. ${sessionScope.键名} session 域对象存储键值对
  3. ${requestScope.键名} request.域对象存储键值对
  4. ${pageScope.键名} pageContext域对象存储键值对

2.简化方式

EL 表达式去处域对象的数据,简化方式,推荐使用

${键名} 将会从最小的域对象开始查找,一旦找到,就不会再继续查找

友好型:客户端的友好型

<%=%> 取出域对象数据,没有此键,页面中显示null

${} 取出域对象中的数据 没有此键,页面中显示" "

3.通过EL表达式,获得普通数据

格式:

${key}

代码演示:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>获取域容器中的数据</title>
</head>
<body>
    <%
        // 1 将数据保存到域容器中
        pageContext.setAttribute("city", "北京1"); // page
        pageContext.setAttribute("city", "北京2", PageContext.REQUEST_SCOPE); // request
        pageContext.setAttribute("city", "北京3", PageContext.SESSION_SCOPE); // session
        pageContext.setAttribute("city", "北京4", PageContext.APPLICATION_SCOPE); // servletContext

        // 2 删除指定域数据
        /*
        pageContext.removeAttribute("city", PageContext.PAGE_SCOPE); // page
        pageContext.removeAttribute("city", PageContext.REQUEST_SCOPE); // request
        pageContext.removeAttribute("city", PageContext.SESSION_SCOPE); // session
        pageContext.removeAttribute("city", PageContext.APPLICATION_SCOPE); // servletContext
         */
        pageContext.removeAttribute("city"); // 删除所有域中的数据
    %>

    <h1>java</h1>
        <h3>获取数据</h3>
        <%
            out.print(pageContext.getAttribute("city")!=null?pageContext.getAttribute("city"):""); // page
            out.print(pageContext.getAttribute("city", PageContext.REQUEST_SCOPE)); // request
            out.print(pageContext.getAttribute("city", PageContext.SESSION_SCOPE)); // session
            out.print(pageContext.getAttribute("city", PageContext.APPLICATION_SCOPE)); // servletContext
        %>

        <h3>智能获取数据</h3>

        <%
            /*
            pageContext.findAttribute(key) 根据key从四个域容器中依次获取数据, 如果获取到了,取值结束; 如果都没有获取到, 返回null
             */
            out.print(pageContext.findAttribute("city"));
        %>

    <h1>EL</h1>
        <h3>获取数据</h3>
        ${pageScope.city}
        ${requestScope.city}
        ${sessionScope.city}
        ${applicationScope.city}

    <h3>智能获取数据</h3>
        ${city}
</body>
</html>

4. EL获得javaBean对象的值

格式:

${对象.成员变量}

代码演示

<%@ page import="cn.itcast.pojo.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%
        //  EL获得javaBean对象的值
        User user = new User();
        user.setUsername("zhangsan");
        user.setPassword("abc");

        request.setAttribute("user", user);
    %>

    <h1>java</h1>
    username = <%=((User)pageContext.findAttribute("user")).getUsername()%> <br/>
    password = <%=((User)pageContext.findAttribute("user")).getPassword()%> <br/>
    nickname = <%=((User)pageContext.findAttribute("user")).getNickname()%>

    <hr/>

    <h1>EL</h1>
        username === ${user.username} <br/>
        password === ${user.password} <br/>
        nickname === ${user.nickname} <br/>
</body>
</html>

public class User {
    private String username;
    private String password;
    private String nickname;
    //省略构造方法、get、set方法
}

5. EL获得List<String>的值

格式:

${List集合对象[索引]}

代码演示

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %><%--
    EL表达式作用一(从域中取出数据): EL获得 List<String> 的值

    格式: ${ List集合对象[索引] }
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--1.创建 List<String>集合, 存到Request域中 --%>
    <%
        List<String> list = new ArrayList<String>();
        list.add("迪丽热巴");
        list.add("古力娜扎");
        request.setAttribute("list",list);
    %>

    <%--2.通过EL表达式, 获取List<String>集合中的数据--%>
    <%--jsp方式获取--%>
    <%
        List<String> names = (List<String>) request.getAttribute("list");
        out.print( names.get(0) +" === "+ names.get(1) );
    %>
    <%--EL方式获取--%>
    ${list[0]} == ${list[1]}

</body>
</html>

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

6.EL获得List<User>的值

格式:

${List集合对象[索引].成员变量}

代码演示

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="com.itheima.pojo.User" %><%--
    EL表达式作用一(从域中取出数据): EL获得 List<User> 的值

    格式: ${ List集合对象[索引].成员变量 }
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--1.创建 List<User>集合, 存到Request域中 --%>
    <%
        List<User> list = new ArrayList<User>();
        list.add(new User("迪丽热巴","123456"));
        list.add(new User("古力娜扎","abcdef"));
        request.setAttribute("list",list);
    %>

    <%--2.通过EL表达式, 获取 List<User>集合中的数据--%>
    <%--jsp方式获取--%>
    <%
        List<User> users = (List<User>) request.getAttribute("list");
        out.print( users.get(0).getUsername() +"=="+ users.get(0).getPassword() );
        out.print( users.get(1).getUsername() +"=="+ users.get(1).getPassword() );
    %>
    <br/>
    <%--EL方式获取--%>
    ${list[0].username} == ${list[0].password}
    ${list[1].username} == ${list[1].password}

</body>
</html>

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

7.EL获得Map<String,User>的值

格式:

${Map集合对象.key.成员变量}
或
${Map集合对象['key'].成员变量}

代码演示

<%@ page import="java.util.List" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ page import="com.itheima.pojo.User" %>
<%@ page import="java.util.Map" %><%--
    EL表达式作用一(从域中取出数据): EL获得 Map<String, User> 的值

    格式:
        ${Map集合对象.key.成员变量 }
        或
        ${Map集合对象['key'].成员变量}
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <%--1.创建 Map<String, User>集合, 存到Request域中 --%>
    <%
        Map<String, User> userMap = new HashMap<String, User>();
        userMap.put("user1", new User("迪丽热巴","123456"));
        userMap.put("user2", new User("古力娜扎","abcdef"));
        request.setAttribute("userMap",userMap);
    %>

    <%--2.通过EL表达式, 获取 Map<String, User>集合中的数据--%>
    <%--jsp方式获取--%>
    <%
        Map<String, User> map = (Map<String, User>) request.getAttribute("userMap");
        out.print( map.get("user1").getUsername() +"=="+ map.get("user1").getPassword());
        out.print( map.get("user2").getUsername() +"=="+ map.get("user2").getPassword());
    %>
    <br/>
    <%--EL方式获取--%>
    ${userMap.user1.username} == ${userMap.user1.password}
    ${userMap.user2.username} == ${userMap.user2.password}
    <br/>
    ${userMap['user1'].username} == ${userMap['user1'].password}
    ${userMap['user2'].username} == ${userMap['user2'].password}

</body>
</html>

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

4.EL的内置对象pageContext

EL的四大内置对象

  1. applicationScope ServletContext域
  2. sessionScope session域
  3. requestScope request域
  4. pageScope pageContext域

注意

<%pageContext%>指的是pageContext域对象

${pageContext}指的是EL中的一个内置对象

JSP中一共预先定义了9个这样的对象,分别为:request、response、session、application、out、pagecontext、config、page、exception

pageContext : WEB开发中的页面的上下文对象.

作用:可以用来获取JSP中四个域中的数据(pageScope, requestScope, sessionScope, applicationScope)

  • 例如,在Servlet中,想获得web应用的名称:request.getContextPath();
  • 那么,在jsp页面上,想获得web应用的名称:${pageContext.request.contextPath}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>获取WEB应用项目名称</title>
</head>
<body>
    <h3>获取WEB应用项目名称</h3>
    <%--JSP方式获取--%>
    <%= request.getContextPath()%>
    <%--EL方式获取--%>
    ${pageContext.request.contextPath}
</body>
</html>

5.EL执行运算符

  1. 算数运算符 + , - , * , / , %

  2. 逻辑运算符 && , || , !

  3. 比较运算符 > , < , >= , <= , == , !=

  4. Null运算符 empty 判空运算

    如果判断的对象是空,结果为true

    注意:

    1. 容器判断,判断的是长度 ==0 就是空
    2. 基本类型数组,不是判断长度,判断数组容器是否存在
    3. 基本类型数组,判断是空的话只能令他 = null 结果才为true
  5. 三元运算符

    • (布尔表达式)?结果1:结果2

示例代码

<body>
        ${(6>9)?"漂亮":"酷"}
        <br>
        <%
            User user = new User();
            pageContext.setAttribute("user",user);

            String[] str = new String[0];
            request.setAttribute("str",str);

            List<String> list = new ArrayList<String>();
            request.setAttribute("list",list);

            int[] arr = {};
            request.setAttribute("arr",arr);

            Integer[] ar = {};
            request.setAttribute("ar",ar);
        %>
            user对象为空吗:${empty user}<br><%--false--%>
            str数组为空吗:${empty str}<br><%--true--%>
            list集合为空吗:${empty list}<br><%--true--%>
            arr数组为空吗:${empty arr}<br><%--false--%>
            ar包装类数组为空吗:${empty ar}<br><%--true--%>
    </body>

6.案例

记录上一次登录所使用的用户名

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

步骤

  1. 获取提交的用户名密码
  2. 获取是否“记住用户名”
  3. 判断和tom,123 匹配
    1. 如果匹配 重定向到首页
    2. 不匹配 转发回到登录首页;获取cookie中的username值。显示在页面上

示例代码

login首页

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>登录页面</title>
    </head>
    <body>
        <form action="${pageContext.request.contextPath}/login" method="post">
            <%-- 从Cookie中取出  user = tom--%>
            用户名:<input type="text" name="username" value="${cookie.user.value}"><br>
            密的码:<input type="password" name="password"><br>
            <input type="checkbox" name="rem" value="remUsername">记住用户名<br>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

处理记住用户名的操作

  1. 用户名密码的验证
  2. 记录用户名
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 获取用户名和密码
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("tom".equals(username) && "123".equals(password)){
            response.getWriter().write("login ok");
        }else{
            response.getWriter().write("login no");
        }

        // 2.记住用户名
        // 判断是否勾复选框的value值
        String rem = request.getParameter("rem");// remUsername
        System.out.println(rem);
        if(rem != null){
            // 勾选记住用户名
            Cookie cookie = new Cookie("user", username);
            cookie.setMaxAge(60*10);
            cookie.setPath(request.getContextPath());
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

第二章 JSTL的核心标签库使用

1.概述

JSTL(JSP Standard Tag Library),jsp标准标签库,可以嵌入在jsp页面中使用标签的形式完成业务逻辑等功能。jstl出现的目的和EL相同,也是要放在jsp页面中的脚本代码。

JSTL标准标签库有5个子库,但随着发展,目前最常用的是核心库Core

标签库 标签库的URI 前缀
Core http://java.sun.com/jsp/jstl/core c
I18N http://java.sun.com/jsp/jstl/fmt fmt
SQL http://java.sun.com/jsp/jstl/sql sql
XML http://java.sun.com/jsp/jstl/xml x
Functions http://java.sun.com/jsp/jstl/functions fn

2 jstl标签的安装

导入jar包

javax.servlet.jsp.jstl.jar
standard.jar

使用tagelib指令在jsp页面导入要是用的jstl标签库

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

3.常用的jstl标签

jstl目前常用的标签只有if、foreach标签

3.1 if标签

if标签作用:起到java代码判断的作用

if标签的属性介绍:

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

  • test:判断是否执行标签内的内容(true--执行标签中的内容,false,不执行)。
  • var:用来保存test属性结果(使用var属性给他取个名字),这个结果可以保存到制定的web域中,默认保存在pageContext域
  • scope:指定保存数据到哪个web域

示例代码

<%-- if标签的使用--%>
<%@ taglib prefix = "c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ page contentType="text/html;charset=utf-8" language="java"%>
<html>
    <head>
        <title>if标签</title>
    </head>
    <body>
        <%
       	int num = 10;
        pageContext.setAttribute("num",num);
        %>
        <c:if test="${num>5}"> num大于5</c:if>
        <c:if test="${num<=5}">num 小于等于5</c:if>
        
        <%--将判断结果  保存到var属性中,并存到指定的域对象--%>
        <c:if test="${num == 100}" var = "result" scope="request"></c:if>
        <h3>
            取出域对象中的值
        </h3>
        ${result}
    </body>
</html>

3.2 forEach标签 重点

forEach标签作用:起到java代码的for循环作用

forEach标签属性介绍

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

  • var:在不循环对象的时候,保存的是控制循环的变量;在循环对象的时候,保存的是被循环对象中的元素
  • items:指定要循环的对象
  • varStatus:保存了当前循环过程中的信息(循环的开始、结束、步长、次数等)
  • begin:设置循环的开始
  • end:设置循环的结束
  • step:设置步长

小结:

foreach标签:循环,包括传统for和增强for
传统for for(int a = 0;a<10;a++){}
属性:
begin="" 相当于 a=0
end="" 相当于 a<10(包含10)
step="" (步长)相当于 a++
step="2" 相当于 1,3,5...
var = "a" 属性var,定义属性值
含义:将循环次数变量,存储到最小域对象 pageContext中
键名就是a
EL 表达式取出
<c:foreach>
循环体
<c:foreach>

遍历数组,遍历集合
属性:
items:遍历容器
var:遍历的容器中的每个元素,存储在pageContext域对象中
var属性值,就是与对象的键名

varStatus(变量状态属性):
varStatus="vs":会将对象,存在pageContext域中
域对象的键名就是vs
对象,是定义了循环状态的对象
对象中有个属性count,循环的次数

输出循环的次数
int count = 0;
for(String s:str){
    count++;
    System.out.println(s);
}

示例代码

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<body>
    <%--forEach标准循环--%>
    <c:forEach begin="1" end="10" step="1" var="a">
    	<div style="color:red;font-size:28px">
        	div区域 ${pageScope.a}
        </div>
    </c:forEach>
    
    <%--遍历集合--%>
    <%
            String[] strs = {"I","Love","Java"};
            pageContext.setAttribute("strs",strs);
        %>
        <c:forEach items="${strs}" var="s" varStatus="vs">
         <%--EL 在pageContext域中取出键值对,键是s,值是数组元素--%>
        ${s} ${vs.count}<br>
        </c:forEach>
    
     <%--集合,存储User对象--%>
        <%
            List<User> list = new ArrayList<User>();
            User u1 = new User();
            u1.setUsername("张三");
            u1.setPassword("123");

            User u2 = new User();
            u2.setUsername("李四");
            u2.setPassword("456");

            list.add(u1);
            list.add(u2);

            pageContext.setAttribute("list",list);
        %>
        <c:forEach items="${list}" var="s">
            ${s.username} ${s.password}
        </c:forEach>
</body>

第三章 过滤器Filter

1.Filter概念

过滤器:过筛子,符合条件的才能过去,不符合条件的过不去

生活比喻:安检,检查安全的人与物才可以通过放行

程序:客户端需要访问服务器的目标资源,在客户端和服务器资源之间设置过滤器,符合要求放行

2.入门

需求:

  • 浏览器要访问HelloServlet
  • 途径过滤期MyFilter, 若MyFilter放行,可执行访问到HelloServlet; 若不放行,无法访问HelloServlet

执行图解:

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

实现步骤

  1. 编写Servlet, 在web.xml配置Servlet访问路径
  2. 编写Filter,定义类, 实现接口Filter, 实现接口中抽象方法, 在web.xml配置Filter的访问过滤路径

代码:Servlet

@WebServlet(urlPatterns = "/servlet1")
public class Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().write("servlet");
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

代码: MyFilter

import javax.servlet.*;
import java.io.IOException;

/**
* 过滤器的快速入门
 * 1.定义类实现接口 Fileter
 * 2.重写接口中的抽象方法
 * 3.web.xml配置
 * */
public class MyFilter1 implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        //放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

代码: web.xml

 <!-- 配置过滤器  配置方式和servlet  90%一致-->
    <filter>
        <filter-name>myFilter1</filter-name>
        <filter-class>com.zhuxu.fitle.MyFilter1</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>myFilter1</filter-name>
        <!--
            Servlet配置  <url-pattern></url-pattern> 浏览器的访问地址
            Fileter配置  <url-pattern></url-pattern> 过滤器要拦截的资源
        -->
        <url-pattern>/*</url-pattern>
    </filter-mapping>

执行流程

Tomcat服务器启动的时候,读取配置文件web.xml(过滤器的配置)

Tomcat引擎读取完配置文件后,创建对象 FilterChain对象,过滤器链,维护着过滤器和资源之间的顺序

request,response对象在Tomcat引擎创建对象,调用过滤器,层层传递参数,传递到servlet

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

3.Filter的生命周期

1.创建

对象初始化创建,调用方法init(初始化)

方法参数 FilterConfig

Tomcat引擎创建过滤器对象,并调用init传递参数

Tomcat启动的时候,创建过滤器对象

方法参数 FilterConfig,过滤器配置对象

可以获取到过滤器的 名字等等

方法 getServletContext() 获取到最大对象

2.拦截方法

拦截方法doFilter

每次访问要拦截的对象,就运行

访问了,非拦截对象,不运行

3.销毁

对象的销毁方法 destroy()

关闭服务器的时候,过滤器对象销毁

4.Filter的url-pattern配置

1.完全匹配

要过滤的资源 /servlet1

只拦截servlet1,其他资源不拦截 几乎不用

没有必要为一个资源,创建过滤器

<!-- 
    过滤资源,只有hello
    绝对匹配 <url-pattern>/hello</url-pattern>
    只能过滤指定的资源
-->
<url-pattern>/hello</url-pattern>

2.目录匹配

过滤器最常见的配置

一次过滤一大片 /jstl/*

拦截下 jstl目录下的所有资源

<!--
   目录匹配,过滤器中最常见
   /abc/*  过滤abc目录下的所有资源
   一次过滤一片资源
   过滤后台资源 /admin/*
-->
<url-pattern>/admin/*</url-pattern>

3.后缀名匹配

/jstl/* 值拦截后缀名是.jsp

<!-- 
  后缀名匹配,一般不使用
  *.jsp  访问所有jsp文件
-->
<url-pattern>*.jsp</url-pattern>

4.四种拦截形式

默认标签体中写的是REQUEST

  1. 请求拦截:默认配置,拦截客户端发来的请求
  2. 转发拦截:FORWARD Servlet1转发到Servlet2,就会拦截
  3. 包含拦截:INCLUDE 当一个jsp页面包含另一个jsp页面,拦截
  4. 错误拦截:ERROR 程序出现500错误,跳转到一个页面去 拦截

5.注解配置Filter

@WebFilter(urlPatterns="/过滤资源")

@WebFilter("/*")
public class ChinaFilter implements Filter {
    //代码省略...
}
package cn.itcast.web.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

// 方式一
//@WebFilter(urlPatterns = {"/hello.jsp", "/helloServlet"})

// 方式二
// @WebFilter(urlPatterns = {"/hello.jsp"})

// 方式三
// @WebFilter(urlPatterns = "/hello.jsp")

// 方式四
@WebFilter("/hello.jsp")
public class Filter3 implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        // 因为父类不能调用子类的方法,所以向下转型
        HttpServletRequest httpServletRequest = (HttpServletRequest) req;
        String uri = httpServletRequest.getRequestURI();
        System.out.println("执行过滤器3 ... ... 访问的路径: " + uri);

        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

}

6 Filter 处理中文乱码

新建一个拦截器

每次拦截都执行doFilter方法

方法的参数 servletRequest,servletResponse传递到Servlet的doGet方法

过滤器中,设置request对象使用的编码表

所有的Servlet都受益

客户端中文显示设置

servletRequest.setCharacterEncoding("utf-8");

服务器端中文显示设置

servletResponse.setContentType("text/html;charset=utf-8");

代码: ChinaServlet

@WebServlet("/china")
public class ChinaServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        System.out.println("ChinaServlet , 获取请求参数 username = " + username);
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

代码: ChinaFilter

@WebFilter("/*")
public class ChinaFilter implements Filter {

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        //在过滤器中,设置request对象的编码表
        req.setCharacterEncoding("utf-8");
        //设置response缓冲区的编码表,通知浏览器的解码
        resp.setContentType("text/html;charset=utf-8");

        System.out.println("ChinaFilter执行了, 过滤中文,设置编码utf-8");
        chain.doFilter(req, resp);
    }

    public void init(FilterConfig config) throws ServletException {

    }

    public void destroy() {
    }
}

7 过滤器链 FilterChain的执行过程

Filter中的过滤器链 FilterChain: 由Tomcat引擎创建对象

作用: 维护过滤器执行顺序

EL&JSTL&Filter&Listener
day24-EL&JSTL&Filter&Listener
第一章  EL表达式
第二章  JSTL的核心标签库使用
第三章  过滤器Filter
第四章 监听器Listener(了解)

小结: Servlet中doGet方法参数 request, response对象, 由Tomcat引擎创建, 经过多个过滤器一层层传递

8 多个过滤器的先后执行顺序

web.xml配置

和配置文件的编写顺序决定运行的顺序,准确的说法是,根据mapping的顺序决定 (由上到下执行)

注解开发

注解开发没有配置文件的

按照类名的自然顺序决定: A-B-C(不区分大小写) 1 2 3

如果存在配置文件,配置文件优先

9.过滤器案例:登录验证(权限校验)

1.需求

  1. 访问项目的资源。验证是否登录
  2. 如果登陆了,则直接放行
  3. 如果没有登录,则跳转到登录页面,提示“尚未登录,请先登录”

2.实现

1.登录页面 login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>登录页面</title>
    </head>
    <body>
        <!--登录失败的提示信息-->
        ${message}
        <form action="${pageContext.request.contextPath}/login" method="post">
            用户名:<input type="text" name="username"><br>
            密 &nbsp;&nbsp;码:<input type="password" name="password"><br>
            <input type="submit" value="登录">
        </form>
    </body>
</html>

2.登录成功界面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
    <head>
        <title>成功界面</title>
    </head>
    <body>
        <h1>欢迎访问</h1>
    </body>
</html>

3.过滤器

@WebFilter(urlPatterns = "/resource/*")
public class LoginFilter implements Filter {
    /**
     * 登录的过滤,如果登录,直接放行
     * 没有登录,退到登录页面上
     * 客户端是否登录取决于session域对象
     * */
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        // 取出session域对象的值
        // ServletRequest转成子接口
        HttpServletRequest request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse)servletResponse;

        String username = (String) request.getSession().getAttribute("username");
        if (username == null){
            // 没有登录,退到登录页面
            request.setAttribute("message","请先登录,再访问");
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }else{
            // 登录状态直接放行
            filterChain.doFilter(request,response);
        }
    }

    @Override
    public void destroy() {

    }
}

4.Servlet

/**
 * 处理客户端登录的请求
 * 用户名 密码 tom 123
 * 登录验证
 *      登录成功,页面跳转到 resource/welcome.jsp
 *      登录信息存储到session域中
 *
 *      登录失败,回到登录页面去
 * */
@WebServlet(urlPatterns = "/login")
public class LoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String username = request.getParameter("username");
        String password = request.getParameter("password");
        if ("tom".equals(username) && "123".equals(password)){
            // 登陆成功,用户名存储在session
            request.getSession().setAttribute("username",username);
            // 页面跳转到 resource/welcome.jsp
            // 重定向,需要写web应用名称
            response.sendRedirect(request.getContextPath()+"/resource/welcome.jsp");
        }else{
            // 登录失败
            // 回到登录页面,告知用户登录失败,request域存储登录失败的信息
            request.setAttribute("message","登录失败,用户名或者密码输入错误");
            request.getRequestDispatcher("/login.jsp").forward(request,response);
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

第四章 监听器Listener(了解)

1 Listener概述

监听器Listener 是 监听某个组件变化的对象.

  • 事件源是固定的,主要是request, session, servletcontext域对象

  • 监听的是域对象变化

    • 对象的创建和销毁, 域对象中存储的数据变化
  • 第一个维度划分:

    • 监听的域对象request, session, servletcontext

      域对象 监听器
      request ServletRequestListener
      session HttpSessionListener
      servletcontext ServletContextListener
  • 第二个维度划分:

    • 监听的域对象的状态

2 ServletContext监听器入门

用于监听 servletcontext域对象, 对象的创建和销毁, 域对象中存储的数据变化

实现步骤

  • 创建类实现监听器接口 ServletContextListener
  • 重写抽象方法
  • 注解方式 配置 Listener
@WebListener
public class MyServletContextListener implements ServletContextListener {
    @Override
    /**
     *  ServletContext对象,被创建,调用
     */
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext域对象创建");
    }

    @Override
    /**
     *   ServletContext对象,被销毁前调用
     */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext域对象销毁");
    }
}
  • web.xml配置方式 Listener
<listener>
    <listener-class>com.itheima.listener.MyServletContextListener</listener-class>
</listener>

3 监听器事件对象 ServletContextEvent

ServletContextEvent: 是ServletContext域对象的事件对象, 此对象由tomcat引擎创建ServletContext

  • 方法:
    • Object getSource() 获取到被监听的事件源
    • ServletContext getServletContext() 获取到被监听的事件源
  • 小结:
    • 两个方法 除了返回值外,功能实现是一致的, 设计目的为了通用性
    • 其他的监听器事件对象(HttpSessionEvent, ServletRequestEvent), 都有共同的方法 getSource()
@WebListener
public class MyServletContextListener implements ServletContextListener {
    @Override
    /**
     *  ServletContext对象,被创建,调用
     */
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext域对象创建");
        ServletContext context = (ServletContext) servletContextEvent.getSource();
        System.out.println(context);

        ServletContext servletContext = servletContextEvent.getServletContext();
        System.out.println(servletContext);
    }

    @Override
    /**
     *   ServletContext对象,被销毁前调用
     */
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("ServletContext域对象销毁");
    }
}

4 注解版

package cn.itcast.listener;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;

// 每次请求都会创建一个新的request对象; 当响应结束后,立刻销毁request对象
@WebListener
public class MyRequestListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent servletRequestEvent) {
        ServletRequest servletRequest = servletRequestEvent.getServletRequest();
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        System.out.println("新的request对象创建了 .... ... 路径: " + httpServletRequest.getRequestURI());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent servletRequestEvent) {
        System.out.println("request对象销毁了 .... ...");
    }

}

重点 Servlet抽取源

如 登录 注册 ....

首页

<html>
<head>
    <title>Title</title>
    <style>
        body{
            font-size: 20px;
        }
    </style>
</head>
<body>
    <%--
      每个超链接上添加参数,告知服务器,我要做什么
    --%>
    <a href="${pageContext.request.contextPath}/user?operator=login">登录</a> <br>
    <a href="${pageContext.request.contextPath}/user?operator=register">注册</a> <br>
    <a href="${pageContext.request.contextPath}/user?operator=updatePassword">改密</a> <br>
    <a href="${pageContext.request.contextPath}/user?operator=findPassword">找回密码</a> <br>

</body>
</html>

处理请求操作

/**
 * 所有的客户端的用户操作请求
 * 我来实现
 * */
@WebServlet(urlPatterns = "/user")
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {


        // 获取客户端超链接的参数
     /*   String operator = request.getParameter("operator");
        if ("login".equals("operator")){
            login();
        }else if ("register".equals(operator)){
            register();
        }else if ("updatePassword".equals(operator)){
            updatePassword();
        }*/
        // 优化
        String operator = request.getParameter("operator");
        // 反射,获取客户端参数  opreator 是方法名
        try {
            Class cla = this.getClass();
            // 获取方法
            Method method = cla.getMethod(operator,HttpServletResponse.class,HttpServletResponse.class);
            method.invoke(this,request,response);
        }catch (Exception exception){
            exception.printStackTrace();
        }
    }

    // 方法处理登录
    public void login(HttpServletRequest request, HttpServletResponse response){
        System.out.println("处理登录的方法");
    }

    // 方法处理注册
    public void register(HttpServletRequest request, HttpServletResponse response){
        System.out.println("处理注册的方法");
    }

    // 方法处理改密
    public void updatePassword(HttpServletRequest request, HttpServletResponse response){
        System.out.println("处理修改密码的方法");
    }
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}