EL 表达式

  • EL (Expression Language): 表达式语言.
  • 在JSP 2.0规范中加入的内容, 也是Servlet规范的一部分.
  • 作用: 在JSP页面中获取数据. 让我们的JSP脱离java代码块和JSP表达式
<%--请求域中添加username数据--%>
<% request.setAttribute("username","zhangsan"); %>

<%--获取请求域的username 3种方式--%>

<%--Java代码块--%>
<% out.println(request.getAttribute("username")); %> <br/>

<%--JSP表达式获取--%>
<%= request.getAttribute("username")%> <br/>

<%--EL表达式获取--%>
${username}

EL 表达式获取数据类型

  • 获取基本数据类型的数据
  • 获取自定义对象类型的数据
  • 获取数组类型的数据
  • 获取List集合类型的数据
  • 获取Map集合类型的数据
<%@ page import="com.lizicai.bean.Student" %>
<%@ page import="java.util.ArrayList" %>
<%@ page import="java.util.HashMap" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<% pageContext.setAttribute("num",10); %>
基本数据类型 ${num} <br/>

<% Student stu = new Student("李明", 23);
pageContext.setAttribute("stu",stu);
%>
自定义对象: ${stu} <br/>
${stu.name}
${stu.age}  <br/>

<%
    String[] arr = {"Haha", "go"};
    pageContext.setAttribute("arr",arr);
%>

数组: ${arr} <br/>
${arr[0]} ${arr[1]} ${arr[2]} <br/>


<%
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    pageContext.setAttribute( "list",list);
%>
List集合 ${list}  ${list[0]} <br/>

<%
    HashMap<String, Student> map = new HashMap<>();
    map.put("s01",new Student("李明",20));
    map.put("s02",new Student("张三",20));
    pageContext.setAttribute( "map",map);
%>
Map 集合: ${map} <br/>
第一个学生 ${map.s01} <br>
第一个学生的姓名 ${map.s01.name} <br>
</body>
</html>

EL 表达式注意事项

  • EL 表达式没有空指针异常
  • EL 表达式没有索引越界异常
  • EL 表达式没有字符串的拼接
<%
    Student s = null;
    String [] arr2 = {"Hello", "World"};
    pageContext.setAttribute( "s",s);
    pageContext.setAttribute( "arr2",arr2);
%>
${s}
${arr2[10]}
${arr2[0]}+${arr2[1]}

EL 表达式运算符

  • 关系运算符
关系运算符 作用     示例 结果
==或eq     等于     略   略
!=或ne     不等于   略   略
<或lt      小于     略   略
>或gt      大于     略   略
<=或le     小于等于 略   略
>=或ge     大于等于 略   略
  • 逻辑运算符
运算符  作用 示例 结果
&&或and 并且 略   略
||或or  或者 略   略
!或not  取反 略   略
  • 其他运算符
运算符               作用
empty                1判断对象是否为null.2判断字符串是否为空字符串.3判断窗口元素是否为0
条件?表达式1:表达式2 三元运算符
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>EL 表达式运算符</title>
</head>
<body>
<%
    String ss = null;
    String ss2 = "";
    int[] arr = {};
%>
${empty ss} <br/>
${empty ss2} <br/>
${empty arr} <br/>

<% pageContext.setAttribute("gender", "man"); %>
<input type="radio" name="gender" value="man" ${gender == "man" ? "checked" : ""}> 男
<input type="radio" name="gender" value="woman" ${gender == "woman" ? "checked" : ""}> 女
</body>
</html>

EL 表达式使用细节

  • EL 表达式能够获取四大域对象的数据, 根据名称从小到大在域对象中查找.
  • 还可以获取JSP其他八个隐式对象, 并调用对象中的方法.
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%
    pageContext.setAttribute("username", "zhangsan1");
    request.setAttribute("username", "zhangsan2");
    session.setAttribute("username", "zhangsan3");
    application.setAttribute("username", "zhangsan4");
%>
${username} <br>

<%= request.getContextPath() %>
${pageContext.request.contextPath}

</body>
</html>

EL 表达式隐式对象

