EL&JSTL&Filter&Listener

day24-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>

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>

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>

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.案例

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

步骤

  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标签的属性介绍:

1568524664183

  • 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标签属性介绍

1568524714801

  • 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

执行图解:

实现步骤

  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

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引擎创建对象

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

1568641974893

小结: 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);
    }
}

原文地址:https://www.cnblogs.com/anke-z/p/13269087.html