JavaWeb学习笔记(二)
概述
JavaEE阶段有三个大组件:Jsp/Servlet、Filter、Listener
一个普通的Java类继承了实现Servlet接口的实现类(HttpServlet),称为Servlet,JSP就是Servlet
一、过滤器(Filter)
1.1 过滤器图解
一个普通的Java类实现了一个Servlet API提供的Filter接口的实现类,称为Filter。过滤器是比较核心的技术,它可以对WEB服务器中所有的WEB资源(动态、静态)进行管理,例如:JSP/Servlet、静态资源(HTML/JS/CSS/图片)、文件(上传的文件)资源
可以对请求和响应的资源进行“拦截”(需要自己设置拦截的规则),拦截之后我可以实现一些特殊的功能。
1.2过滤器配置
过滤器的配置过程,跟Servlet的配置过程是类似,也有两种版本:web.xml中<filter>
注册和@WebFilter
注册,可以定义拦截规则。
(1)新建一个普通的Java类,实现Filter接口,必须要实现doFilter方法,其他方法为接口默认方法
过滤器使用 FilterChain 调用链中的下一个过滤器,如果调用的过滤器是链中的最后一个过滤器,则调用链末尾的资源。
package com.yu.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/07/05/7:16
* @Description:
*/
public class Demo01Filter implements Filter {
public Demo01Filter(){
System.out.println(Demo01Filter.class+"构造方法..创建对象...什么时候实例化");
}
/*doFilter方法必须要实现*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(Demo01Filter.class+"...执行特殊功能的代码..."+Math.random());
System.out.println("<---"+Demo01Filter.class+"前");
/*设置放行*/
filterChain.doFilter(servletRequest,servletResponse);//访问下一个过滤器或资源
System.out.println("--->"+Demo01Filter.class+"后");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(Demo01Filter.class+"对成员变量进行初始化操作...赋值");
/*取xml中配置的初始值*/
System.out.println(filterConfig.getInitParameter("name"));//初语
System.out.println(filterConfig.getInitParameter("age"));//18
System.out.println(filterConfig.getInitParameter("world"));//没有配置:null
}
@Override
public void destroy() {
System.out.println(Demo01Filter.class+"...关闭服务器进行销毁");
}
}
(2)在web.xml
中进行配置,过滤器的注册
和配置拦截的规则
<?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>
<filter-name>Demo01Filter</filter-name>
<filter-class>com.yu.filter.Demo01Filter</filter-class>
<!--在xml文件中进行初始化赋值-->
<init-param>
<param-name>name</param-name>
<param-value>初语</param-value>
</init-param>
<init-param>
<param-name>age</param-name>
<param-value>18</param-value>
</init-param>
</filter>
<!--设置拦截规则-->
<filter-mapping>
<filter-name>Demo01Filter</filter-name>
<!--
可使用通配符:
/*:所有的请求都会被该过滤器进行处理
/sys/*:所有以sys开头的请求都会被该过滤器处理
*.jsp *.html *.xxx:特殊(不是"/"开头),所有以后缀名jsp,html等等(自己设置)结尾的请求都会被该过滤器处理
/1.jpg:只有当访问的是具体的1.jpg的时候会被该过滤器处理
-->
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
过滤规则:
/*
:所有的请求都会被该过滤器进行处理/sys/*
:所有以sys开头的请求都会被该过滤器处理*.jsp *.html *.xxx
:特殊(不是"/"开头),所有以后缀名jsp,html等等(自己设置)结尾的请求都会被该过滤器处理/1.jpg
:只有当访问的是具体的1.jpg的时候会被该过滤器处理
注意:
过滤器在服务器启动的时候,进行实例化和初识化数据操作,所以,过滤器错误,服务器无法使用
测试index.jsp文件:
<%--
Created by IntelliJ IDEA.
User: Administrator
Date: 2021/7/5
Time: 7:09
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<meta charset="UTF-8">
<title>$Title$</title>
</head>
<body>
<%
System.out.println("index.jsp页面");
%>
<h3 style="color: cyan">晓看天色暮看云</h3>
<h3 style="color: pink">行也思君</h3>
<h3 style="color: pink">坐也思君</h3>
</body>
</html>
未放行前:(访问服务器空白,不显示index内容)
设置放行后:
1.3 拦截规则
(1)设置多个拦截规则
package com.yu.filter;
import javax.servlet.*;
import java.io.IOException;
/**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/07/05/7:16
* @Description:
*/
public class Text02Filter implements Filter {
public Text02Filter(){
System.out.println(Text02Filter.class+"构造方法..创建对象...什么时候实例化");
}
/*doFilter方法必须要实现*/
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(Text02Filter.class+"...执行特殊功能的代码..."+Math.random());
System.out.println("<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>"+ Text02Filter.class+"前");
/*设置放行*/
filterChain.doFilter(servletRequest,servletResponse);//访问下一个过滤器或资源
System.out.println("<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>"+ Text02Filter.class+"后");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println(Text02Filter.class+"对成员变量进行初始化操作...赋值");
}
@Override
public void destroy() {
System.out.println(Text02Filter.class+"...关闭服务器进行销毁");
}
}
配置文件:
<filter>
<filter-name>Text02Filter</filter-name>
<filter-class>com.yu.filter.Text02Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Text02Filter</filter-name>
<!--只要访问Example01Servlet就会被过滤器处理-->
<servlet-name>Example01Servlet</servlet-name>
<!--<url-pattern>/sys/*</url-pattern>
<url-pattern>*.php</url-pattern>-->
</filter-mapping>
servlet代码:
package com.yu.servlet; /**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/07/05/8:13
* @Description:
*/
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
@WebServlet(name = "Example01Servlet",
value = {"/sys/example01",
"/view/example01",
"/example01.html",
"/sys/example.php",
"/example.asp"
})
public class Example01Servlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(request.getRequestURI());
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("<h3>访问路径:"+request.getRequestURI()+"</h3>");
out.close();
}
}
1.3.1关于跳转方式启动过滤器
package com.yu.filter;
import javax.servlet.*;
import java.io.IOException;
public class Test03Filter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println(Test03Filter.class+"*************************************"+Math.random());
filterChain.doFilter(servletRequest,servletResponse);/*访问下一个过滤器或者资源*/
}
}
xml:
<filter>
<filter-name>Test03Filter</filter-name>
<filter-class>com.yu.filter.Test03Filter</filter-class>
</filter>
<!-- 设置多个拦截规则 -->
<filter-mapping>
<filter-name>Test03Filter</filter-name>
<url-pattern>/user/*</url-pattern>
</filter-mapping>
结果:先执行过滤器,后访问资源
1.3.2改造过滤器的配置:只有请求转发的跳转才能触发过滤器
<filter>
<filter-name>Test03Filter</filter-name>
<filter-class>com.yu.filter.Test03Filter</filter-class>
</filter>
<!-- 设置多个拦截规则 -->
<filter-mapping>
<filter-name>Test03Filter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
结果:请求转发的跳转才触发过滤器
1.4 常用的过滤器
- 解决POST请求中文的编码过滤器
- 登录过滤器(Session过滤器)
- 日志过滤器等等
(1)约定不允许直接访问JSP页面,解决方法:WEB-INF文件夹下就可以
package com.yu.filter; /**
* Created with IntelliJ IDEA.
*
* @Author: 鱼
* @Date: 2021/07/05/9:52
* @Description:
*/
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@WebFilter(filterName = "JSPFilter",urlPatterns = "/*")
public class JSPFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
//对象下转型
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
//获取请求的路径
String path = request.getRequestURI();
if (path.endsWith(".jsp")){//字符串匹配:以.jsp结尾
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.write("<h3>不知道写什么,不允许直接访问jsp页面</h3>");
out.close();
}else{
chain.doFilter(request, response);
}
}
}
(2)编码过滤器,针对于POST请求,都需设置request.setCharacterEncoding("UTF-8");
package com.yu.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "EncodingFilter",value = "/*")
public class EncodingFilter implements Filter {
private static final String METHOD = "POST";
private static final String ENCODING = "UTF-8";
private static final String CONTENT_TYPE_ENCODING = "text/html;charset=UTF-8";
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//对象下转型,使用子类中新增的方法
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//获取请求的方式
String method = request.getMethod();
if(METHOD.equalsIgnoreCase(method)){//是否为post请求
request.setCharacterEncoding(ENCODING);//解决POST请求中文乱码问题
}
response.setContentType(CONTENT_TYPE_ENCODING);
chain.doFilter(req, resp);
}
}
(3)登录过滤器,有一些WEB资源只有用户登录之后才能访问
lastIndexOf
方法:如果要检索的字符串值没有出现,则该方法返回 -1。
package com.yu.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@WebFilter(filterName = "SessionFilter",value = "/*")
public class SessionFilter implements Filter {
private static final String LOGIN_URL = "/sys/login";
private static final String SESSION_KEY = "session_user";
private static List<String> excludeStaticPathList = new ArrayList<>();
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest)req;
HttpServletResponse response = (HttpServletResponse)resp;
//获取HttpSession对象
HttpSession session = request.getSession();
//获取请求的路径并且获取有后缀的字符串
String path = request.getRequestURI();
String ext = null;
int index = path.lastIndexOf(".");
if(index!=-1){
ext = path.substring(index);//获取的后缀名是从.开始截取
}
if(path.endsWith(LOGIN_URL)||excludeStaticPathList.contains(ext)){//设置哪些请求不检查session
chain.doFilter(req, resp); //允许访问,放行
}else{
if(session.getAttribute(SESSION_KEY)==null){//没有登录,回到登录页面,重定向
response.sendRedirect(request.getContextPath()+LOGIN_URL);
return;
}
chain.doFilter(req, resp); //用户已经登录,可以访问资源
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
excludeStaticPathList.add(".html");
excludeStaticPathList.add(".js");
excludeStaticPathList.add(".css");
excludeStaticPathList.add(".png");
excludeStaticPathList.add(".jpg");
excludeStaticPathList.add(".jpeg");
excludeStaticPathList.add(".gif");
excludeStaticPathList.add(".dmp");
}
}
二、监听器(Listener)
监听器使用的设计模式是观察者设计模式(单例设计模式、模版设计模式、代理设计模式),监听器是监听WEB域(HttpServletRequest、HttpSession、ServletContext)的创建和销毁,以及属性的操作的行为。
package com.yu.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class ApplicationListener implements ServletContextListener, ServletContextAttributeListener {
@Override
public void attributeAdded(ServletContextAttributeEvent scae) {
System.out.println("ServletContext添加属性:"+scae.getServletContext().getAttribute("bookName"));
}
@Override
public void attributeRemoved(ServletContextAttributeEvent scae) {
System.out.println("ServletContext移除属性:"+scae.getServletContext().getAttribute("bookName"));
}
@Override
public void attributeReplaced(ServletContextAttributeEvent scae) {
System.out.println("ServletContext修改属性:"+scae.getServletContext().getAttribute("bookName"));
}
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("创建ServletContext对象:"+sce.getServletContext());
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("服务器关闭,销毁ServletContext对象:"+sce.getServletContext());
}
}
<listener>
<listener-class>com.yu.listener.ApplicationListener</listener-class>
</listener>
package com.yu.listener;
import javax.servlet.ServletContextAttributeEvent;
import javax.servlet.ServletContextAttributeListener;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class SessionListener implements HttpSessionListener, HttpSessionAttributeListener {
@Override
public void attributeAdded(HttpSessionBindingEvent se) {
System.out.println("HttpSession添加属性:"+se.getSession().getAttribute("bookName"));
}
@Override
public void attributeRemoved(HttpSessionBindingEvent se) {
System.out.println("HttpSession移除属性:"+se.getSession().getAttribute("bookName"));
}
@Override
public void attributeReplaced(HttpSessionBindingEvent se) {
System.out.println("HttpSession修改属性:"+se.getSession().getAttribute("bookName"));
}
@Override
public void sessionCreated(HttpSessionEvent se) {
System.out.println("HttpSession,获取的时候才创建该对象:"+se.getSession().getId());
}
@Override
public void sessionDestroyed(HttpSessionEvent se) {
System.out.println("HttpSession,调用销毁方法:"+se.getSession().getId());
}
}
package com.yu.listener;
import javax.servlet.ServletRequestAttributeEvent;
import javax.servlet.ServletRequestAttributeListener;
import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;
@WebListener
public class RequestListener implements ServletRequestListener, ServletRequestAttributeListener {
@Override
public void attributeAdded(ServletRequestAttributeEvent srae) {
System.out.println("HttpServletRequest添加属性:"+srae.getServletRequest().getAttribute("bookName"));
}
@Override
public void attributeRemoved(ServletRequestAttributeEvent srae) {
System.out.println("HttpServletRequest移除属性:"+srae.getServletRequest().getAttribute("bookName"));
}
@Override
public void attributeReplaced(ServletRequestAttributeEvent srae) {
System.out.println("HttpServletRequest修改属性:"+srae.getServletRequest().getAttribute("bookName"));
}
@Override
public void requestDestroyed(ServletRequestEvent sre) {
System.out.println("一次请求完成,立即销毁:"+sre.getServletRequest());
}
@Override
public void requestInitialized(ServletRequestEvent sre) {
System.out.println("一次请求开始,重新创建新的对象:"+sre.getServletRequest());
}
}
访问多次demo01.jsp查看属性的操作行为
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<%
request.setAttribute("bookName","request-红楼梦"+Math.random());
application.setAttribute("bookName","servletcontext-水浒传"+Math.random());
session.setAttribute("bookName","session-西游记"+Math.random());
%>
</body>
</html>
session销毁行为
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<base href="${pageContext.request.contextPath}/">
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<%
session.invalidate();
%>
</body>
</html>
启动会调用ServletContext的销毁以及测试removeAttribute的方法