隐式对象名称     对应JSP隐式对象 说明
pageContext      pageContext     功能完全相同
applicationScope 没有            操作应用域对象数据
sessionScope     没有            操作会话域对象数据
requestScop      没有            操作请求域对象数据
pageScope        没有            操作页面域对象数据
header           没有            操作请求头数据
headerValues     没有            获取请求头数据(多个值)
param            没有            获取请求参数数据
paramValues      没有            获取请求参数数据(多个值)
initParam        没有            获取全局配置参数数据
cookie           没有            获取Cookie 对象
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

<%-- pageContext 对象, 可以获取其他3个域对象和JSP中八个隐式对象--%>
${pageContext.request.contextPath} <br/>

<%--applicationScope sessionScope requestScop pageScope--%>
<% request.setAttribute("username", "zhangsan1"); %>
<% pageContext.setAttribute("username", "zhangsan2"); %>
${username} <br/>
${requestScope.username} <br/>
${pageScope.username} <br/>

<%--header headerValues 获取的数组--%>
${header["connection"]} <br>
${headerValues["connection"][0]} <br>


<%--param paramValues 获取请求参数--%>
${param.username} <br/>
${paramValues.hobby[0]} <br/>
${paramValues.hobby[1]} <br/>


<%--initParam 获取全局配置参数--%>
${initParam.pname} <br>


<%--cookie--%>
${cookie} <br>
${cookie.JSESSIONID} <br>  <%-- 获取集合元素--%>
${cookie.JSESSIONID.name} <br> <%-- 获取cookie对象的名称 --%>
${cookie.JSESSIONID.value} <br>  <%-- 获取cookie对象的数据值 --%>

</body>
</html>

JSTL 介绍

  • JSTL (Java Servler Pages Standarded Tag Library): JSP标准标签库
  • 主要提供给开发人员一个标准通用的标签库
  • 开发人员可以利用这些标签取代JSP页面上的Java代码, 从而提高程序的可读性, 降低程序的维护难度.
组成      作用       说明
core      核心标签库 通用的逻辑处理
fmt       国际化     不同地域显示不同语言
functions EL函数     EL表达式可以使用的方法
sql       操作数据库 了解
xml       操作XML    了解
  • JSTL 核心标签库
标签名称           功能分类         属性       作用
<标签名:if>        流程控制         核心标签库 用于条件判断
<标签名:choose>    ifelseif流程控制 核心标签库 用于多条件判断
<标签名:when>      ifelseif流程控制 核心标签库 用于多条件判断
<标签名:otherwise> ifelseif流程控制 核心标签库 用于多条件判断
<标签名:forEach>   迭代遍历         核心标签库 用于循环遍历

http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/解压lib的包导入tomcatlib中

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="ss" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>JSTL演示</title>
</head>
<body>
${pageContext.setAttribute("score","A")}
<ss:if test="${score eq 'F'}">
    优秀
</ss:if>

<ss:choose>
    <ss:when test="A">优</ss:when>
    <ss:when test="B">良</ss:when>
    <ss:when test="C">及格</ss:when>
    <ss:otherwise>成绩不合法</ss:otherwise>
</ss:choose>
</body>
</html>
<%@ taglib prefix="ss" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page import="java.util.ArrayList" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<%
    ArrayList<String> list = new ArrayList<>();
    list.add("aaa");
    list.add("bbb");
    list.add("ccc");
    list.add("ddd");
    pageContext.setAttribute("list",list);
%>
<ss:forEach  items="${list}" var="str">
    ${str} <br>
</ss:forEach>

</body>
</html>

过滤器介绍

  • 在程序中访问服务器资源时, 当一个请求到来, 服务器首先判断是否有过滤器与请求资源相关联
  • 如果有, 过滤器可以将请求拦截下来, 完成一些特定的功能, 再由过滤器决定是否交给请求资源
  • 如果没有, 则像之前那样直接请求资源了. 响应也是类似
  • 过滤器一般用于完成通用的操作, 例如: 登录验证, 统一编码处理,敏感字符过滤等等``````

Filter

  • Filter 是一个接口. 如果想实现过滤器的功能, 必须实现该接口
  • 核心方法
返回值 方法名                                                                      作用
void   init(FilterConfig.filterConfig)                                             初始化方法
void   doFilter(ServletRequest.request,ServletResponse.response,FilterChain.chain) 对请求资源和响应资源过滤
void   destroy()                                                                   销毁方法
  • 配置方法
    • 注解方式
    • 配置文件

