typora-copy-images-to: img
filter&listener&邮箱
学习目标
- 能够说出过滤器的作用
- 能够编写过滤器
- 能够说出过滤器生命周期相关方法
- 能够说出什么是过滤器链
- 能够编写过滤器解决全局乱码案例
- 能够编写ServletContextListener
- 能够搭建邮箱服务器
- 能够通过Java代码发送邮件
第一章-Filter
知识点-Filter概述
1.目标
- 掌握什么是Filter和Filter作用
2.路径
- 什么是filter
- 过滤器的作用
3.讲解
3.1什么是filter
Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能.
过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中**最为实用**的技术之一.
3.2过滤器的作用
对目标资源(Servlet,jsp)进行过滤.
应用场景:登录权限检查,解决网站乱码,过滤敏感字符 ...
4.小结
Filter是运行在服务器端的Java程序, 优先于请求资源(jsp,servlet,html…)之前执行
FIlter应用场景
- 登录权限校验
- 处理网站乱码
- 过滤非法字符
知识点-Filter入门(重点)
1.目标
- 掌握配置文件方式和注解方式配置Filter
2.步骤
2.1配置文件方式
- 创建一个类实现Filter接口
- 在web.xml配置FIlter
2.2注解方式
- 创建一个类实现Filter接口
- 在这个类上面添加@WebFilter(“拦截的路径”)
建议:可以直接new Filte
3.代码
3.1 通过xml配置方式
- 创建一个类实现Filter接口
/**
* - 创建一个类实现Filter接口
* - 在web.xml对过滤器进行配置
*/
public class FilterDemo01 implements Filter {
@Override
//过滤的方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo01收到了请求...");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
- 在web.xml对过滤器进行配置
<!--注册Filter-->
<filter>
<filter-name>FilterDemo01</filter-name>
<filter-class>com.itheima.web.filter.FilterDemo01</filter-class>
</filter>
<!--配置Filter过滤路径-->
<filter-mapping>
<filter-name>FilterDemo01</filter-name>
<url-pattern>/demo01</url-pattern>
</filter-mapping>
3.2通过注解方式
- 创建一个类实现Filter接口
- 直接在这个类上面添加注解进行配置
@WebFilter("/demo02")
public class FilterDemo02 implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("FilterDemo02... 收到了请求");
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
}
4.小结
4.1入门步骤
xml方式
- 创建一个类实现Filter接口
在web.xml配置Filter
<!--配置filter-->
<filter>
<!--filter-name:filter名字 随便取的(一般用类名, 不要重复)-->
<filter-name>FilterDemo01</filter-name>
<!--filter-class:filier类的全限定名-->
<filter-class>com.itheima.web.filter.FilterDemo01</filter-class>
</filter>
<!--配置Filter拦截映射的路径-->
<filter-mapping>
<!--filter-name:必须和filter里面的filter-name一致-->
<filter-name>FilterDemo01</filter-name>
<!--url-pattern:匹配的路径-->
<url-pattern>/demo01</url-pattern>
</filter-mapping>
注解方式
- 创建一个类实现Filter接口
- 在这个类上面添加@WebFilter(“拦截的路径”)
4.2request和response
知识点-Filter的生命周期
1.目标
- 掌握Filter的生命周期
2.路径
- Filter生命周期介绍
- 生命周期方法
- Filter生命周期描述
- FilterConfig【了解】
3.讲解
3.1Filter生命周期介绍
过滤器从创建到销毁的过程
3.2生命周期方法
init(FilterConfig):初始化
doFilter(ServletReqeust req,ServletResponse resp,FilterChain chain):执行过滤的方法
destroy():销毁
3.3Filter生命周期描述
- 服务器启动的时候, 会调用init()方法进行初始化【调用一次】
- 任何一次请求都会调用doFilter()方法进行过滤【路径相匹配】
- 服务器正常关闭或者项目从服务器移除, 调用destory()方法进行销毁【调用一次】
注意: 默认情况下,Servlet是来了第一次请求的时候 调用init()方法进行初始化.我们可以在Servlet里面设置启动项.
3.4 FilterConfig【了解】
获得过滤器的初始化参数
- 配置初始化参数
<filter>
<filter-name>myFilter01</filter-name>
<filter-class>com.itheima.filter.MyFilter01</filter-class>
<!--添加初始化参数-->
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>myFilter01</filter-name>
<!--
servlet的映射路径的目的是: 指定由哪个servlet去处理对应的请求
过滤器的过滤路径的目的是: 指定过滤哪个或者哪些请求
-->
<url-pattern>/*</url-pattern>
</filter-mapping>
- 在Filter的init()方法里面获得了
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//在filter对象初始化的时候,使用filterConfig对象获取web.xml配置文件中的初始化参数
String encoding = filterConfig.getInitParameter("encoding");
System.out.println("MyFilter01创建了..."+encoding);
}
4.小结
知识点-映射路径
1.目标
- 掌握映射路径的配置
2.路径
- 完全路径匹配
- 目录匹配
- 扩展名匹配
- 缺省匹配
3.讲解
假设有一个管理员权限的过滤器,它应该对用户发出的管理员功能的请求进行条件的过滤。但是当用户发出登录、注册等请求的时候,不应该进行过滤。所以我们过滤器,应该有选择的过滤器请求。这就需要学习配置过滤器不同的映射路径,从而让过滤器过滤希望过滤器的请求。
3.1完全路径匹配
以”/“开始
/demo01 ---> 过滤器只能拦截路径/demo01;
3.2目录匹配
以”/“开始 以 *结束 .
/* --->当前项目下的所有的路径都可以拦截; /aa/* ---> 可以拦截 /aa/bb, /aa/bb/cc
3.3扩展名匹配
以”“开始 例如: .jsp *.do
*.do--->可以拦截路径的后缀是 do的 ; *.jsp--->拦截所有JSP
3.4缺省匹配
/ 除了jsp以外的资源都匹配
当前Filter里面不支持, Servlet里面可行的. 后面在Servlet里面遇到
4.小结
- 完全路径匹配
/demo01
- 目录匹配
/* 匹配所有的资源 /aa/* 匹配以/aa开头的资源
- 扩展名匹配
*.jsp 匹配上了所有的jsp *.html 匹配上了所有的html
- 缺省匹配 / 匹配除了jsp以为的所有的资源
/ 除了jsp 其它的都匹配
/* 匹配所有
知识点-拦截方式
1.目标
- 掌握Filter的拦截方式
2.分析
有了上面学习的映射路径,我们可以控制过滤器过滤指定的内容,但是我们在访问资源的时候,并不是每次都是之间访问,有时是以转发的方式访问的,这就需要我们要让过滤器可以区分不同的访问资源的方式,有不同的拦截方式。 是通过 DispatcherType 来指定的.
3.讲解
DispatcherType.REQUEST,默认值,过滤从浏览器发送过来的请求和重定向 不过滤转发
DispatcherType.FORWARD,只过滤转发过来的请求
3.小结
通过dispatcherTypes配置拦截方式
DispatcherType.FORWARD: 【只】过滤转发
DispatcherType.REQUEST: 除了转发以为其它的都过滤(1.浏览器的直接请求 2.重定向)【默认值】
拦截方式的这个值,我们可以配置多个
@WebFilter(value = {"/demo06"},dispatcherTypes={DispatcherType.FORWARD,DispatcherType.REQUEST})
一般情况下, 转发我们不会过滤的. 转发属于服务器内部的行为. 直接使用默认值的情况偏多
知识点-过滤器链
1.目标
- 掌握过滤器链
2.分析
过滤器链作用:一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源
3.讲解
3.小结
过滤器链执行顺序
- 配置文件: 谁先配置
filter-mapping
谁先执行 - 注解方式: 按照Filter的首字母顺序 eg: AFilter BFilter A在B的前面, AFilter先执行
- 配置文件: 谁先配置
案例一:统一全网站中文乱码的处理
1,需求分析
在整个网站中,可能会有get请求或post请求向服务器提交参数.参数中往往有中文信息.在后台每个Servlet中都需要去处理乱码.
我们想做的是:请求到达Servlet中.就可以直接调用getParameter方法获得请求参数,请求参数已经没有乱码了.
2,思路分析
3,代码实现
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 包名:${PACKAGE_NAME}
*
* @author Leevi
* 日期2020-07-17 10:41
*/
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//统一设置请求的编码方式为UTF-8
req.setCharacterEncoding("UTF-8");
//统一设置响应的编码方式(如果设置了这种解决响应乱码的代码,那么就不能做下载)
resp.setContentType("text/html;charset=UTF-8");
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
4.小结
案例二:非法字符过滤
1,需求分析
当用户发出非法言论的时候,提示用户言论非法。
效果:
第一个版本
思路分析
代码实现
- IllegalFilter
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
/**
* 包名:${PACKAGE_NAME}
*
* @author Leevi
* 日期2020-07-17 11:01
*/
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//判断请求参数中是否包含非法字符
String content = req.getParameter("content");
if (content != null) {
if (content.contains("你大爷")) {
//表示请求参数中有非法字符,则拦截
resp.getWriter().write("评论中包含非法字符,请重新评论!!!");
return;
}
}
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
第二个版本
思路分析
代码实现
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
/**
* 包名:${PACKAGE_NAME}
*
* @author Leevi
* 日期2020-07-17 11:01
*/
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
private List<String> strList = new ArrayList<>();
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//从strList中遍历出每一个字符串,然后进行比较
//判断请求参数中是否包含非法字符
String content = req.getParameter("content");
if (content != null) {
for (String str : strList) {
if (content.contains(str)) {
//表示请求参数中有非法字符,则拦截
resp.getWriter().write("评论中包含非法字符,请重新评论!!!");
return;
}
}
}
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
//读取IllegalWords.txt里面的数据
//1. 将IllegalWords.txt转换成字节输入流
InputStream is = IllegalCharFilter.class.getClassLoader().getResourceAsStream("IllegalWords.txt");
//2. 将字节输入流,包装成BufferReader
try {
BufferedReader bfr = new BufferedReader(new InputStreamReader(is,"UTF-8"));
String str = null;
while (( str = bfr.readLine()) != null) {
//每读到一个字符串,就将它存储到strList中
strList.add(str);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第三个版本
思路分析
动态代理的作用是:
- 在不修改类的源码的基础上,增强类的方法
- 可以减少重复代码,在执行方法之前添加前置操作、执行方法之后添加后置操作(Spring的AOP思想)
- 我们可以在不写接口的实现类的情况下,创建接口的对象(mybatis框架)
代理模式的分类:
- 静态代理
- 动态代理
静态代理和动态代理的区别:
- 静态代理中必须存在代理类
- 静态代理的代理关系是在编译的时候确定的,而动态代理的代理关系是在程序运行的时候才确定的
代码实现
package com.itheima.filter;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* 包名:${PACKAGE_NAME}
*
* @author Leevi
* 日期2020-07-17 11:01
*/
@WebFilter("/*")
public class IllegalCharFilter implements Filter {
private List<String> strList = new ArrayList<>();
@Override
public void destroy() {
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//放行之前,使用动态代理技术,增强req对象的方法
//将req强转成HttpServletRequest
HttpServletRequest request = (HttpServletRequest) req;
//类加载器
ClassLoader classLoader = req.getClass().getClassLoader();
//被代理的接口: HttpServletRequest
HttpServletRequest requestProxy = (HttpServletRequest) Proxy.newProxyInstance(classLoader, new Class[]{HttpServletRequest.class}, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//增强getParameter()方法,其它方法还是调用被代理者原本的方法
if (method.getName().equals("getParameter")) {
//要增强getParameter()方法,其实就是将请求参数值中的非法字符替换成*
//1. 获取请求参数值
String value = (String) method.invoke(request, args);
//2. 判断请求参数值中是否包含非法字符
for (String str : strList) {
if (value.contains(str)) {
//2.1 包含非法字符,就要将value中的非法字符替换成*
String start = "";
for (int i=0;i<str.length();i++){
start += "*";
}
value = value.replace(str,start);
}
}
return value;
}
//不用增强的方法,要调用被代理者原本的方法
return method.invoke(request,args);
}
});
//最后肯定要放行
chain.doFilter(requestProxy, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
//读取IllegalWords.txt里面的数据
//1. 将IllegalWords.txt转换成字节输入流
InputStream is = IllegalCharFilter.class.getClassLoader().getResourceAsStream("IllegalWords.txt");
//2. 将字节输入流,包装成BufferReader
try {
BufferedReader bfr = new BufferedReader(new InputStreamReader(is,"UTF-8"));
String str = null;
while (( str = bfr.readLine()) != null) {
//每读到一个字符串,就将它存储到strList中
strList.add(str);
}
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
第二章-监听器Listener
知识点-Listener概述
1.目标
- 掌握什么是Listener
2.路径
- 什么是Listener
- 监听器的应用
- 监听器的术语
3.讲解
3.1什么是Listener
监听器就是一个Java类,用来监听其他的JavaBean对象的变化
在javaweb中监听器就是监听**三个域对象**的状态的。request,session,servletContext(application)
3.2监听器的应用
主要在Swing编程
在Android/ios大量应用
JS里面的事件
3.3监听器的术语
eg: 一个狗仔拍明星出轨
事件源 :被监听的对象.(目标对象) 明星
监听器对象:监听的对象. 狗仔
事件:事件源行为的称呼. 出轨
注册(绑定):将"监听器"对象注册给"事件源". 狗仔需要和明星绑定(跟踪, 蹲点...)
事件对象:在"监听器对象"中获得"事件源" 狗仔的镜头里面获得明星出轨证据
4.小结
- 什么是监听器? 就是一个类(对象), 用来监听其它JavaBean状态的
- 我们学的是web里面的监听器, web里面的监听器是监听三个域对象的
监听器应用
- 在Android/ios大量应用
- JS里面的事件
- 初始化工作(监听ServletContext)
知识点-javaweb中的监听器
1.目标
- 知道JavaWeb中的监听器类型
2.路径
- 说明
- JavaWeb中的监听器类型
- JavaWeb的监听器使用步骤
3.讲解
3.1 javaweb的监听器
javaweb的监听器:监听ServletContext,HttpSession,ServletRequest三个域对象状态
事件源和监听器绑定的过程:通过配置web.xml完成
3.2 JavaWeb中的监听器类型
- 三类8个
只讲解 监听ServletContext的创建和销毁.
3.3JavaWeb的监听器使用步骤
- 创建一个类实现监听器接口
- 在web.xml进行配置(绑定)
4.小结
- 学习监听器就学一个 监听ServletContext的创建和销毁
知识点-监听ServletContext的创建和销毁的监听器
1.目标
- 掌握ServletContextListener
2.路径
- ServletContextListener
3.讲解
说明: 监听ServletContext对象的创建和销毁
方法
问题
ServletContext对象何时创建和销毁:应用在,它就在
创建:服务器启动时候(前提是这个项目在这个服务器里面). 服务器为每个WEB应用创建一个单独的ServletContext.
销毁:服务器关闭的时候,或者项目从服务器中移除.企业中应用
初始化工作.
加载配置文件:Spring框架,ContextLoaderListener
步骤:
- 创建一个类实现ServletContextListener
- 在web.xml配置
代码:
- JAVA代码 ```java package com.itheima.listener;
import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener;
/**
- 包名:com.itheima.listener *
- @author Leevi
- 日期2020-07-17 14:38
- 一、写一个类实现ServletContextListener接口,并重写方法
- 方法1: contextInitialized()会在ServletContext对象创建的时候执行,也就是在服务器启动的时候
- 方法2: contextDestroyed()会在ServletContext对象销毁的时候执行,也就是在服务器关闭的时候 *
二、在web.xml中配置监听器 */ public class MyContextListener implements ServletContextListener{ @Override public void contextInitialized(ServletContextEvent sce) {
System.out.println("监听到了服务器的启动....创建spring的核心容器");
}
@Override public void contextDestroyed(ServletContextEvent sce) {
System.out.println("监听到了服务器的关闭....销毁spring的核心容器");
} } ```
- 配置(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_3_1.xsd"
version="3.1">
<listener>
<listener-class>com.itheima.listener.MyContextListener</listener-class>
</listener>
</web-app>
4.小结
步骤
- 创建一个类实现ServletContextListener接口
- 在web.xml配置
- 应用: Spring框架里面, 服务器启动时候, 就加载Spring框架 初始化
第三章-邮箱(了解)
1.邮件流程
2.邮件服务器
2.1服务器
- 硬件+软件(eg: mysql, tomcat…)
2.2邮件服务器
- 租(企业邮箱)
- 自己搭建
3.邮件软件安装
- 服务端
- 客户端
4.邮件的发送
- 直接通过Foxmail发送
通过java代码发送
- 拷贝jar
- 拷贝工具类
- 使用工具类发送
MailUtil
package com.itheima.util;
import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
import java.util.Properties;
/**
* 发送邮件工具类
*/
public class MailUtil {
private MailUtil(){}
/**
* 发送邮件
* 参数一:发送邮件给谁
* 参数二:发送邮件的内容
*/
public static void sendMail(String toEmail, String emailMsg) throws Exception {
//1_创建Java程序与邮件服务器的连接对象
Properties props = new Properties();
//设置要连接的邮件服务器的主机地址
props.put("mail.smtp.host", "localhost");
//设置是否进行校验
props.put("mail.smtp.auth", "true");
Authenticator auth = new Authenticator() {
@Override
public PasswordAuthentication getPasswordAuthentication() {
//发邮件者的账号和密码
return new PasswordAuthentication("service", "123456");
}
};
Session session = Session.getInstance(props, auth);
//2_创建一封邮件
Message message = new MimeMessage(session);
//设置发送者的地址
message.setFrom(new InternetAddress("service@itheima98.com"));
//设置接收者的地址
message.setRecipient(RecipientType.TO, new InternetAddress(toEmail));
//设置邮件的主题
message.setSubject("生日祝福");
//设置邮件的内容
message.setContent(emailMsg, "text/html;charset=UTF-8");
//3_发送邮件
Transport.send(message);
}
}
第四章-扩展
1.密码加密
可逆: 加密之后还可以解密
- 对称加密:加密和解密使用的密钥是相同的,常见的加密算法:AES、3AES
- 非对称加密:加密和解密的密钥不同,常见的非对称加密算法:RSA算法
- 数字证书:让客户端能够认证服务器
- 不可逆: 加密之后 不可以解密
2.MD5加密算法
- 不可逆
- 步骤 直接拷贝工具类进行加密
3.保证MD5加密算法安全
- 前端控制(避免密码过于简单),加密多次
- 加盐
4.怎么登陆
- 登陆的时候 按照 注册那种方式加密一下, 再去查询数据库 就OK了
5. 退出登录
5.1 思路
- 修改超链接 请求LogoutServlet
- 在LogoutServlet里面, 移除session里面存的user, 重定向到首页
5.2实现
- 超链接
<a href="logout">退出</a>
- LogoutServlet
package com.itheima.web;
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;
/**
* @Description:
* @Author: yp
*/
@WebServlet("/logout")
public class LogoutServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//1.销毁session
request.getSession().invalidate();
//2.重定向到登录页面
response.sendRedirect(request.getContextPath()+"/login.jsp");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}