1、Filter
1.1什么是filter
Filter:一个实现了特殊接口(Filter)的Java类. 实现对请求资源(jsp,servlet,html,)的过滤的功能.
过滤器是一个运行在服务器的程序, 优先于请求资源(Servlet或者jsp,html)之前执行. 过滤器是javaweb技术中最为实用的技术之一.
1.2 过滤器的作用
对目标资源(Servlet,jsp)进行过滤.
应用场景:登录权限检查,解决网站乱码,过滤敏感字符 …
1.3 Filter入门
2.1配置文件方式
- 创建一个类实现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>
<filter-name>FilterDemo01</filter-name>
<filter-class>com.it.web.filter.FilterDemo01</filter-class>
</filter>
<!--配置Filter过滤路径-->
<filter-mapping>
<filter-name>FilterDemo01</filter-name>
<url-pattern>/demo01</url-pattern>
</filter-mapping>
2.2注解方式
-
创建一个类实现Filter接口
-
在这个类上面添加@WebFilter(“拦截的路径”)
/**
* Filter的编写步骤:
* 1. 写一个类实现Filter接口,并且重写方法
* 2. 配置Filter的拦截路径:
* 1. 注解方式配置
* 2. 配置文件方式配置
*
* Filter的生命周期:
* 1. Filter什么时候创建: 服务器启动的时候
* 2. Filter什么时候销毁: 服务器关闭的时候
*
* Filter的生命周期方法:
* 1. init(): 会在Filter对象被创建出来的时候执行, 这里面通常是从配置文件中读取一些初始化的数据(耗时操作)
* 2. destroy(): 会在Filter对象销毁的时候执行, 可以进行一些序列化保存备份工作
* 3. doFilter(): 会在Filter每次过滤请求的时候执行, 真正执行过滤
*
* Filter的三种拦截路径的介绍:
* 1. 精确匹配: "/demo01"
* 2. 模糊匹配: "/*"
* 3. 扩展名匹配: "*.jsp"
*/
@WebFilter("/demo01")
public class FilterDemo01 implements Filter {
@Override
public void destroy() {
System.out.println("FilterDemo01销毁了。。。");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
System.out.println("FilterDemo01拦截到了请求...");
//放行:让这次请求通过,去到它想去的地方
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
System.out.println("FilterDemo01被创建出来了。。。");
}
}
@WebFilter
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface WebFilter {
//拦截方式
DispatcherType[] dispatcherTypes() default {DispatcherType.REQUEST};
}
Filter的生命周期
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);
}
filterConfig 接口
public String getInitParameter(String name)
//返回指定初始化参数的值,如果初始化参数不存在,则返回null
映射路径
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里面遇到
拦截方式
有了映射路径,我们可以控制过滤器过滤指定的内容,但是我们在访问资源的时候,并不是每次都是直接访问,有时是以转发的方式访问的,这就需要我们要让过滤器可以区分不同的访问资源的方式,有不同的拦截方式。 是通过 DispatcherType 来指定的.
-
DispatcherType.REQUEST,默认值,过滤从浏览器发送过来的请求和重定向 不过滤转发
-
DispatcherType.FORWARD,只过滤转发过来的请求
//两种类型都拦截
@WebFilter(value = {"/demo06"},dispatcherTypes={DispatcherType.FORWARD,
DispatcherType.REQUEST})
一般情况下, 转发我们不会过滤的. 转发属于服务器内部的行为. 直接使用默认值的情况偏多
@WebServlet("/demo01")
public class ServletDemo01 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("ServletDemo01收到了请求....");
//请求转发跳转到ServletDemo02
request.getRequestDispatcher("demo02").forward(request, response);
//重定向
//response.sendRedirect("demo02");
}
}
过滤器链(filterChain)
过滤器链作用:一个请求可能被多个过滤器所过滤,只有当所有过滤器都放行,请求才能到达目标资源,如果有某一个过滤器没有放行,那么请求则无法到达后续过滤器以及目标资源
过滤器链执行顺序
- 配置文件: 谁先配置
filter-mapping
谁先执行 - 注解方式: 按照Filter的首字母顺序 eg: AFilter BFilter A在B的前面, AFilter先执行
- 如果既有注解方式配置的过滤器,又有配置文件方式配置的过滤器,那么配置文件方式配置的过滤器先进行过滤
案例一: 全网站请求的中文乱码的处理
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@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");
chain.doFilter(req, resp);
}
@Override
public void init(FilterConfig config) throws ServletException {
}
}
案例二: 非法字符过滤
动态代理实现:
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;
@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();
}
}
}
}
2、监听器Listener
2.1什么是Listener
监听器就是一个Java类,用来监听其他的JavaBean对象的变化
在javaweb中监听器就是监听三个域对象的状态的。request,session,servletContext(application)
2.2监听器的应用
主要在Swing编程
在Android/ios大量应用
JS里面的事件
2.3 javaweb中的监听器
1 javaweb的监听器
javaweb的监听器:监听ServletContext,HttpSession,ServletRequest三个域对象状态
事件源和监听器绑定的过程:通过配置web.xml完成
2 JavaWeb中的监听器类型
- 三类8个
监听ServletContext的创建和销毁.
ServletContext是什么时候创建: 服务器启动的时候
ServletContext是什么时候销毁: 服务器关闭的时候
所以监听ServletContext创建和销毁,就能监听服务器的启动和关闭,就可以在服务器启动和关闭的时候执行一些代码(比如在服务器启动的时候读取Spring的配置文件,创建Spring的核心容器)
3 JavaWeb的监听器使用步骤
- 创建一个类实现监听器接口
- 在web.xml进行配置(绑定)
实现:
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
/**
* 一、写一个类实现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.it.listener.MyContextListener</listener-class>
</listener>
</web-app>
3、邮件
邮件流程
利用java实现发送邮件
1 什么是JavaMail
在我们开发中,我们很多时候都需要涉及发送邮件的操作,比如:用户注册成功邮件激活账号,会员生日邮件提醒等等。这样的邮件操作就需要学习JavaMail来完成我们的java发送邮件的操作。
JavaMail是Sun公司提供的处理电子邮件的一套编程接口。使用JavaMail我们可以使用java代码完成邮件的接收和发送。
2 JavaMail应用场景
2.1 会员生日时发送邮件
例如qq每当到qq用户的生日的时候,qq会发送一封生日祝福邮件给qq用户。
2.2 会员注册成功,发送邮件,会员激活后,会员才能登陆。
我们现在上网很多时候需要注册一个用户,往往在我们注册后,网站会给我们发送一封激活邮件,需要我们去激活才能进行登录
JavaMail 下载地址:https://github.com/javaee/javamail/releases
包含了 SMTP, IMAP, 和 POP3 协议的实现:
3 邮件使用的协议
网络中发送邮件应该有与http协议一样概念的邮件协议。
3.1 发邮件协议
发邮件协议使用的是SMTP,非 SSL 连接的端口协议的端口号是25。
SMTP的全称是“Simple Mail Transfer Protocol”,即简单邮件传输协议。它是一组用于从源地址到目的地址传输邮件的规范,通过它来控制邮件的中转方式。SMTP 协议属于 TCP/IP 协议簇,它帮助每台计算机在发送或中转信件时找到下一个目的地。
3.2 收邮件协议
收邮件协议有2中,一种是POP3,还有一种是IMAP。协议的端口号为110。
POP3是Post Office Protocol 3的简称,即邮局协议的第3个版本,它规定怎样将个人计算机连接到Internet的邮件服务器和下载电子邮件的电子协议。它是因特网电子邮件的第一个离线协议标准,POP3允许用户从服务器上把邮件存储到本地主机(即自己的计算机)上,同时删除保存在邮件服务器上的邮件。
IMAP全称是Internet Mail Access Protocol,即交互式邮件存取协议,它是跟POP3类似邮件访问标准协议之一。不同的是,开启了IMAP后,您在电子邮件客户端收取的邮件仍然保留在服务器上,同时在客户端上的操作都会反馈到服务器上,如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。
JavaMail常用的API
Session类
Session类表示邮件会话。它集合了邮件API使用的属性和默认值。一个默认会话可以被桌面上的多个应用程序共享。也可以创建非共享会话。
Session常用方法
public static Session getInstance(Properties props,
Authenticator authenticator)
//创建java到邮件服务器间的会话对象Session
//Properties 以key 和value的形式保存邮件服务器的设置 JavaMail规范附录A中列出的属性值
//Authenticator
Authenticator
public abstract class Authenticator
Authenticator常用方法
protected PasswordAuthentication getPasswordAuthentication()
MimeMessage类
public class MimeMessage extends Message implements MimePart
这个类表示MIME样式的电子邮件消息。它实现了Message抽象类和MimePart接口。
MimeMessage常用方法
public void setFrom(Address address)
//设置发件人地址
public void setRecipients(Message.RecipientType type, Address[] addresses)
/*
参数一:设置邮件的接收方式。
RecipientType.TO:为正常接收邮件
RecipientType.CC:表示抄送
RecipientType.BCC:表示秘密抄送
参数二:设置邮件的收件人。
*/
public void setSubject(String subject)
public void setSubject(String subject, String charset)
//设置邮件的主题
public void setContent(Object o, String type)
//参数一:设置邮件的内容
//参数二:设置解析邮件的方式。如"text/html;charset=UTF-8",以html,并且以utf-8的编码解析
Transport
public abstract class Transport extends Service
对消息传输进行建模的抽象类
Transport常用方法
public static void send(Message msg)
public static void send(Message msg, Address[] addresses)
//发送一个信息。使用适合于每个地址的消息传输,消息将被发送到消息中指定的所有接收地址
//(从message方法getAllRecipients返回)。send方法在发送消息之前调用saveChanges方法
依赖:
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
<version>1.4</version>
</dependency>
邮件创建步骤:
- 创建一个邮件对象(MimeMessage);
- 设置发件人,收件人,可选增加多个收件人,抄送人,密送人;
- 设置邮件的主题(标题);
- 设置邮件的正文(内容);
- 设置显示的发送时间;
- 保存到本地。
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;
/**
* 发送邮件工具类
*/
public class MailUtil {
private MailUtil(){}
/**
* 发送邮件
* 参数一:发送邮件给谁
* 参数二:发送邮件的内容
*/
public static void sendMail(String toEmail, String emailMsg) throws Exception {
//1_创建Java程序与163邮件服务器的连接对象
Properties props = new Properties();
// 使用的协议(JavaMail规范要求)
props.setProperty("mail.transport.protocol", "smtp");
props.put("mail.smtp.host", "localhost");
props.put("mail.smtp.auth", "true");
Authenticator auth = new Authenticator() {
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@it.com"));
//设置收件人地址
message.setRecipients(Message.RecipientType.TO,
new InternetAddress[]{new InternetAddress(toEmail)})
//设置邮件的主题
message.setSubject("用户激活");
//设置邮件的内容
message.setContent(emailMsg, "text/html;charset=UTF-8");
//3_发送邮件
Transport.send(message);
}
/**
* 测试类
*/
public static void main(String[] args) throws Exception{
String toEmail = "zs@it.com";
String emailMsg = "测试一下";
sendMail(toEmail,emailMsg);
System.out.println("发送成功。。。");
}
}
4、定时任务
4.1 什么是定时任务
定时任务用于安排以后在后台线程中执行的任务。可安排任务执行一次,或者定期重复执行。
4.2 定时任务的应用场景
4.2.1 每隔1小时检查用户在线人数
每隔1小时系统自动统计在线的用户人数。首先需要编写统计用户在线人数功能,然后我们需要1小时执行一次。需要java中的定时任务。
4.2.2 每隔5分钟更新新闻
新闻都是实时的,而且新闻都是每隔一段时间更新最新的新闻。所以我们需要定时任务完成。
java.util.Timer
Tabnine
Codota:代码智能提示
codota插件_5 个 IDEA 必备插件,让效率成为习惯
对应的在线网站:https://www.codota.com/code
idea中:TabNine::config
4.3 Timer
Timer构造方法
public Timer() //创建一个新的计时器。关联的线程不作为守护进程运行。
public Timer(boolean isDaemon)
Timer常用的API
public void schedule(TimerTask task, long delay)
public void schedule(TimerTask task, Date time)
public void schedule(TimerTask task, Date firstTime, long period)
public void schedule(TimerTask task, long delay, long period)
TimerTask
public abstract class TimerTask implements Runnable
4.4 使用步骤
1.创建定时器Timer对象
2.调用Timer对象的schedule方法执行定时任务
3.创建定时器任务对象TimerTask
4.实现TimerTask的run方法
public static void main(String[] args) {
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
System.out.println("该睡觉了");
}
},new Date(),1000*3);
}