FilterChain

  • FilterChain 是一个接口, 代表过滤器链对象. 由Servlet容器提供实现类对象. 直接使用即可.
  • 过滤器可以定义多个, 就会组成过滤器链
  • 核心方法
返回值 方法名 作用
void doFilter(ServletRequest.request,ServletResponse.response) 放行方法

如果有多个过滤器, 在第一个过滤器中调用下一个过滤器, 依次类推. 走到访问最终资源 如果只有一个过滤器, 放行时, 就会直接到达最终访问资源

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet ( value = "/demo1Filter")
public class Demo1Filter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Demo1Filter 执行了...");
        resp.getWriter().write("Demo1Filter 执行了...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

@WebFilter("/*")
public class Filter implements javax.servlet.Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filte");

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

        filterChain.doFilter(servletRequest,servletResponse);
    }
}

过滤器使用细节

  • 配置方式
    • 注解方式 @WebFilter(拦截路径)
    • 配置文件方式
<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.lizicai.filter.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/demo2Filter</url-pattern>
</filter-mapping>
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet ( value = "/demo2Filter")
public class Demo2Filter extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("Demo2Filter 执行了...");
        resp.getWriter().write("Demo2Filter 执行了...");
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

public class Filter2 implements javax.servlet.Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("Filte");

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

        filterChain.doFilter(servletRequest,servletResponse);
    }
}
  • 多个过滤器使用顺序
    • 如果有多个过滤器, 取决于过滤器映射的顺序
<filter>
    <filter-name>filter2</filter-name>
    <filter-class>com.lizicai.filter.Filter2</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter2</filter-name>
    <url-pattern>/demo2Filter</url-pattern>
</filter-mapping>
<filter>
    <filter-name>filter3</filter-name>
    <filter-class>com.lizicai.filter.Filter3</filter-class>
</filter>
<filter-mapping>
    <filter-name>filter3</filter-name>
    <url-pattern>/demo3Filter</url-pattern>
</filter-mapping>

过滤器生命周期

  • 创建
    • 当应用加载时实例化对象并执行init初始化方法
  • 服务
    • 对象提供服务的过程, 执行doFilter方法
  • 销毁
    • 当应用卸载时或服务器停止时对象销毁. 执行detory()方法.
import javax.servlet.*;
import javax.servlet.Filter;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * 过滤器生命周期
 */

@WebFilter("/demo3Filter")
public class Filter3 implements javax.servlet.Filter {

    /**
     * 初始化方法
     * @param filterConfig
     * @throws ServletException
     */
    @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("Filte");

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

        filterChain.doFilter(servletRequest,servletResponse);
    }

    /**
     * 对象销毁
     */
    @Override
    public void destroy() {
        System.out.println("对象销毁了");
    }
}

FilterConfig 介绍

  • FilterConfig是一个接口. 代表过滤器的配置对象, 可以加载一此初始化参数.
  • 核心方法
返回值              方法名                        作用
String              getFilterName()               获取过滤器对象名称
String              getInitParameter(String.name) 根据key获取value
Enumeration<String> getInitParameterNames()       获取所有参数的key
ServletContext      getServletContext()           获取应用上下文对象
<filter>
    <filter-name>filter4</filter-name>
    <filter-class>com.lizicai.filter.Filter4</filter-class>
    <init-param>
        <param-name>username</param-name>
        <param-value>xiaoming</param-value>
    </init-param>
</filter>
    <filter-mapping>
    <filter-name>filter4</filter-name>
    <url-pattern>/demo4Filter</url-pattern>
</filter-mapping>

过滤器五种拦截行为

  • Filter过滤器默认拦截的是请求, 但是在实际开发中, 我们还有请求转发和请求包含, 以及由服务器触发的全局错误页面.
  • 默认情况下过滤器是不参与过滤的, 要想使用, 就需要我们配置
  • 拦截方式
    <filter>
        <filter-name>filter5</filter-name>
        <filter-class>com.lizicai.filter.Filter5</filter-class>
        <async-supported>true</async-supported>
    </filter>
    <filter-mapping>
        <filter-name>filter5</filter-name>
        <url-pattern>/index.jsp</url-pattern>

<!--        过滤请求, 默认值-->
        <dispatcher>REQUEST</dispatcher>

<!--        过滤全局错误页面-->
        <dispatcher>ERROR</dispatcher>

<!--        过滤转发-->
        <dispatcher>FORWARD</dispatcher>

<!--        当请求包含时, 过滤器工作, 只能过滤动态包含. JSP 的include是静态包含, 过滤器不会过滤-->
        <dispatcher>INCLUDE</dispatcher>

<!--        过滤异步类型, 它要求我们在filter标签中配置开启异步支持-->
        <dispatcher>ASYNC</dispatcher>
    </filter-mapping>
    <error-page>
        <exception-type>java.lang.Exception</exception-type>
        <location>/error.jsp</location>
    </error-page>
    <error-page>
        <error-code>404</error-code>
        <location>/error.jsp</location>
    </error-page>

监听器介绍

  • 观察者设计模式, 所有的监听器都是基于观察者设计模式的
  • 三个组成部分
    • 事件源: 触发事件的对象
    • 事件: 触发的动作, 封装了事件源
    • 监听器: 当事件源触发事件后, 可以完成功能
  • 在程序当中, 我们可以地: 对象的创建销毁, 域对象中属性的变化, 会话相关内容进行监听
  • Servlet 规范中共计8个监听器, 监听器都是以接口形式提供, 具体功能需要我们自己来完成.

监听对象的监听器

  • ServletContextListener: 用于咋啦ServletContext对象的创建和销毁
  • 核心方法
返回值 方法名                                      作用
void   contextInitialized(ServletContextEvent.sce) 对象创建时执行该方法
void   contextDestroyed(ServletContextEvent.sce)   对象销毁时执行该方法

参数: ServletContextEvent代表事件对象

事件对象中封装了事件源,也就是ServletContext

真正的事件指的是创建或销毁ServletContext对象的操作

  • HttpSessionListener: 用于监听HttpSession对象的创建和销毁
  • 核心方法
返回值 方法名                                作用
void   sessionCreated(HttpSessionEvent.se)   对象创建时执行该方法
void   sessionDestroyed(HttpSessionEvent.se) 对象销毁时执行该方法

参数: Httpsessionevent代表事件对象

事件对象中封装了事件源,也就是Httpsession

真正的事件指的是创建或销毁Httpsession对象的操作

  • ServletRequesListener: 用于监听ServletRequest对象的创建和销毁
  • 核心方法
返回值 方法名                                      作用
void   requestInitialized(ServletRequestEvent.sre) 对象创建时执行该方法
void   requestDestroyed(ServletRequestEvent.sre)   对象销毁时执行该方法

参数: ServletRequestEvent代表事件对象

事件对象中封装了事件源,也就是ServletRequest

真正的事件指的是创建或销毁ServletRequest对象的操作

监听域对象属性变化的监听器

  • ServletContextAttributeListener: 用于监听ServletContext应用域属性的变化
  • 核心方法
返回值 方法名                                               作用
void   attributeAdded(ServletContextAttributeEvent.scae)    域中添加属性时执行该方法
void   attributeRemoved(ServletContextAttributeEvent.scae)  域中移除属性时执行该方法
void   attributeReplaced(ServletContextAttributeEvent.scae) 域中替换属性时执行该方法

参数: ServletContextAttributeEvent代表事件对象

事件对象中封装了事件源,也就是ServletContext

真正的事件指的添加, 移除, 替换应用域中属性的操作

  • HttpSessionAttributeListenen: 用于监听HttpSession会话域中属性的变化
  • 核心方法
返回值 方法名                                        作用
void   attributeAdded(HttpSessionBindingEvent.se)    域中添加属性时执行该方法
void   attributeRemoved(HttpSessionBindingEvent.se)  域中移除属性时执行该方法
void   attributeReplaced(HttpSessionBindingEvent.se) 域中替换属性时执行该方法

参数: HttpSessionBindingEvent代表事件对象

事件对象中封装了事件源,也就是HttpSession

真正的事件指的添加, 移除, 替换会话域中属性的操作

  • ServletRequestAttributeListener: 用于监听ServletRequest请求域中属性的变化
  • 核心方法
返回值 方法名                                               作用
void   attributeAdded(ServletRequestAttributeEvent.srae)    域中添加属性时执行该方法
void   attributeRemoved(ServletRequestAttributeEvent.srae)  域中移除属性时执行该方法
void   attributeReplaced(ServletRequestAttributeEvent.srae) 域中替换属性时执行该方法

参数: ServletRequestAttributeEvent代表事件对象

事件对象中封装了事件源,也就是ServletRequest

真正的事件指的添加, 移除, 替换请求域中属性的操作

监听会话相关的感知型监听器

  • HttpSessionBindingListener: 用于感知对象和会话域绑定的监听器
  • 核心方法
返回值 方法名                                      作用
void   valueBound(HttpSessionBindingEvent.event)   数据添加到会话域中(绑定)时执行该方法
void   valueUnBound(HttpSessionBindingEvent.event) 数据从会话域移除(解绑)时执行该方法

参数: HttpSessionBindingEvent 代表事件对象

事件对象中封装了事件源, 也就是HttpSession

真正的事件指的是添加, 移除会话域中数据的操作

  • HttpSessionActivationListener: 用于感知会话域中对象钝化和活化的监听器
  • 核心方法
返回值 方法名                                    作用
void   sessionWillPassivate(HttpSessionEvent.se) 会话域中数据钝化时执行该方法
void   sessionWillActivate(HttpSessionEvent.se)  会话域中数据活化时执行该方法

参数: HttpSessionEvent代表事件对象

事件对象中封装了事件源, 也就是HttpSession

真正的事件指的是会话域中数据钝化, 活化的操作

监听器的使用

  • 监听对象的
    • ServletContextListener
    • HttpSessionListener
    • ServletRequestListener
  • 监听属性变化的
    • ServletContextAttributeListener
    • HttpSessionAttributeListener
    • ServletRequestAttributeListener
  • 会话相关的感知
    • HttpSessionBindingListener
    • HttpSessionActivationListener
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ServletContextListenerDemo implements ServletContextListener {
    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("监听到对象的创建...");
        ServletContext servletContext = sce.getServletContext();
        System.out.println(servletContext);
        // 更改ServletContext 属性监听
        servletContext.setAttribute("username", "zhangsan");

        servletContext.setAttribute("username","liming");

        servletContext.removeAttribute("username");
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("监听到对象的销毁...");

    }
}
import javax.servlet.ServletContext;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class ServletContextAttributeListenerDemo implements ServletContextAttributeListener {
    @Override
    public void attributeAdded(ServletContextAttributeEvent event) {
        System.out.println("监听到应用域对象添加...");
        ServletContext servletContext = event.getServletContext();
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }

    @Override
    public void attributeRemoved(ServletContextAttributeEvent event) {
        System.out.println("监听到应用域对象删除...");
        ServletContext servletContext = event.getServletContext();
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }

    @Override
    public void attributeReplaced(ServletContextAttributeEvent event) {
        System.out.println("监听到应用域对象替换...");
        ServletContext servletContext = event.getServletContext();
        Object value = servletContext.getAttribute("username");
        System.out.println(value);
    }
}

配置文件方式

<listener>
    <listener-class>com.lizicai.listener.ServletContextAttributeListenerDemo</listener-class>
</listener>
<listener>
    <listener-class>com.lizicai.listener.ServletContextListenerDemo</listener-class>
</listener>

学生管理系统优化

  • 解决乱码
    • 使用过滤器实现所有资源的编码统一
  • 检查登录
    • 使用过滤器实现校验是否登录问题
  • 优化JSP页面
    • 通过EL表达和JSTL替换之前的Java代码块和JSP表达式
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter("/*")
public class FilterEncodingUTF8 implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//        请求和响应对象转换为 HTTP 协议相关
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

//        设置编码格式
        request.setCharacterEncoding("UTF-8");
        response.setContentType("text/html;charset=UTF-8");

//        放行
        filterChain.doFilter(request,response);
    }
}
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter( value = {"/addStudent.jsp", "/listStudent.jsp"})
public class FilterLogin implements Filter {
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//        1. 请求和响应对象转换为 HTTP 协议相关
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

//        2. 获取会话域对象中数据
        Object name = request.getSession().getAttribute("username");

//        3. 判断用户名
        if( name == null || "".equals(name)){
//            resp.setContentType("text/html;charset=UTF-8");
            response.getWriter().write("未登录, 跳转到登录页面...");
            response.setHeader("Refresh", request.getContextPath()+"2;URL=/stuLogin.jsp");
            return;
        }

//        放行
        filterChain.doFilter(request,response);

    }
}

最后一个优化, 项目是03_JavaWeb_test4